Opt Technologies Magazine

オプトテクノロジーズ 公式Webマガジン

第3回 社内ISUCONを開催しました

f:id:opttechnologies2015:20191025162714p:plain

こんにちは、 オプトテクノロジーズ シニアエンジニアの @sisisin です。
先日、「第 3 回 社内 ISUCON」が開催されました。
今回は参加者としてどのようなチューニングを実施したのかを書いてみようと思います。

社内 ISUCON について

オプトテクノロジーズでは 4 半期に 1 度、1 営業日丸ごと利用して社内ハッカソンを開催しています。
9 月 2 日にその社内ハッカソンの時間を利用して社内 ISUCON が開催されました。

ISUCON とは、「いい感じにスピードアップコンテスト」の略で、毎年 LINE さん主催で開催されているパフォーマンスチューニングに関するプログラミングコンテストです。
最近は参加者も増えていたり、社内 ISUCON を開催している企業さんも多く、耳にしたことがある人は少なくないと思います。

そんな ISUCON ですが、オプトテクノロジーズでも社内 ISUCON を 2017 年より毎年実施しており、2019 年も開催の運びとなりました。
企画・運営してくれたメンバーには感謝しきりです。

さて今回の社内 ISUCON、実施したのは 9 月 2 日で、本家 ISUCON の直前に当たる時期でした。
社内からは何人か予選参加する人がいた(自分もそのうちの 1 人)ので、練習に丁度いいタイミングでしたね。
また、インターン生を迎えていたので一緒に参加してもらったり、グループ会社の方も参加したりしていたので、いつもより賑やかな参加者になっていたかなと思います。

そんな社内 ISUCON ですが、競技に参加した自分がどんなことをしたのかという点でレポートさせていただこうと思います。

過去の開催記事はこちら:

問題・レギュレーションについて

今年の問題は本家 ISUCON8 の予選問題でした。

参照実装: Perl, Ruby, Python, PHP, Node.js, Go
インフラ: GCP インスタンス: GCP Compute Engine シンガポールリージョン の 2 vCPU, mem 7.5GB, Cent OS 7 * 1 台
その他: GCP コンソールからのアクセスは禁止

本家との差分でいうと、メモリがだいぶ多く、インスタンス台数が 1 台で少なくなっていますね。

準備〜当日

チームについて

@kadokusei,@matzkoh,@sisisin(自分) の 3 人チームでした。
@kadokusei は普段インフラ屋さんで、@matzkoh と自分はフロントエンドエンジニアというアンバランスなチーム構成。
@kadokusei がインフラ周り、@matzkoh と自分がアプリ周りという自然な役割分担になりました。

(@kadokusei とは本家予選に一緒に参加する予定だったので、役割分担は本家予選と近い動きになるようにって考えたりもしました)

準備について

事前に以下のようなことをやりました。

  • Slack チャンネル作成・webhook を用意
  • リポジトリ用意
    • deploy 用の shell script 用意
    • mysql, postgresql, redis を立ち上げられる docker-compose.yml を用意
  • 役割分担決め(先述の通り)
    • 初動は @matzkoh が足回り整備をやるといった話もした
  • 言語の決定
    • フロントエンドエンジニア 2 名だけど試しに Go でやってみようと決まった
  • Tour of Go をやったり、goroutine の実装パターンを勉強したり
    • go prof 準備もやろうと思いましたが、時間がなかったり、パッケージ管理システムがあまりわからずハマって敗北したりも。。

ごく最低限という感じですが、これでも社内の他の人達よりは準備していたようでした。

当日について

当日のタイムテーブル
  • 10:00 - 10:30 頃 オリエンテーション
  • 10:30 頃 - 17:00 競技時間
  • 17:00 - 18:00 結果発表 & 実施したチューニングについて発表

競技時間は本家より短めですね。

競技中にやったことなど
午前

@matzkoh が打ち合わせ通り足回り・環境周りを整備

  • 用意していたリポジトリへコードの push
  • Go のローカルサーバ立ち上げ用 Makefile 作成
  • デプロイスクリプト作成
  • ローカル環境セットアップ

などを実施。
昼頃にはローカル環境立ち上げられるようになっており、かなり開発しやすい状態に。

@kadokusei はインフラ周りとログ解析のために alp 導入作業。

  • h2o の設定の調査
  • とりあえず遅いリクエストのログだけ出してくれたりした
    • 最初の調査はこれを元にあたりを付ける形に
  • nginx へ置き換え
    • 何故か静的ファイルがうまく解決できずハマったりして結局 nginx は断念
  • alp のセットアップ
    • h2o で alp を見れるようにするのにも苦労していた模様

@sisisin

  • ざっくり実装を読んだりした
    • Go わからなかったので読み慣れている Node.js で(Go でやってみるとは一体・・・
    • ここで「アッこれ ISUCON8 だ・・・」ってなる
  • API 一覧を出した
  • ローカルの mysql クライアントで本番 DB に接続できるようにした
  • ざっとインデックスとりあえず見てみて適当に reservations に張った
    • mysql -uisucon torb -e ALTER TABLE reservations ADD KEY event_id_and_sheet_id_user_id_idx (event_id, sheet_id, user_id)
    • /initialize で初期化されるというあるあるを最初数回やっていた
    • 適当にやったけど効果は余り出なかったっぽい
  • @kadokusei の出してくれたログやソースコード見てて目についた getEvent という単語が聞き覚えがある(ズルい)とかからヤバそうな N+1 になってるなーってなる
  • コードリーディング(getEvent
    • 予約テーブルが件数多いのに全件回してて地獄っぽいと読み取れた
    • sheets テーブルがマスタテーブルになっていると @matzkoh から指摘を受ける
    • 実装の詳細を読み解くのに時間を使った

f:id:opttechnologies2015:20191024165645j:plain
競技中のとあるチームの様子


午後

@matzkoh

  • 飯(大事)
  • getEvents も相当遅いっぽいので N+1 解消に取り組む
    • が、Go との戦いに敗北
  • @sisisin が /admin/api/reports/events/:id/sales CSV 出力を SELECT INTO OUTFILE にしようとしていたので、そのクエリ作成を実施

@kadokusei

  • 12:30 ごろクエリ一覧を眺めたり h2o と格闘したりしていた
    • 14:00 頃に alp が見れるようになる
  • MySQL の設定変更
  • スロークエリの調査
  • /admin/???/report/sales に不要そうな行ロックを見つけたので削除してみる
    • ほんとに消して大丈夫か?という疑問はあったけど、とりあえず試してみてベンチ落ちたら戻そうの精神で消してみた
    • → 7000 前後ぐらいになった
    • (講評見るに、恐らくスコアが低かったおかげで通ってた疑惑がある)
  • 競技終了前にやっておくことを整理したり実施したり
    • 再起動試験 − slow query log を止める − アクセスログを止める
    • (一応)メモリとかディスクとか確認

@sisisin

  • 飯(大事)
  • getEvent を変更
    • reservation を全部取ってきて回していたところをマスタの sheets のループで十分そうということに当たりをつけ、そのように変更
    • これでとりあえずスコアが 4000 超え
    • Go で nullable なカラムをどう struct に定義するのかとかそういうのが全然わからなくて辛かった
  • /admin/api/reports/events/:id/sales の CSV 出力改善
    • SELECT INTO OUTFILE にしてファイルを直接出すという手で行こうと決める
    • が、ファイル出力がうまく行かず試行錯誤
      • クエリを直す余裕がなさそうなので @matzkoh に手伝ってもらった
    • 結局最後まで 500 が出てしまう問題が解決できなかった
      • せっかく @matzkoh がクエリ作ってくれたのに通せなくて無念を背負う
      • Go でどうデバッグすれば良いのか全くわからなくてその辺、不慣れな言語つかうのはめっちょつらいという気持ちを得る

なお @kadokusei は結局ごはん抜きだった模様

結果発表

f:id:opttechnologies2015:20191024171406j:plain
結果発表の様子

自分のチームは最終スコア 7499 点で優勝でした!
ベンチの様子見てると getEvent を倒したあたりで頭抜けてたので割と安心はしていましたが、勝てて良かったです。

採点でベンチが fail して 0 点となったチームが複数ありましたが、@kadokusei の最後の後始末は尊かったですね。
おかげで安心して採点の様子を眺めていられました。

当日のリポジトリはこちら: https://github.com/opt-tech/isucon3_team_sisisin

他のチームの実施したチューニングや感想について
  • みんな一様に 「h2o 何もわからない」になっていたようで、普段使っていないツールをつかうことの難しさを実感してました
    • 業務では使い慣れてるのを使うのが如何に無難なことか・・・
    • 中には nginx.conf を触っていたら h2o じゃん!ってなったチームも
  • メモリが多かったので古き良き DB 全部オンメモリをやろうとしたところも
    • DB ボトルネックじゃなかったので、アプリ側改修がないとあまり効かなかった模様
  • getEventgetEvents を倒そうとしていたチームがいくつかあったけど、バグったり時間不足だったりで倒せなかったみたい
    • 短時間で実装って難しいですよね・・・
  • 業務で普段 Scala でコードを書いているが、参照実装がないので言語選定に苦労していたチームが多かったようです

後日談

アンケート結果を見ると今年も好評だったようです。
自分も楽しく参加できて、しかも本家の予習にまでなったので有意義な時間でした。

また、今年は引き続きチューニングしたいチーム向けに、ベンチとポータルがしばらく開放されていました。

それを利用して 2 位のチームが最終的に 1 万点超えたり、他のチームでもスコアを伸ばしたりしていたようです。

f:id:opttechnologies2015:20191025162830p:plain
後日のチューニング結果

終わってみて

自分はフロントエンドに軸足を置いているものの、最近の業務ではバックエンドタスクが多く、しかもパフォーマンスチューニングに追われている身なので、割と業務直結な試行錯誤・特訓になったなあという感想です。

本家予選も参加予定だったので、その練習としても良かったし、短時間で集中して実装する催しは好きなのでぜひ次回も参加したい気持ちです。

予選については個人ブログですが記事にしてるのでもしよかったらどうぞ。 http://sisisin.hateblo.jp/entry/2019/09/10/002012

というわけで社内 ISCUON の参加記事でした。
また来年もがんばるぞい!

宣伝

もしオプトテクノロジーズに興味をもっていただけましたらこちらより「カジュアル面談希望」とお声掛けいただければと思います。