AtCoder の過去問埋めを超楽にするサービスを作った話(ダイジェスト)

はじめに

こんにちは、CCS OB の @kakira9618 です。この記事は CCS Advent Calendar 2022 の20日目の記事です。

adventar.org

19日目(前日)はあきひよさんの 去年の自分からのバトンを受け取って半ば投げ捨てた人の記事 です。

表題の通り、Webサービスを作ったので記事を書きます……が時間があまりない(記事執筆開始: 2022/12/20 22:00)ので、ダイジェスト版(概説・動機・システム構成説明・実装で辛かったところ・評価・感想)でお送りします。色々考えながら作ったので、記事にできそうなことは他にもあるのですが、時間の制約上、個々の観点についてはまた今度……

前提知識

日本の競技プログラミングの最大手サイトです。プログラムを提出すると、予め用意されている複数のテストが実行されて自動採点されます。

何を作ったの?

AtCoder Companions というサイトを作りました (2022/12/11 リリース)。

告知ツイート

詳細はツイートの動画やサイトのAboutを確認していただくとして、ざっと概要の概要を説明すると、「同じ間違え方をした後に正解している他の提出を見つけて、間違いと正解の提出のコードの差分を表示する」サービスです。ざっと動画見てイメージしてもらうのが早そうです。

期間など

開発着手からリリースまで約2ヶ月でしたが、アイデア自体は1年ほど前からあったと思います。

動機(対外向け)

みんな AtCoder やってますか?僕は最近はできてないですね((

現役の人も、全くやってない人も、昔やってた人もいると思います。

AtCoder の腕前をあげる上で欠かせないのが、過去問演習です。

とりあえず、問題を解いて・・・サンプルケースもあってる。よし、提出!とするまでは良いのですが、かなりコレになりがちです(個人の感想です)

よくあるやつ

解説はAtCoderで閲覧できるので、方針が合っているかどうかというのは大体想像がつきます。サンプルテストケースが通ってない場合も、その入力をデバッグすることができるので問題ないと思います。問題は、方針もサンプルテストケースの出力も合っているはずなのに、一部テストケースだけなぜか通らない、というパターンです。

これがサッと解決すればよいのですが、大抵の場合はそうはいかず、解決するのに無限に時間がかかったり、人に聞いたり、あるいは諦める必要があったりしました(個人の感想です)。無限に考えてようやくAC(正解)しても、直した内容は単なるポカミスとかだったりして、これだけのことに自分はn時間も消費してしまったのか… となることがあると思います。 そしてそのような体験が続くと、AtCoderに飽きてしまいやらなくなる… みたいなことも十分有り得ると思います。

これをなんとかできないか、と考えてできたサービスが AtCoder Companions です。

AtCoder Companions に、そのような提出のURLを投げると、

  1. 同じ間違え方をしている提出を検索し
  2. その中から、最終的にAC(正解)にたどり着いている提出を抽出し
  3. 1.と2.のコードの差分を表示

してくれます。

AtCoder Companions のメイン画面

"同じ間違え方をしている提出" というのは、画像の Result Vector、つまり各テストケースにおける結果の配列が同じであるような提出を指しています。

同じ間違え方をしている提出がどのように正解にたどり着いているかがわかれば、必然的に自分の提出で修正しなければならない箇所がわかるわけですね。

裏・動機

業務(Web系) とかではシステムの大部分が出来上がっててその拡張を作るなどの機会が多いのですが、一からサービスを作ることは少ない(部署による)ので、そのような経験に欠けがちでした。

また、コストの許容ラインは個人サービスのほうがより低く設定されていることが多く、その辺一度作ってどんな感じなのか体験したいという裏の動機がありました。

真・動機

いえ、もっと突っ込むと、

  • 焦燥感:AtCoder Replay (前作)などを作ってから時間(3年)が経っており、そろそろなんか作らないとやばい。特にフロントエンドとか。
  • 好奇心:今持っている知識を使ってある程度まともなWebサービスを作ってみたらどの様になるのか、腕試ししてみたい。

という気持ちがありました。これが真の動機(?)です。

実装

さて、いきなりシステムの話になって申し訳ないです…🙇‍♂️

AtCoder Companions のインフラ全体像はこんな感じになりました。AWS様様です。

AtCoder Companions のインフラ構成図

全体的にサーバーレスな構成となっています。また、環境ごと独立してインフラを管理できるように、AWS SDKによってインフラはコード化されています。

基本的に、Static File のリクエストと API Call のリクエストで通る経路が違い、Static File は CloudFront を通って配信され、API request は APIGateway 経由で lambda が叩かれます。lambdaはDynamo DB にアクセスしたりします(Token用)

AWSとは別でクロール用のサーバーが動いており(これは今は手元PC)、AtCoder にクロールをして、その情報を Resource Bucket に送ります。この情報を CloudFront から署名付きで(理由は後述)配信することで、同じ間違え方をしている情報の取得が行えるようになっています。

また、フロントエンドは Vite + React + TypeScript + Tailwind + DaisyUI で、バックエンド(Lambda)は Node.js で、インフラ(AWS SDK)は TypeScript で書いてます。ほとんど JavaScript 系で書かれますね。

実装でやばかったところ

最終的には先程のような構成のサービスとなりましたが、当初はもっとシンプルに実装できる予定でした。 しかし、開発を進めていくとやらなければならないことがたくさん増えて増えて当初の予定よりだいぶ大きなプロジェクトになってしまいました。

最初はクローラーだけが後ろで動いている静的なサイト想定で作り始めたのですが……

  • CORSの関係で動的な仕組みを入れなきゃいけない、やばい
  • クローラーのアクセス数が多すぎて、やばい
  • クローラーは一歩間違えれば攻撃とみなされるのでポリシーを設定しなきゃ、やばい
  • DoS攻撃されるとやばいので制限入れなきゃ(お財布もだが、AtCoderを巻き込むので)、やばい
  • 制限入れるのであればチートができないようにしなきゃ、やばい
  • Google Analytics 便利だけど GDPR関連、やばい
  • 謎の課金、やばい
  • CI/CD周り・テストがない、やばい
  • ドキュメント書かなきゃ、やばい

などなど、やばいづくしで当初の想定の8倍1くらいの時間がかかりました😇

もうちょっと見積もりは丁寧にやりたいですね。とは言いつつ、やってみないと問題点が上がってこない事が多いので、悩みどころです。

大体の問題は解決したけど、まだいくつか解決していないところ(課金系の問題とかテストCI・CD周りとかはまだです)もありますので、今後の課題とします。

以下、詳細です。技術的な内容も含まれるので、興味無いかたは評判の項まで進めちゃってください。

CORSの関係で動的な仕組みを入れなきゃいけない、やばい

AtCoder Companions の特性上、AtCoderの個々の提出を一つ一つクロールする必要があります2

しかし、個々の提出ページはAPIとして他のサイトから利用されることを想定しておらず、AtCoder Companions 上の javascript からそのページの内容を取得し利用することはできないようになっています。 これでは、ソースコードの差分を表示するときに困ってしまいますので、自前でプロキシサーバーを立ててそこにリクエストを送る形としました。(自前サーバーであれば、CORS用のレスポンスヘッダーを挿入できるのでリクエストを間接的に行うことができるようになります)

しかし、これで静的な仕組みでつくれるだろう、という当初の目論見はあっけなく崩れ去ったのでした。

クローラーのアクセス数が多すぎて、やばい

ABC (AtCoder Beginner Contest)の場合、1つのコンテストあたり大体6万〜10万くらいの提出があります。まるで競技プログラミングサイトの制約みたいですね(?) その一つ一つの提出にアクセスするということは、つまり6万〜10万回以上のアクセスが発生するということです。

もちろんそれ用のプログラム(クローラー)を書いてスクレイピングするのですが、このオーダーの回数になってくると、しっかりとwaitをもたせてアクセスしないとDoS攻撃になってしまいます。 そして、しっかりと wait をもたせてクロールさせると、1コンテストあたり半日から1日くらいの時間がかかってしまうことになります。(EDPCなど提出数の多いコンテストの場合、更に5倍以上の時間がかかる) AtCoderには公開されているアルゴリズムのコンテストが1000弱くらいあるので、1周クロールが終わるのには年単位の時間がかかる計算になります。

公式側の対応として、提出一覧ページで各テストケースの情報が取れたり、APIを公開していただければアクセス回数は減ると思うのですが、普段は要らない情報だったりするので難しいところです。 AtCoder社長の chokudai さんとやり取りをしつつ、その辺りの仕組みの調整を行っている段階です。

クローラーは一歩間違えれば攻撃とみなされるのでポリシーを設定しなきゃ、やばい

前項で上げたとおり、かなりの回数のアクセスを行っているので、一歩間違えればDoS攻撃になってしまいます。 また、ソースコードなど著作性の認められるものの扱いは、慎重に行う必要があります3

この辺りで問題が起きるのを未然に防止するために、Crawling Policy という専用ページを作って、クロールする内容、アクセス頻度、利用目的を明記しました。 法的な文章は書くのはもちろん、読むのすら慣れていないので、このページを作るのには時間がかかりました。 また、全体としてUIに英語を使用しているので、英語で書いたほうが良いんじゃないか、という問題もありました4

この辺、良いまとめとかリソースがあればよいのですが、、、なかなかないですね。あったらぜひ教えて下さい。

DoS攻撃されるとやばいので制限入れなきゃ(お財布もだが、AtCoderを巻き込むので)、やばい

CORS対応したことで、自前のプロキシサーバーからAtCoderにアクセスする仕組みができたのは良いのですが、そうすると今度は「プロキシサーバーを踏み台にしてAtCoderにアクセスさせる」という攻撃ができるようになってしまいます。 踏み台にされた場合、AtCoderからみたアクセス元のIPはプロキシサーバーのアドレスです。これがAtCoderにBANされてしまうと、AtCoder Companions 全体に影響が出てしまいます(DoS攻撃の成立)

このリクエストはクローラーと違い、ユーザのブラウザから行うので、何らかの制限を入れる必要があります。 そこで、今回は新規ブラウザに対して Token を発行し、各APIを呼ぶには Token が必要になる、という仕組みを導入しました。 サーバー側では、その Token に紐づく API の使用回数をカウント・保存(Dynamo DB)していて、これによって、1日あたり○回までしか API を使えない、という制限を行えるようになりました。

具体的には「Find Companions API(同じ間違え方をした提出のメタ情報CSVのURLを取得するAPI)」と「Fetch Submission API(プロキシサーバーを通して提出のソースコードを取得するAPI)」の2つを制限の対象としています。

SQL系のDBとは違い、Dynamo DB はあまり触ってなかったので、慣れるのに時間を要しました。コストの算出方法なども独特で、auto scaling の設定などを考えて実装する必要がありました。

制限入れるのであればチートができないようにしなきゃ、やばい

もともと、Lambda が返せる情報量は5MBくらいなので、データはS3に予め上げておいて、そのURLを返すという方式にしています。

S3でのパスは、各テストケースに対する結果(Result Vector)のハッシュによって定まるようになっており、これによってある Result Vector に対応する提出の一覧を一発で取ってこれるようなデータ構造になっています。

前項の通り、Tokenによる制限を入れたのは良いのですが、そうすると今度はAPIを呼ぶことに価値ができてしまうので、その価値がなくなってしまうような脆弱性があってはいけません。 しかし、仕組み上 Find Companions API は、Result Vector がわかっていれば、手元でハッシュなどの計算を行うことによって直接URLの推測を行うことができてしまいます。 そのようにアクセスできてしまうと、簡単に制限の迂回ができてしまうことになります。

よってこの部分には Lambda によってファイルのURLに署名をつけて、そのURLを返すことにしています。 この署名が正しいかどうかをサーバーで検証してから、アクセスを許可することで、確実にAPIをコールした事がわかるし、静的ファイルに有効期限などの機能もつけられます。

現在はこの仕組みで動いていますが、ほとんどのリクエストは 5MB 以下なので Lambda で動的生成できるようにしたほうが無駄5が少なくなりそうで、現在実装検討中です。

Google Analytics 便利だけど GDPR関連、やばい

アクセス解析には Google Analytics を使っています。いろいろな情報が取れて基本的に便利なのですが、落とし穴もあります。それは、GDPR関連です。

詳細はググっていただくとして、日本国内だけではなく、GDPRの対象国へのサービスも行っていると認められる場合、GDPR対象国からのアクセスがあったときに、そのアクセスに紐づくCookieやIPなどの個人情報は GDPR が定める扱いをしなければなりません. (しないと訴訟されて多額の賠償金を払わなければならない、ということになっていて、実際にGoogle Fonts を使っていたら訴訟されて有罪になった例もあります)

個人か法人かには関係なく訴訟されたらまずいため、今回は 安全側に倒しGDPR 対象国からのアクセスをアクセス禁止にするという対応を取らせていただいています(対象国の皆様、申し訳ありません)

本来なら、きちんとポリシーを定義して、個人情報の取扱をしっかりとするのが望まれているはずですが、開発期間の関係(年内に完成させたかった)もあり、このような対応になってしまいました。今後の課題ですね。

謎の課金、やばい

AtCoder Companions は AWS の上に構築されているので、サーバー利用料はAWSに支払っています。が、無料枠というものがあり、今回の構成ではほとんど料金が発生しない… そのつもりでした。

しかし、蓋をあけてみると、やはり何かしら想定外の課金が起きていました6

この辺りの情報は、AWSコンソールの Billing Console の Free Tier から見れますので基本的にそれを見ながら調整すれば良いです。

想定外だったのは、

  • S3に対して細かいファイルをあまりにもたくさんアップロードしすぎたために、PUTにかかる料金が嵩んでいた
  • 謎のアラームが生えていて、無料分(10個まで)を超過していたこと

ですね。前者はすべてのレスポンスを S3 から返すのではなく、5MBを超えるものについてだけ動的にファイルを作って返すようにすれば解消しそうです(未実装)。

後者は、色々原因を調べていくと、どうやら Dynamo DB の auto scaling 用に設定されたアラームがカウントされてしまっているようでした。 今回はAWS CDKでインフラ環境を構築しており、環境(dev, live)ごとにTableをつくっていたので、auto scaling の設定なども環境が増えると倍増するようになっていました。 最終的には開発環境(dev)のauto scaling は要らないな、ということになり、そちら側の設定のみを削除することで対応しました。

CI/CD周り・テストがない、やばい

リリースまでには間に合いませんでした・・・😇 今後実装予定です。

とりあえず完成を急いだため、テスト・CI/CD周りは実装を後回しにしていました。しかし、その代償としてソースコードの Testablity が落ちてしまっています。 これからリファクタリングを行い、 Testablity を上げていかなければなりません。

デプロイ系のスクリプト化はちまちま作ってたので、テストなしのデプロイするだけのパイプラインを作ってもよいのですが、やはりテストがないとデグレとか色々心配になってしまうのでおとなしくテストしましょう。

ドキュメント書かなきゃ、やばい

まず、ソースコードに対するドキュメントがまだ配備されてないので、今後の課題です😇

また、一般利用者が読むドキュメントページ もあります。 このページは実装としては markdown で書いたものを Fetch して React Dom に変換して差し込むということをしているだけなのでシンプルなのですが、 ユーザの目線でドキュメントを書く、ということに慣れていないのでとても時間がかかりました。

内容面では、どのような内容を書いたら良いのかがわからなかったので、いろんなサービスの About っぽいページを参考にしながら書く内容を吟味しました。

デザイン面では、初期版では中央揃えと箇条書きが混ざって非常に読みにくくなっていたり、箇条書きのインデントがどんどん深くなって読みにくくなっていたり、画像の大きさが端末によっては適切でなくなってしまうという問題があり、修正しました。

アクセシビリティも重視しており、視覚に関する一部の情報がなくてもブラウザの支援機能等を利用してサイトの利用ができるように考慮しました7

iPhoneのリーダー機能、存在は知っていましたが、まともに使ったのはこれが初めてでした。

その他の観点

こちらのリプツリーに(項目だけ)あります。 実装以外にも、βテストしたりローカライズちょっとだけしてみたり、プロジェクト管理頑張ってみたり、色々してました。

評判・評価

というわけで、リリースには時間がかかってしまいましたが、嬉しいことにリリース後、かなりたくさんのポジティブなリアクションを頂きました。

AtCoder 社長(chokudai さん)にもポジティブな評価を頂けたようです。やったね。

動画再生数的には、UUが1.1万なので、AtCoderのアクティブなコンテスト参加者数(〜1万)を考えると、かなりの割合の方に見てもらえたんじゃないかと思います。

AtCoder Companions は新規利用の際にトークンが発行されるのですが、その数によると770人超の方に実際に使って頂けたようです。ありがとうございます。

Dynamo DB のItemの数

感想

とりあえず、目標としてたサービスを作りきることができ、ホッとしました。 更にリリースしたサービスがしっかり使われていて、かつポジティブな反応が数多くあったため、正直めっちゃ嬉しかったです。

またいつもめんどくさがってやらないことにも手を着けられたので、学びが非常に多かったです。 特に、(技術面、デザイン面、企画面、プロマネ面の学びももちろんありますが)法律面の学びがあったのは大きいと思います。

課題も解決できたし、満足感も得られたし、自分自身の学びにもなったので当初の目的(動機)はほぼ達成できたのではないでしょうか。

ただ、今後の課題ですね。としたところもたくさんあるので、まだゴールではなく、今後も開発を続けていきたいと思っています。

また、記事をアップロードするのが遅くなり申し訳ありません……🙇‍♂️ そしてダイジェストのはずだったのに結局1万文字以上書いてしまった……

まとめ

Web開発やばいけど楽しいのでみんなやろう。あと AtCoder Companions 使ってね。

明日は、@ichi-raven さんの 主にC++の話(?)です…… ってもう出来てる!?素晴らしすぎる(n時間遅刻した自分を見ながら)


  1. 当初は1週間で作り上げる予定でした。そんなうまくいくはずがないですね。
  2. 同じ間違え方をした提出をリアルタイムで検索するには、予めコンテストの提出一覧にアクセスし、各テストケースの結果を抽出・インデックス化する必要がありました
  3. スクレイピングしてデータの解析に用いる用途であれば、問題はなさそうではある。
  4. 後に規約系は日本語バージョンを優先することにして対処しました
  5. 間違え方ごとにファイルパスを与える関係で、S3ファイルに大量に細かいファイルを上げています
  6. といっても100円弱/月 程度。
  7. Chrome の色覚特性をシミュレーションする機能や、ウェブアクセシビリティ導入ガイドブックなどが参考になりました

ISUCON 12の予選に参加したよ!

はじめに

ブログではお久しぶりです。@kakira9618 です。前の記事が約7年前ですが、Twitterでは元気に飯テロしてます。

さて、今回、ISUCON 12 の予選にチーム kakipippi として参加してきました。
結果は、、、スコア0(泣)でしたが、色々収穫があったので忘れる前に記事にします。

超長い(19000文字以上あります)ので注意。

目次

メンバーについて

Twitterのフォローワーの @tran0826 (かいと; 敬称略) と @ui_mtc (スギノキ; 敬称略) と一緒にISUCONに参加してきました。 全員Web系の会社勤務で、私以外のふたりは初めての参加です。また、みんな競プロ経験勢(特に、@tran0826 は橙コーダー)です。

私は今まで4回ほどISUCONに参加してきましたが、サークルの先輩と一緒にチームを組むことが多く、おんぶにだっこという形で参加させていただいていました。 しかし、今回は自分が一番先輩ということで、おんぶにだっこではマズい、引っ張っていく側にならなきゃという意識で臨みました。

Web・インフラの経験について

私のWebの経験は、小学生くらいのときに自鯖(ftp, http, ssh)建てたりCGIを改造してみたり〜から始まって、はてなインターンperl/Swiftを使った(当時の)モダンな開発を経験したり、研究室のサーバーを管理したり、会社の研修で、ミニアプリ(AtCoder Replay)などを作ったりしてた、という感じでした。業務(4年目)ではセキュリティということで、開発のレイヤーをガッツリと触ることは少なかったですが、AWSGCPを使う案件も多く、それなりにクラウド技術などは触っていたりしました。プログラミング経験全体からみるとWeb専門、というわけでは無いです(ゲームのほうが長いです)が、一応ISUCONが改善の対象とするレイヤーの経験は一通りある、という感じです。

@ui_mtcと@tran0826のふたりは、業務で初めてWebに触れていて、それぞれ1年目、2年目でした。@tran0826は、ちょうどISUCON練習が始まる前にwebで動くフーリエ級数展開ゲーム(!?)を趣味で作っていて、すごい。

@ui_mtc は現在進行系で会社のwebの研修を受けていて、クライアント側の開発(Reactなど)を勉強しているところ、とのことでした。

事前準備について

時系列で書きます。(ここから常体)

6/6以前 Twitterにて

@ui_mtc と @trans0826 が Twitter でチームメイトの募集をしているのを見かけて、申し込む。

6/6 爆速登録

@tran0826 が爆速でISUCONの登録をこなす。

1分10秒で締め切りって何ていうISUCON?

6/13 kickoff MTG

kickoff MTGがあった。軽くISUCONやWeb・インフラ歴などを共有したり、使用言語(go)を決めたりした。あと、定期的に勉強会をしようという話になり、各自勉強することを決めたりした。

6/22, 6/29, 7/6 練習前半(Web全体像講座)

勉強会。@ui_mtc がちゃんとGoの自習(Go tour)を進めていて、わからないところは質問したりしてて偉すぎる。また、ISUCON12の事前講習とかの情報を@tran0826に共有してもらう。

自分は何をしたかというと、ISUCONの技術領域はとんでもなく広く、web開発に関する全体像(概要)がつかめていないと勉強するハードルがかなり上がってしまう&チーム内の意思疎通が難しくなってしまいがちだと思ったので、ISUCONの理解に必要な事項に絞った、Web全体像を把握する講座(?)をメンバー向けに開いた。資料が用意できなかったので、jamboardで手書きで色々書いたのだが、今板書を見てみるとあまりにもカオスで笑った。書くのも練習が必要ですねこれは()

Web全体像講座の一部。その場のノリでどんどん書いていったため、カオス。(できればiPadとかを使って手書きしたかったけど、jamboardのレスポンスが悪くて結局マウスで書くことに。。何か良い手書き共有サービスがあったら教えて下さい!というか作るか・・・)

内容は、

  • クライアント、サーバー、HTTPリクエスト/レスポンス(厚め)
  • 静的なページを配信するシステム
  • 原始的な方法(CGI、ファイルによるDB管理)で動的なページを配信する方法の説明
  • DBMSSQL、placeholder、ORM
  • MVCフレームワークを使ったWebアプリの開発
  • ネットワーク(特にIPアドレスとポート番号が何を識別するのかについて)
  • プロセス
  • リバースプロキシ・LBの導入、DBの分割
  • 公開鍵暗号方式sshd
  • linuxのコマンド(随時)、ファイルパーミッション、所有者

という感じです。ISUCON向けに絞った(例えば、Reactなどフロントエンドの開発については割愛している)ものの分量的にはかなりあって、これを2日に分けて合計5時間くらいで説明したのでだいぶ急ぎ足の説明になってしまった。 本当はセッション管理とかgit、Docker、CIとかも説明したかったけど、時間の都合上、割愛。

効果がちゃんとあったかどうかは不明。だけど、これ以降、少なくとも意思疎通で困ることはなかった。

7/9, 7/17, 7/20 練習後半(ISUCON 10予選による実践練習)

このあたりで、実践練習をしていた。過去問が色々ある中で、練習の対象にしたのは ISUCON 10 予選 だった。これは

  • そこそこ新しい
  • ISUCON 11 予選 は直前練習とか用に取っておきたい
  • さくらクラウドのクーポン1を使って、無料で練習でき、ISUCON10予選用の環境構築方法が丁寧に記述されたマニュアルがあった

といった理由で選んだ。結局時間無くて ISUCON 11 予選の練習はできなかった…(泣

実際にインスタンスを建てて、環境をセットアップして練習した。やはりスムーズに行く感じではなく、sshログインからベンチ走行まで、計測ツールのインストール&設定から実行まで、個別の改善x2まで、と一つの問題を4回くらいに分けて解く感じになってしまった2ssh-agent の挙動が Win と Mac で違ったり3、コード管理の方法の方針を決めたり4でかなり時間がかかってしまった。

また、作業をしている中で、ツールのインストール・設定方法や、躓いた点、参考文献などをドキュメントにしておきたかったので、github に isucon12-memo というプライベートリポジトリを建てて、チームに共有した。 memo のつもりでちょっと雑に書いてあるため、特に@ui_mtc を混乱させてしまった面もあり、反省5

isucon12-memo はこちら。間違いとかもあると思うので、ご利用は自己責任で。 github.com todoがまだある状態で本番を迎えてしまったため、来年までになんとか詰めておきたい。

本番前の最後の練習日に、役割と本番の立ち回り6を決めて、いざ本番……!!!という感じだった。

本番・・・の前に (計測くんについて)

いざ本番!って感じだったのだが、ここでちょっと天啓が・・・。

@kakira9618「Discord で計測結果見れたら便利なんじゃね?」

残り2日くらいしかなかった&計測の役割を@ui_mtcに振ってからの発想だったので申し訳なくなりつつも、かなり便利だと思ったので、急いで実装。 言語はpythonで、discord.pyを使えば結構カンタンに Discord bot を作れるということがわかった7ので、コードの質とかはガン無視してとにかく動くものを作った。出来上がったのはこちら。

Discord bot 『計測くん』の動作例。benchと打つと、ベンチマークを走らせて、各種計測を行い、Discordに結果を投稿してくれる。

これ、すごく便利でした。チームメイトの2人にもたくさん使ってもらえました。Twitterでも反響があり、やっぱり手続きを簡易化したり可視化したりするのって大切なんだなぁという感触を得ました。

ちなみに、以下に示すとおりbenchコマンド以外にも色々実装しましたが、本番で使われることはありませんでした。。。8

  • ベンチ中に計測コマンドを発行する機能…ベンチマーカーの出力に特定の文字列が現れたら、そのタイミングで計測コマンドを発行できるようにした9
  • 計測だけをする機能…3台のサーバーを組み合わせた実装になったときに、ベンチをリクエストするのは1台だけのはずなので実装。
  • alp コマンド機能…alpはデフォルトのオプション以外にも使う状況がありそうなので実装。
  • 任意のコマンド実行機能…RCEです。普通にsshで打てば良さそうだけど、ログを取ったほうが良いことはあると思うので、ログ機能付きの簡易シェルとして実装。

具体的に良かった点を言語化すると、

  1. ベンチ実行 -> 計測 -> 投稿までDiscord上の簡単なコマンドで行えるため、効率が上がる。ベンチマークを回す回数を増やせるので、それだけ改善に時間を割くことができる。("4人目"ができるようなもの、だと思ってます)
  2. コマンド操作に慣れていなくても、誰でも簡単に計測を行うことができる。
  3. Discord上に計測結果が集約されるので、見やすい。ログが確実に残るので、あとから見直したりできる。
  4. ツイッターで少しバズる(?)

など。悪かった点は反省(後述)で。特にコマンドの扱いに慣れていないメンバーもいたので、2.のメリットはかなり大きかった。また、3. は本来コンテスト中に役立つかなぁと思ったが、まさに今、ブログを書くときに役立っている。git commit のように、そのベンチで何を改善したのか、というのをコマンドの引数として入れる実装にすれば、あとになって振り返るときにもっと楽なのかもしれない。

コードはこちら。RCE機能が入っているので、セキュリティにはお気をつけください。

github.com

ギリギリまでコード修正などをして、なんとか作り上げられた。しかし、作り上げられたという達成感と、本番への期待感が入り混じってしまい、本番前日は結局一睡もできなかった。前日に作業するの禁止したほうが良さそう。

本番

そして、いざ本番! コミュニケーションコストや家の広さ等を考え、3人とも @tran0826 の家に集合することになった。

ちゃんとしたイス+デスク+デュアルモニタ環境が2セットもあってすごかった10。めっちゃ作業しやすかったです。ありがとうございます。

6:00 頃 起床(?)

眠れないので「計測くん」を改善する。起床技術者試験、突破(?)

7:45 頃 出発

家を出る。深夜テンション。

9:40 頃 到着

みんな家到着。特に@ui_mtcと会うのは久しぶり(2年ぶりくらいかな)。ISUCON生放送を聞く。

9:55 頃 問題説明

問題の説明が始まる。動画がめちゃくちゃ豪華・・・! なるほど、SaaSか。なんか複雑そう? でも機能はそこまで無いのかな?

10:00 頃 開始

開始!ポータルから選手用サイトにログイン。 事前の打ち合わせ通りに、自分はまっ先に当日マニュアルを開き、手順に沿って環境をセットアップ。cloudformation で yml 選択してポチるだけ。簡単。

10:10 頃 ssh接続で躓く

インスタンスが立ち上がったのを確認する あれ、なんかsshしても deny されてしまう。なぜ…(2分くらい考える) あ、そうだ!事前準備のenv_checkしたのだいぶ前(1ヶ月くらい前)で、そのときに入っていなかった公開鍵(私用PC用)を後からgithubに追加したんだった。多分事前準備で env_check したときの公開鍵が自動的に ~/.ssh/authorized_keys に記述される設定になっているのだろう、と思い、急遽 @tran0826 にsshログイン&自分の公開鍵を追加してもらうことにした。すまん。でも無事ログインできた。

おっと今回はサイトにHTTPアクセスするのに /etc/hosts の編集が必要らしい。なるほどね。設定をDiscordに投下。 初回のベンチを回す。3000点くらい。

10:20 頃 構成把握

sshログインして、どんな構成か軽く見て回った11

練習(ISUCON 10)では接続ユーザはubuntu、webアプリが置いてあるユーザはisuconとなっていたので、まずisuconでログインできるようにするところから始めていたが、今回は必要なさそう。

nginxとかmysqlはsystemdにぶら下がっているのか。あれ、でも docker-compose-go.yaml があるぞ?あ、アプリはdockerで管理して、dockerdをsystemdで管理してるのか。なるほど。

goのコードを眺める。うわ長そう(そっ閉じ)。

メモリ量などスペック把握。OK。

10:30 頃 リポジトリ用意

計測ツールを入れるか・・・!となったが、その前にリポジトリの準備が必要だったので、githubリポジトリを作り、webappをpush。

また、設定ファイルも管理したいので、/etc/nginxの中身を/webapp/etc/nginxに移して、/etc/nginx -> /webapp/etc/nginx などのシンボリックリンクを貼った。権限周りで何か起こると面倒なので脳死sudo chmod -R 777 /webapp/etc/nginx などした。mysqlも同じように設定12シンボリックリンクのコマンドは混乱しやすいので、前日に練習していた。順調順調。

このへんでチームメイトが重要そうなことメモを作ってDiscordに投稿してくれた。ありがたや

10:40 頃 計測ツール導入

ツールを入れはじめる。 予め用意してあった isucon12-memo を見ながら設定した。 まずalp。/etc/nginxシンボリックリンクの設定はうまく出来てるかな? -> 設定変更、反映確認。できてそう! dstat, netdata はインストールするだけ。OK。ちゃんと動作確認済みの資料用意しておいてよかった〜。

10:45 頃 pprof が導入できない

このあたりから雲行きがおかしくなる。pprofがうまく導入できない。導入するとアプリが落ちるんだけど・・・。と思い、journalctl でログを確認。

なんか WAF (Web Application Flamework) にecho じゃなくて echo/v4 を使っているらしい。memoは echo用にラップされたモジュール github.com/sevenNt/echo-pprof を使って設定する手順を書いていた。しかし、これは echo/v4用ではなく echo 用であり、ラップする関数を読んでいるところで引数の型が整合しなくてエラー落ちしてた。github見に行くとv4対応されているようなので、go get で最新のコミットを指定してインストールしなおすもうまく行かず。ラッパーを使うの諦めて自分で全部書くのも視野に入れるか、、、なんて思っていたところに、github.com/hiko1129/echo-pprof が引っかかり、導入してみたらうまく行った。ここで30分くらいロスト。

他のチームメイトはこのあたりでアプリを触ってもらっていた。セキュリティがガバガバである。

11:15 頃 my.cnfが反映されない

なんとかpprof動いたので、次は pt-query-digest。まずは slow-query の設定をしなきゃ。。。ということで my.cnfを設定するも、実際に mysql にログインして確認すると設定値が変わってなさそう。え?シンボリックリンクミスった?と思ったが、問題はなさそう。journalctl 読むと、/webapp/etc/mysqlパーミッションがあまりにもおかしいので my.cnf の読み込みを ignore した、と出てて、なぁんだ、となる。パーミッションを戻す。

しかしそれでも設定値が反映されない。 というかデフォルト設定の slow_query_log_file = ほげ/ip-192-168-0-12-slow.log ってなんなんだよ。となり、mysql のバージョンを確認してみると 8.0 ということがわかる。今まで5.7で練習していたので、これが原因か orz となった。8.0をつけて設定をググるがなかなか設定値を反映させることができない。mysql の help から my.cnf を読み込む先を取得できるらしいということをググって見つける。色んな場所にmy.cnfを置いてみるがやはり反映されない。/root/.my.cnf とかも試してみるが、やはりだめ。えっ・・・mysql 5.7に戻すか、、、と思ったが、アプリケーションに影響が出るのが怖いため、それもしたくない。(この地点で12:00くらい)

八方塞がりになってしまったので、いろいろごちゃごちゃやったあと、一旦 /etc/mysql の状態をもとに戻した。すると、slow_query_log=1 の設定だけは反映されていることがわかる。え?マジ?どうやらシンボリックリンクにするとうまく動かないようなので、一つのリポジトリにするのは諦めて、/etc/mysql 用のリポジトリを作った。しかし、/etc/mysql の設定ファイルは所有者が root のためgitコマンドを発行するのにいちいち sudo が要る。そして push することができない13。過ぎていく時間。全てを諦めて、git管理するのを諦めた。ごめんなさい。。。

しかしslow_query_log_fileの設定は全然変わらない。おかしいなぁと思い、もうそこで良いか、と思った瞬間に、設定値に""がついていたことに気づく。これを消してみたところ、反映された。mysql 5.7では動いたのに。。。えぇ・・・。

ようやくpt-query-digest の動作確認が取れる。この時点で午後13:30くらい。

13:30 頃 計測くん導入

本当はお昼にしたかったが、まだ計測くんを導入していなかったので、導入。 。。。インストール中の細かいエラーをやっつける。pip3が入ってなくてちょっとだけつまずく。と、ここで、ベンチマーカーの仕様がISUCON10のものと大きく異なることに気づく。あ、コマンドラインじゃなくてブラウザからボタンを押して運営にjobを積むタイプのやつじゃん、となる。curlなどでベンチを開始を押すことはできたかもしれないが、ハマりそうな気がしたので、ベンチは手動で押す方式にして、その後の計測はタイマー式で発火するように、プログラムを変更14

プログラム変更が終わり、ようやく指標が取れるようになる。時刻15:00。えぇ・・・(ここまでが午前で終わる想定だった)

この間に、ふたりがアプリの解析を進めてくれた。なんか排他ロックとかsqliteとか言ってて怖い・・・ ちゃんとチャンネルに気になったことをまとめてくれていてありがたい。

15:00 頃 休憩

お昼休憩。おにぎりとかチョコとか食べる。

15:15 頃 アプリの説明を受ける

@trans0826 にアプリの説明や構成などについて聞く。あぁSaaSってそういうことか、となる。コードの説明を聞いて、なんかMySQLsqliteが両方とも使われているらしいことを知る。ロックのとり方もなんか変。それってトランザクションでやるやつなんじゃ・・・。一意なIDを生成する場所もよくわからない重そうな処理をしている。stubって何に使われているんだ。sqlitemysql に移行できたらこの辺良くなりそう15。など考えていた。

15:30 頃 残りのインスタンスに計測くん導入

今後の方針をチームメイトと相談し、引き続き2人にはアプリの解析と改善を行ってもらうことにした。私は計測くんが他のインスタンスでも動くように設定することに。16

16:00 頃 ちょっと休憩

全てのインスタンスで計測くんが動くようになった。疲れたのでまたちょっと休憩した。

@tran0826 がsqliteのインデックスを貼ってくれたりしてくれている。ありがとう。また、pprofの結果を見るに、sqliteボトルネックらしいことも聞く。 sqlite はファイル開きまくるイメージがあったので、ファイルディスクリプタ数が足りてないんじゃないかと思い、そのあたりを調査することにした。問題はなさそうだった。 また、@ui_mtc がnginxの設定などのチューニングをしてくれたりしてた。さらに Unix Domain Socket への移行もやってくれるみたい。超助かる。お願いします。

また、このあたりで、ベンチを実行する際のホストの番号と、AWSで立ち上げたインスタンスに付与されているIPアドレスの順番が異なることに気づく。@ui_mtc が自分のインスタンスに負荷をかけているつもりで、実は@kakira9618のインスタンスに負荷をかけていたらしい。このあたりは私は気づいていた&ハマりやすいなと思っていたので、もっと早く共有できていれば、と思った。ごめんなさい。。。

16:30 頃 flock改善

もうあまり時間がないけど、インフラ側でできそうなことはだいたい終わった&今回はアプリがメインのチューニングポイントっぽいので、@kakira9618もアプリの改善をすることに。チームメイトにはN+1とかに取り組んでもらっているので、それ以外のところをチェック。

計測くんの pt-query-digest をみると、slow-queryが出ていることに気づく。mysql側でもインデックスが貼れそう。具体的にクエリで引いている表にどのくらいのレコード数があるかなどを検証したら、多重度高めでインデックス貼ったら効果大きそうだったので、@tran0826にインデックスを貼ることを提案。実装してくれた。でもスコアはあまり上がらなかった。

次。なんかロック取りまくっているところは、明らかに改善できそうだったので見てみる。トランザクションを入れることも考えたが、とりあえず、全部ロック外してみたらどうなるかな?と思い、外したバージョンを投げる。

-> 5000点くらいの点数(コンテスト中弊チーム最高点)。おおおおおおお!!!!!!!! となったが、再度キューに突っ込んだところエラーが。なんかデータのvalidationが通ってないらしい。実際にデータベースが壊れていた。

一個だけロック外したバージョンなども試してみたが、やはりDBが壊れてしまうようだったので、だめぽ。いったんロックをもとに戻し、コードを眺める。ロックの解放の位置を見てみると、全て defer fl.close() となっていたので、関数終了手前であることがわかる。本来ならそこまでロックを取る必要は無いはずなので、適切な位置で fl.close() を読んであげるように修正する。 排他ロックは、今回はファイルをつかったもの (flock) となっているため、diskのi/oがロックを取得するたびに発生する。これを /tmpfs などのメモリ上におけたら良いなと思い、 /etc/fstabなどを編集してメモリの領域をマウントする。これを書き込み先として設定して、、、スコアが伸びなかった(残念)。もうちょっと伸びてくれていいのに。と思ったが仕方ない。

@ui_mtc の Unix Domain Socket の実装が完成し、master にマージされる。これはベンチ見る限りちょっとだけ早くなってそう。ナイス!

17:50 頃 最終処理

ここまでで、競技時間は残り10分と、本来最終フェーズに割り当てた時間を大幅にオーバーしていた。流石にこれ以上改善するとリスクがあるよね、ということで、最終フェーズに移行する。デバッグログの設定を消し、mysqlのスロークエリやnginxのアクセスログを出力しない設定にしたりした。これで再起動、、っと。あれ、なんか失敗してる(5分前)

あ、なんか Unix Domain Socket 対応で追加したはずの .sock ファイルが消えてる・・・。修正。→あれ、うまく起動しない。

え、焦る自分。みんなの状態を確認すると、どうやら@tran0826のインスタンスだけ今正常に動いているらしい。ということで、残りの設定を@tran0826のPCでやることに。英語配列のキーボードが上手く操作できない。。。設定後、再起動などしてもらったのだが、そこでやはりエラーがでてデーモンが立ち上がらない。journalctl を見て、、、とかやろうとしているうちに、18:00 競技時間終了!でした。はい、0点です。

ISUCON12 予選に参加して良かったこと

以上のように、結果は奮わなかったISUCON12予選でしたが、良かったことや収穫もありました。

準備フェーズ

勉強会を定期的に開いたこと・実践を取り入れられたこと

週1〜週2くらいのペースで、リモートで勉強会を開催しました。定期的に勉強会を開くことによって、モチベーションを保ちつつ学習できました。リモートということもあり、やはり回数を重ねないとどうしても存在感が薄くなってしまうので、ある一定期間定期的に勉強会をすることには意味があるなと思いました。

次の勉強会までにやってくることを各自Discordに投稿しておいたのも良かったと思います。かなりやることは明確になっていたと思います。17 内容としては、かなり基礎的なもの(Web基礎、go tour、sshの設定、各種計測ツールの使い方等)でしたが、最低限これができなければお話にならない、というラインは押さえられていたんじゃないかと思います。

また、後半の勉強会では実践形式で、実際にサーバーを建てて練習できたのが良かったと思います。実際にサーバーで手を動かすことによって、躓くところなどを事前に洗い出しておくことができ、それを基にして isucon12-memo を作ったので、設定でハマるということが(想定された環境の通りであれば)あまりなかったと思います。予選本番でも、実際にサーバー内の環境を見てみて、どういう構成になっているのかを一から把握すること無く、「あ、今回はsystemdを使っているんだ」「webappはdockerの上で動いてるんだね」「スキーマ定義はここだね」などスムーズに把握することができたと思います。やっぱり手を動かすことは大切です。

isucon12-memo の準備

調べたことをDiscordに貼っていくというのを当初考えていたのですが、Discordはどんどんログが流れていってしまうので、ドキュメントの整備には向いていないと思い、github内のリポジトリで管理する形式としました。@ui_mtc に git コマンドに慣れてもらうといった意図もありました。

メモ(の多く)は以下の形式で書きました。

## title
### 概要

### インストール方法

### 使い方

### 備考・注意点・躓いた点

### 参考文献

また、質の高いドキュメントにするために、

  • ググってURLを貼って終わりにしない。基本的に動作確認を行ったものを書く。自分の環境の出力結果を載せる。
  • URL先がリンク切れになっても使えるように、コード、設定値等は(参考文献を明示した上で)引用しておく

という点を意識しながらドキュメントを書いていました。本番でもかなり役になってくれたと思います。

計測くん

メリットなどは「本番の前に」の節で既に述べているので割愛。

計測くんを作ったのはとても良い判断だったと思います。本番後になって気づいたのですが、実際に、ISUCON 12 の事前練習のスライドにも、デプロイ -> 性能計測 ->プロファイル まで一気通貫やれる仕組みが整っていると完璧、とありました。今回はこれが2/3ほど(デプロイ以外)実装できましたね。

speakerdeck.com

また、他のチームはどうしているのか調べたところ、fluentd + elasticsearch + kinaba 18でシステムを作っているチームやElastic Stack に加えて、Google Cloud Profiler などを利用しているチーム19もあるようでした。

pythonを使ってbotを作るという選択は、最小限の労力で高い効果を得たという意味で、良かったと思います。一方で、調べられる情報量と表示の仕方はfluentd + elasticsearch + kinabaといった構成のほうがベターだと思いました。セットアップにかかりそうな時間と慣れ、効果などを総合的に判断して導入する仕組みを決めたいですね。

インフラ層の典型を学べたこと

isucon12-memo を作っている中で、定番のネタ(OSのファイルディスクリプタ数をチューニングしたり、Unix Domain Socket を使った通信を行ったり、とか)を習得することができました。今まで概念だけ知ってたけど、設定方法は知らない、、、といった段階から、ドキュメント見ながらであれば、特に迷わず設定できる、といったレベルまで上げることができたと思います。

更に、インフラ層の典型は、アプリ層が変わっても基本的に有効なため、今後のISUCON、または業務などにも活かすことができるはずです。これは、ISUCON予選に出場して得た明確なメリットだと私は思います。

本番

作業環境

@tran0826の家の環境がとても良かったです。外部ディスプレイが2個あって、片方は縦置きだったのですが、縦置きディスプレイはログとか流しておくのにちょうどよいですね。ちょっと欲しくなってしまいました。

また、長時間イスに座って作業してたのですが、終わっても全然辛くなかったです。あのイスなんてやつだろう・・・?

進捗共有

直接声に出して伝える情報と、Discordにテキストとしてメモしておく情報をうまく使い分けられたのが良かったです。

今から〇〇やります/やってます、〇〇サービス今落ちてますーなどの状態等の共有は、直接声に出して、作業を進めました。同じインスタンスを2人以上の人が改変すると、謎の挙動が起きてしまうということがあると思いますが、そういうことは今回は起きなかったと思います。

また、ドキュメントやコードを見て思ったことなど、忘れやすそうなことは、声ではなくDiscordにメモしておいたのも良かったと思います。忘れるのを防止するというだけでなく、作業中の人の集中力をカットしてしまうことが防げたと思います。

計測くんをなんとか動かせたこと

せっかく用意しても動いていなかったら意味がないので…。

色々トラブルがありましたが、競技後半には計測くんが動いている状態になっていたことが良かったと思います。予期せぬ本番でのコード改変も、直前に自分がコードを書いていたので、あまり大量に時間を浪費せずに改変することができました。このあたりもオリジナルで計測botを作ったのが活きていると思います。

反省点・敗因分析

一方で反省すべき点も多いISUCONでした。

準備フェーズ

isucon12-memo の情報不足

isucon12-memo ですが、本番で実際に運用してみる(メンバーに使ってもらう)と、「このコマンドはどこで実行するのか」、「パスの指定は、この環境の場合どうすればよいのか」と言ったところで詰まるところが多かったようです。特に手元、サーバー、コンテナ内を行き来するISUCONにおいて、どこでコマンドを実行するべきかを記載しなかったのはかなり痛手だったなと思いました。自分でメモを作るときは、手元の端末の今の状態でコマンドを打てば良いので、どこでコマンドを打ったかという情報をメモすること自体を忘れてしまいがちなのが罠なのかなと思いました(パスも同様)。このあたりは、改善が必要な点だと思います。

また、単純に調べる時間が足りなくて、todo.md に複数 todo が残ったまま本番を迎えてしまいました。埋めれば、それだけネタの引き出しが増えるということで、本番に取れる作戦の幅が広がります。来年までには埋めたいですね。

全体的な練習不足、特にアプリ部分(go)に関する実践練習・習熟が足りなかったこと

今回、スコアがなかなか上がらなかった原因はこれだと思っています。

インフラ層の実践練習はそこそこ行ったのですが、アプリ層の練習はあまり行いませんでした。go を使うと決めたのに、goを使ったweb開発の練習が足りていませんでした。基礎的な文法とWAFの使い方くらいで勉強が終わっていたため、他のいろんなモジュールを使った開発や、周辺エコシステムに慣れるといったことをあまりしていませんでした。

DB周りについても、インデックスを貼る、ぐらいのことはできたものの、トランザクションを使ったり、副問合せをつかったクエリを組み立てたり、といった普通の開発でよく出てくる要素の練習をほとんどしていませんでした。

今回のISUCONはかなりアプリが複雑だったので、そういった開発の経験や改善の引き出しの数が十分に無いと、改善に踏み込むことができない(怪しいところはわかるものの、どうやって改善したら良いのかがわからない)問題だったと思います。

睡眠不足

謎にテンションが上がってしまい、前日は全く眠れませんでした。

本番中に寝てしまうことはオフラインだったのでなんとか防げたものの、やはり集中力は下がってしまうので、寝たほうが良いです(当然)。

とは言っても、実際に前日に十分寝るのはなかなか難しいです。解決策としては、前日はあまり作業を行わない、というのが良いのかなと思いました。作業をしてしまうと、どうしてもそのことを考えてしまうので。。。そのためにも、直前ではない日に、ISUCONの作業時間をとっておくのは大切だと思います。

本番

計測くんを入れるのに手間取った

計測くんを入れるためには、計測ツールをインストール・設定しなければならず、まずこれに時間がかかりました。 次に、計測くん自体を改変する必要があり、これにも時間がかかってしまいました。 結局、ISUCONの時間の半分を計測くんの導入にかけてしまっていた計算になります。これではアプリの改善に力を入れることはできません。

このあたりの解決策としては、

  • 計測くんをコンテナ化する
  • ansible などを使って、provisioning を自動化する

などがありそうです。今回は、時間不足でここまで踏み込むことができませんでしたが、今後は検討したいと思います。

インスタンスの使い方と戦略

今回は、各インスタンスごとに、gitリポジトリをもたせ、github の プライベートリポジトリに変更内容をcommit + pushして共有。他のインスタンスでの変更は、各インスタンス上でpullする、という形を取っていました。

この方式は、練習時は良かった(1人1台担当にすることができる、サーバー上でファイルを直接イジって動作を確認できる、並列に作業できる)のですが、本番では複数台を組み合わせた構成(アプリ1台+DB2台など)など当然各インスタンスでの役割は異なることが多いため、インスタンス上gitでデプロイを行う方式とは相性が悪かったです。

手元でコード管理をしつつ、デプロイコマンドを各インスタンスに向けて行う方式(Jenkins、ansibleとか)にしたほうが良かったかなと思いました。

また、各メンバーは、並列に改善を行っていたのですが、チームの特性を考えると、今回は(必要なセットアップが終わったら)みんなで一つの改善ポイントに向かい合う、といった形のほうがスコアが出たのではないか、と思います。このあたりは、個々のスキルや得意分野を見て、柔軟に決める必要がありそうです。

メンバーのトラブルシューティングにあまり関われなかった

(特に競技前半と中盤で)予想以上に環境のセットアップに時間がかかってしまったため、メンバーのヘルプにあまり付き合えなかったのが良くなかったです。ほとんど残りのメンバーにそのあたりの作業を丸投げしてしまいました。 次回以降は、環境セットアップの作業をもっと短縮した上で、重要度の高い

最終フェーズの時間の短さ

0点になってしまったのはこれが原因ですね。時間が足りなかったのはそうなのですが、流石に残り10分では厳しかった。。。

……もっとたくさん書きたいのですが、きりがないので、ここで終わりとします。

感想

ISUCON 12 楽しかったです!!!!今までももちろん楽しかったのですが、今回はしっかりと(当人比)練習して取り組んだだけに、今まで一番楽しかったと言っても過言ではないと思います。普段、あまり文章を書かない自分が、約19000文字もあるブログ記事を書くのはかなり異例のことで、自分にびっくりしています。

しかし、それだけに、0点という結果はかなり悔しかったです。せめて、5000点くらいは取りたかった。。。 ただ、悪いところばかりというわけでもなく、収穫もちゃんとあったと思うし、チームメンバーも最後までついてきてくれた。

今回のISUCONの悔しさをバネにして、来年こそは予選を突破したいと思います!

まとめ

  • 勉強会を定期的に開いて、Web全体像の講座をしたり、メモのリポジトリを作ってドキュメントを共有したよ
  • ベンチ実行 -> 計測 -> Discordに投稿してくれる bot を作ったよ
  • 環境セットアップや作戦など、改善すべき点がたくさん見つかったよ
    • 次は、ansible とか使ってデプロイ環境を整えつつ、app層の経験を積んでいくと良さそう
  • 前日は早めに寝ましょう

お疲れさまでした。良いISUCONライフを!

他のメンバーの参加記も読んでね


  1. ISUCON参加者向けに配られたクーポン。なんと2万円分という太っ腹ぶり。ありがとうございます!(AWSも本番用に5千円のクーポンを発行してくれた。ありがとうございます!!)

  2. 当初は、最初の2回くらいで1年分の問題、その後本番形式で、別の問題を1個やる、という想定だった。

  3. win (WSL) では eval ssh-agent の実行が ssh-add の前に必要だったりするやつ。

  4. 複数(3個)あるインスタンス間でどのようにコードを共有、メンテしていくか。途中でインスタンスを6個(dev+live)作る案が@ui_mtcから出てなるほどとなったが流石にリスクがありすぎたので、プライベートリポジトリをGithubに立てて、3台それぞれのインスタンスをメンバー一人ずつに割り当て、個々のインスタンスからcommitをpushする形に落ち着いた。

  5. コマンドをどこ(自分のPC上か、インスタンス上か、インスタンスの中のコンテナ上か)で打てば良いのか、とかホストとコンテナ間のパスの対応とかがきちんと示されていなかった。このあたりは、ある程度経験があれば察することができてしまうので、テキトーになってしまっていたが、初心者向けに質の良いドキュメントを書くには大切なことだなー、と再認識させられた。

  6. 自分は最初の環境のセットアップと、インフラ周り担当、@tran0826はアプリとDB担当、@ui_mtcは計測とmysqlのチューニングあたり担当という感じになった。また、午前は環境のセットアップを@kakira9618がしている間に、残りの2人はルールの熟読とアプリのコードを眺めてもらって、実際の改善は午後からスタートすることにした。最後の1時間は、ログの出力設定の削除、不要なサービスの終了設定、再起動試験などに充てることにした。

  7. 初めての Discord bot 制作だった。基本動作やエラー処理など面倒なところはほとんど discord.py が吸収してくれるので、あとはコードを書くだけという感じだった。むしろ最初の bot 連携のところがちょっと複雑だった(といっても数回マウスでポチる程度)かもしれない。

  8. どちらかというと、使うところまで改善が進まなかった、って感じですね。ぐぬぬ。。。

  9. がしかし本番ではベンチマークの走行がWebUIであることを失念していたので、本番でこの部分は使われることはなかった。本番中に急遽コードを書き換え、Discord上のbenchコマンドを受け取ってから、15秒後に計測コマンドを走らせる形式(ベンチ走行は手動で人間がWebUIから行う)とした。

  10. @ui_mtc はちゃぶ台机を使ってもらった。普段の開発もノートPCだけで行っているとのことだったけど、姿勢とか大変そう。申し訳なかったです・・・。

  11. 実際には VSCode の Remote SSH プラグインを使い、VSCode上で見て回った。慣れているUIなのでとても作業がしやすかった。またmacだとssh-agentとかもちゃんと有効なので、そのままgitできたりしてすごく便利だった。設定も ~/.ssh/config に書くだけなのでらくらく。

  12. sysctl もするべきだった。がすっかり忘れてた。

  13. sudo でユーザーが変わるので ssh-agent に持たせた秘密鍵を引き継ぐことができていない、のだと思う

  14. curlで叩きに行こうとしても認証付きで CSRF とかも対策しているかもしれずリクエストを生成する必要があるかも。またうまく行っても結局ベンチの出力は随時では得られず、全て終了してからでないと得られない、等の点からベンチ走行自体自動化は諦めたほうが良さそうと考えた。しかしタイマー式はタイマー式で、確実性にかける、というデメリットがある。特に運営側のjob処理が安定していないと、タイマーは使えない。今回はそういうことはない!と運営を信じてタイマー式に移行を決断。実際、今回はベンチマークがすごく安定していてすごい(語彙力無)と思った。

  15. しかしmysql 移行は罠だったらしい(ソースはTwitter

  16. このあたり chef とか ansible とか使ってうまく時間短縮できたかもなぁと思いました。ここで AMI を使うという案は頭の中にはあったんですが、当日マニュアル読んでちょっと怖くなったので、それはやめておきました。

  17. 以前までのISUCONは、軽く打ち合わせをして作戦を決め、1回だけ概念の確認・本番の動きを確認して終了、という形が多かったです。流石にそれでは練習不足で、本番になってコマンドをググったりすることが多かったです。今回も、本番中にググることはありましたが、どれも練習環境との違いに起因するもので、それ以外はほぼつまらずに設定できました。

  18. https://trap.jp/post/1628/

  19. https://nonylene.hatenablog.jp/entry/2022/07/24/184518

Xcode 7.0 beta 6が重い時の対処法まとめ

Xcodeを軽くするためにしたこと2つ。

環境

症状

  • Xcodeを起動した直後は軽いが、だんだんと重くなってくる(テキスト編集すら重い。範囲選択するのに1分待ったりするレベル)
  • よく見ると、画面上部に「indexing」と出ている。が、何をindexingしているかは不明
  • 参照するファイルを切り替えた後に特に重くなる。
  • アクティビティモニタを見ると、「Xcode」と「WindowServer」のCPU負荷が高い
  • Buildの速度は普通。

indexingを切る

最初に試した方法。 ターミナルから

defaults write com.apple.dt.Xcode IDEIndexDisable 1

を実行。 確かにindexingがなくなって多少軽くなったが、参照するファイルを切り替えた後に特に重くなる症状は改善せず。
あと、Command + クリックとかで定義元に飛べなくなったり、
Syntax Errorのリアルタイム表示ができなくなったりといろいろ不便。
最終的に元に戻しました。(結果的に戻しても大丈夫だった)
元に戻すには

defaults write com.apple.dt.Xcode IDEIndexDisable 0

を実行する。

ログの削除

効果のあった方法。 ターミナルで

cd ~/Library/Developer/Xcode/iOS\ Device\ Logs
mkdir temp
mv iOS* ./temp

を実行。劇的に症状が改善した。
特に、色々なバージョンのXcodeを入れているとこの症状が出やすいらしい。(未検証)

参考文献

XcodeEmacs が重いと感じたら最初に試してみるコマンド」
http://blog.livedoor.jp/tek_nishi/archives/7738643.html

Xcodeが異常に重い時の対処法」
http://qiita.com/musclemikiya/items/4c643173c4183def81b8

はてなインターンに参加中です!

こんにちは、id:kakira96です。

はてなサマーインターン2015に参加しています。

ただいま、前半過程を無事修了したところで、後半過程に進めることになりました!

詳しくは後のエントリで...

わーい\(^o^)/

インターン中の食べ物たち
f:id:kakira96:20150819103435j:image
f:id:kakira96:20150819103454j:image
f:id:kakira96:20150819104129j:image
定食・カレー等
f:id:kakira96:20150819103640j:image
f:id:kakira96:20150819103534j:image
f:id:kakira96:20150819104059j:image