かきあげせいろはラーメンがたべたい

技術プログラミングいろいろ記録メモ備忘にゃーん!

ISUCON13に参加しました!

去年に引き続き今年参加しました! 今回は初回申し込みで開始ちょうどの10:00時点ですでに参加上限に達したことでエントリー出来ませんでした。

絶対に参加したい気持ちと、前回は学びの宝庫だったこともあり応援したいイベントなので、個人スポンサーとして参加しました。(個人スポンサーはプランによっては参加権がついてくるのです)

また、今回は初期実装で自分が慣れているJavaが存在しないのでGoで参加することにしました。

去年の参加ブログ

自分の知識レベル

  • 普段はJavaでバックエンド。たまにVueでフロントエンドを書く仕事をしています。
  • Goは数年前に入門書をよんでちょっと動かしてみた程度。
  • インフラに触る機会はここ一年で一度なく、エンジニア人生でもデプロイのためにちょこっとEC2を触る程度です。
  • EC2などの簡単なAWSサービスはプライベートで環境をつくったりアプリを動かしてみたりしたことがあります。
  • 自動スケールするようなモダンなサービスもチュートリアル程度ならさわったことがあります。
  • 自分の業務/プロダクトでモダンなサービスを適切に導入できそうか。と言われると自信がないです。

事前準備

前回参加時はとにかく広範囲の知識・経験が足りていないことが強く印象にのこっていたので、ISUCON本を最初から読み直し、本に付属の課題であるprivate-isuで素振り(実際に問題のパフォーマンスチューニングをやってみること)を3週し、ISUNARABEという有志の方が作成してくれた過去のISUCON環境を簡単に構築できるサービスで、ISUCON12を1週しました。

これらの練習時に共通で必要になるであろう手順のメモを、自分自身のチートシートとし育てていきました。これは同じ手順でも、少し環境が変わるだけで

また、練習時に実施した内容も残さずメモしました。

当日やったこと

  • 10:00
  • 10:35
    • CloudFormationで環境構築
      • 10:40 EIPが足りない旨のエラーが出たので、素振りで使っていた別のCloudFormationのリソース達を全部削除
    • hostsファイルにpipe.u.isucon.devを記述
  • 10:43
    • アプリケーションの画面確認
    • EC2インスタンス3台にsshできること確認
    • 最初のベンチ→スコア3000ぐらい
      • 3台すべてでtopした→2台目にしか負荷がかかっていない&MySQLの負荷が高いので、2台目MySQLから手を付けることを決定
  • 10:52
    • alpインストール
      • log形式が変更されない事象発生
        • 画面は1番目のサーバーにアクセスしていた
          • hostsに書いたアドレスが1番目のアドレスだったため
  • 11:04
    • nginxのログローテートのシェル作成(準備していたのでコピペ)
  • 11:07
    • MySQLスロークエリログ有効化
    • バイナリログの設定に気付いたが、複数のことを一度にしたくないので一旦放置
    • pt-query-digestとquery-digesterもインストール
  • 11:15
    • MySQLのテーブル構成確認
  • 11:20
    • alpとquery-digesterの結果をみるためにベンチ
  • 11:22
    • IDEでGoを書くためにIntellijのプロジェクトを作る
  • 11:23
    • query-digesterの結果が長すぎる(長いSQLがある)のでcatで表示しきれない→tailの逆であるheadの存在をしらなかったのでググって知る
  • 11:28
    • query-digesterの1位livestream_tagsテーブルに対してindexを張る
      • ALTER TABLE livestream_tags ADD INDEX livestream_id_idx(livestream_id DESC);
        • あとでSQL側にLimitをつけてもっと高速化出来そうなのでDESCにした
          • ライブは最近のもののほうがアクセスされやすいと考えた
    • EXPLAINでindexを使うようになったことを確認
  • 11:35
    • ベンチ→スコア4390(改善によって+1300された)
    • topでMySQLの負荷が減ったが、まだアプリより高いことを確認
    • ベンチ走行中に2番目のクエリの改善を考え始める
  • 11:39
    • icon画像を静的ファイルにしたいが、時間がかかりそうなチューニングなので一旦index張るだけにする
      • ALTER TABLE icons ADD INDEX user_id_idx(user_id);
  • 11:41
    • ベンチ→5583(+1200)
  • 11:43
    • プリペアドステートメントを消す
    • やりかたを暗記していないのでISUCON本とその課題を素振りしたprivate-isuを参照する
    • Goでsqlx.Open("mysql", conf.FormatDSN())部分をsqlx.Open("mysql", conf.FormatDSN()+"?interpolateParams=true")に変更
    • 11:47 サーバー上でgit initだけする
      • git diffで差分が表示されないことに気付く
      • git init後にaddとcommitしていないことに気付く
    • 11:51 Goの変更を反映する方法を調べる
      • Makefileを見る
      • DockerFileをみる
      • これらを見てもよくわからないので全部ChatGPTに食べさせてどうすればGoの反映が出来るかを聞いた
        • make buildコマンドすればよいことがわかった
          • 実行ファイルっぽいやつのファイルサイズが変わったことで成功と判断
    • 11:54 マニュアルに記載されていたenvチェックをやっていないことに気付いたのでやった
    • 11:56 systemctl restartする
      • systemctl statusでサービスがloadedになり、activeにならない
        • Activeまで数秒かかるだけだったみたい
    • 12:00 ベンチ
      • initializeへのリクエストで502発生
    • initializeの処理を見に行く
    • ログを出力した行を特定したいのでsyslogを見る
      • 出力されておらず、systemctl statusでloadedに戻っていることに気付く
      • Goの起動時にこけたと考える
    • 12:10 sqlxのセットアップ時とかにこけたのかもと考え、プリペアドステートメントの設定指定方法を間違えたかと思いprivate-isuで同じことをしている部分を確認する
      • 接続文字列をログ出力する実装にする
    • 12:14 systemctl restartでactiveにならないことに気付く
    • 12:16 systemctl statusでactiveになったことに確認
      • 悩む
      • restartするまえにmake buildした時点でsystemctl restartに相当する処理が行われているように見える
        • 適当にGoを書き換えてmake buildしてみる
          • systemctl statusで再起動していないことを確認
      • loadedとactiveを繰り返していることに気付く
        • 起動した時間が数秒で、5秒程度で再起動を繰り返していることに気付く
      • 12:51 Goの変更ないようを戻してmake buildとsystemctl restartしてみる
        • systemctl statusでアプリが再起動していることを確認する
        • 実装が悪いことが判明
    • 12:52 再度Goにプリペアドステートメント無効の設定を入れる
      • ログは出すようにする
      • isucon:isucon@tcp(127.0.0.1:3306)/isuphipe?parseTime=true?interpolateParams=true
      • ?が二つついていることに気付く
      • &にしてmake buildしてsystemctl restart
      • systemctl statusで起動成功している
    • 12:56 ベンチ→6700(+1100)
  • 13:01
    • 指定したライブのスコア合計しているクエリが1位
    • ALTER TABLE livecomments ADD INDEX livestream_id_idx(livestream_id DESC);
    • ベンチ→6758(+58)
      • たいして変わっていないことに疑問を持つ
      • ベンチは上がらないが、query-digesterでは順位がさがったので一旦よしとする
  • 13:17
    • ユーザー指定でテーマ取得時のクエリが1位
    • ALTER TABLE themes ADD INDEX user_id_idx(user_id);
    • ベンチ→7884(+1126)
  • 13:25
    • /iconが重いが/initializeが1回呼出しで9秒もかかっていることが気になり、こちらを改善することにする
    • データ作成部分の大量のinsertが遅そうなのでバイナリログをOFF
    • ベンチ→8299
    • /initializeが1秒になる
  • 13:45
    • ユーザー指定でライブあたりのチップ合計するクエリが1位
    • ALTER TABLE livecomments ADD INDEX livestream_tip_idx (livestream_id, tip);
    • ベンチ→8282
    • query-digesterでも合計時間があんまり変わらず
    • show profileしてみるとexecuteが一番時間がかかっている。indexを外しても変化がない
    • ChatGPTに聞いてみたらIFNULL()よりCOALESCE()のほうが速いというのでやってみた
    • 効果が見られないのでINDEXをDROP、IFNULL()に戻す
  • 14:30
    • ベンチがwaitingになるので待ち
  • 14:40
    • ライブあたりのリアクション数のクエリが2位
    • whereを狙ったindexを作る
      • ALTER TABLE reactions ADD INDEX livestream_id_idx (livestream_id);
    • 効果が見られないのでINDEXをDROP
  • 14:49
    • SELECT content,ttl,prio,type,domain_id,disabled,name,auth FROM records WHERE disabled=0 and name='*.u.isucon.dev' and domain_id=2;が3位
    • disabledはカーディナリティ低過ぎで意味なさそうなので無視する
    • ALTER TABLE records ADD INDEX domain_id_idx (domain_id);
    • EXPLAINでdomain_id_idxが使われない
    • FORCE INDEXにしてみても単発のSQLではexec timeが変わらなかった
    • domain_idもカーディナリティが低いことが判明
    • domain_id_idxDROP
    • nameは色々あるみたいなのでnameにindex張る
    • ALTER TABLE records ADD INDEX name_idx (name);
    • ベンチ→変わらず
  • 15:07
    • 集計APIの/statisticsが重い
    • リアクション数とチップの合計をライブごとに集計する処理がN+1
    • 一発で全てJOINするように変更
    • ベンチ→変わらず
    • /statisticsが数回しか呼ばれていないことに気付く
    • query-digesterからは順位が下がった
  • 15:40
    • /iconで静的ファイル化しようとする
    • ISUCON本を参照
    • private-isuの実装をコピペ
    • nginx設定ファイル/etc/nginx/sites-available/default書き換え
      • /iconへのリクエストは静的ファイル用ディレクトリに向けtry_files $uri @app;で静的ファイルがない場合は普通のリクエストにするように
    • 16:22 ベンチ→整合性チェックで失敗。/livestream/reservationで500発生
      • ファイルアクセス時にpermission deniedしてる
      • chmod 777
    • 16:37 ベンチ→iconを更新するとicon_hashが新しくなってない
    • 16:45 ベンチ→アイコン未設定の場合はデフォルト画像のハッシュ値を返さなければならないエラー
    • 17:21 ベンチ→新たに設定したアイコンが反映されていないエラー
      • 画面であらたなアイコン画像を設定するも、デフォルトの画像になってしまう
    • 17:52 画面でアイコンを差し替えられるようになった
    • 17:54 ベンチ→7289
    • もういちどベンチ→アイコン未設定の場合はデフォルト画像のハッシュ値を返さなければならないエラー
      • 静的ファイルとして格納しているディレクトリに、前回ベンチの画像が残ることが原因と考え、削除しベンチすると通ることを確認
    • 17:57 init.shがベンチの最初に/initializeから叩かれることは分かっていたので、shの最後にrmコマンドを追記
      • 静的ファイルを削除
      • ベンチ→/initializeが500になる
  • 18:00
    • 競技終了

というわけで最終スコアはエラーが残っているため0点でした…

点数の遷移

ふりかえり

Keep

  • 画面をつかって小さく原因特定できた
  • セットアップ(環境構築・マニュアル読み・計測ツールインストール)は自分の最高速をだせた
  • ChatGPTを有効に使えている(Goの実装を聞く→ググって検証→やってみて確認)
  • わからない技術要素はバッサリ切り捨てた。PowerDNSなど
  • 設定ファイルの場所で迷わなかった
  • Lixuxの使い方がスムーズ(ctrl+r・Vim・ログ確認)
  • 動画を撮った(ふりかえりの密度が去年より充実)
    • 動画は画面キャプチャの方が画質的によかったかも
      • Macの負荷はどうなんだろうか
      • それはそれとしてスマホでも取っておくと、声が入るので良いか
  • NginxやMySQLの設定は素振り時と比較して問題なさそうであることを判断した
    • 結果的に良かったが、もうちょっとセオリーを知っておきたい
  • ベンチ走行中に次の改善に着手してしまうなど、保守的ではなく投機的な行動をとった
  • 常に自分の行動をしゃべりながら行動するのがとても良かった。何が問題になってるかを冷静に考えられる
  • 13:25時点でスコアが8299点であり、順位は80位ぐらいだったはず。これは自分ではかなり良いペース

Problem

  • 7000点到達以降、改善が効果を発揮しなくなった。ボトルネックを見定められていない?
  • 静的ファイル配信を実現するのに時間がかかった(2時間30分ぐらい使って結局実現できなかった)
  • icon_hashの仕様を破壊してしまい、直すのに手こずった
    • ファイルに無ければRDBをみて、その結果を元にhashを作るというifが2,3ネストする程度の複雑さでも頭がこんがらがる
      • 自分がGoに習熟していないことや、脳内メモリ量が少ないことが原因?
        • 割り切って全部ChatGPTに突っ込めば良かったかも
  • hostsの理解が怪しい
  • DNSはなにか仕込まれてそうとおもっているが、DNS自体の理解も、アプリケーションにおいてどのような役割なのかも怪しい
    • 理解度としては、Webサイトを公開する際にIPより便利にアクセスしてもらうために登録しなければならないもの。という程度
    • アプリケーションにおいての役割は、たぶん個別ページを作るためだと思うけど、それだけ?
  • ChatGPTでSQLのIFNULLよりCOALESCEのほうが速いというのを信じてしまった(これ自体は本当で、ボトルネック取り違えなのかも不明)
  • 競技なのに「勉強になれば良い」という意識がある。もっと闘争心を燃やしたいところ。
  • 静的ファイル配信でハマったときに、あきらめるかどうかの判断ができない(これを書いている今でも、押すべきか引くべきかどっちがよかったんだろうと思っている)
  • 動画で自分の声と顔(ターミナルを表示している画面への写り込み)を観るのがつらい
  • ベンチで出たエラーログの意味を理解していない
    • /reportで400が返ってきた時に調べずにスルーした(結果的に問題にはならなかったのでラッキー)
  • 静的ファイル化した画像を消さなかったことでベンチがこけたことに気付くのが遅かった(どうすれば早く気付ける?経験則かも)
  • ローカルでIDEでプロジェクトを作っておくべきだった
  • Makefileなんもわからん
  • go buildコマンドなんもわからん
  • クリップボードの履歴を検索する何かがあったほうが良かったかも(意外とIPを貼り付ける回数が多かったり)
  • INDEXが効かなかったとき、原因がわかっていない
    • recordsのnameに張ったときに、ベンチだけしか見ていなかった→query-digesterとEXPLAINは必須だったはず
  • 計測が甘い
    • query-digesterで上位のクエリを改善した結果、たまたまAPI自体も改善したときしかベンチに現れていない。これは1番のボトルネックを特定できていないのでは?
  • 最後にinit.shにrmコマンドを追記したと思っていたが、競技終了後に確認したら追記できていなかった。追記後ベンチを回したらfailにならなかった。なぜこんなことが…orz

去年から続投のProblem

  • インスタンスが3つあるのがなぜなのか理解していない
  • 一緒に参加する友達がいなかったorz

特筆するTry(実現可能とは言っていない)(本当はProblemを全部倒したい気持ち)

  • とにかく経験を積むことで突破できそうなProblemが多いので、素振り回数はいくらでも増やして良い。8時間でやる素振りと、時間にとらわれずじっくり向き合う素振りを両方増やしたい
  • 講評を良く読む。ISUCON12予選の講評には3台インスタンスの解説があるはずだが、読んでいないor忘れている。
  • 実践Nginx本は流し読みしただけなので、腰を据えてちゃんと読もう
  • MySQLの設定がどのような項目があるか/どう調整していくかが、学び方からわかっていないので調べるところからやる
  • Goの経験値がとにかく足りていない。未だにerrのifで目が滑る。作って/読んでを増やそう

動画を見ての気になりポイント

  • 肌がかゆそう(詰まったりすると頭を掻いていたりする)
  • 2倍速でも声が聞き取れる(意外とハキハキしゃべってる)

まとめ

去年よりわからないことが減り、改善サイクルを回す回数が大きく増えたことが嬉しいです。

自力のようなものが足りないのは目立ちますが、それでもようやくISUCONで戦うスタート地点に立てたような気がします。

とくに、去年は「改善そのものの技量」と「Linuxなどの環境を泳ぐ能力」の両方に脳みそリソースを大きく割いていましたが、今回は後者はほぼなくなりました。素振りを複数回やることでセオリーを知ったり、業務でIntellijVimプラグインを入れたりした成果がでたようで嬉しいです。

来年も絶対に参加し、今度こそ勝負に参加できるスコアを出したいです!!

泡沫の夢。最終0点なのがくやしく、未練がましく自身の最高点の画像を貼る

カウンセリングのすすめ

2023年3月ごろから鬱を発症し8月現在まで心療内科で治療を受けているのですが、治療の一環でカウンセリングをしてもらっており、これがとても良いと感じたのでおすすめする記事を書きました。

注意

おそらくカウンセリングというトピックは人によって千差万別な 良い/悪い が存在する分野だと思われます。この記事はカウンセリングの専門家が書いたものではなく、カウンセリングを受けた感想にすぎません。この記事を読んでいただいた方は自分に適用してもよい話なのか。ということに十分注意を払ってください。

なにが良いか

1. 自分が大切にしているものを整理できる

カウンセリングでは何をストレスに感じているかという会話は必ず発生するでしょう。

ストレスを感じる部分は自分にとって大切なものをないがしろにされている状況であることが多いため、この話を通じて仕事をする上でどんな価値観で臨んでいるかや、現実とのギャップをどのような時に強く感じるかなどを整理できます。

またストレスを感じている場面を整理することで、次に同じような状況になった時に「これ、カウンセリングでやったところだ!」というメタ視点を持てるようになり、自然とストレスをある程度コントロールできるようになってきました。

2. 自分が大切にしているものへの自覚を強化できる

カウンセリングでは何をストレスに感じているかの対称として、ストレス解消として休日にどんな過ごし方をしているかなどの会話も良く発生します。

プライベートで普段していることから、どのようなことに癒やしを感じているかなども整理できるため、それらを強化する行動をとれるようになったりします。 自分が趣味として言える自覚的なことの強化はもちろんですが、普段なにげなく行っていることを見つけて強化することもできたりします。 こういった「普段なにげなく」のような事柄は意識しないと見つけにくいですが、意識的に会話する。つまりカウンセリングというイベントによって表出されることができることがあるように感じます。

3. 仕事/プライベートに横断する話をできる

仕事の不満は仕事関係の人に相談しづらく、家族や友人の不満は当人に言いづらいことはよくあります。 自分はこれらを全て話せる人が回りに存在しませんでした😇

しかしカウンセリングはそこがメインフィールドですし、メンタルというおよそ全ての時間にかかわってくる問題領域を扱うため、話すことに抵抗感がありません。 愚痴を言うことですらカウンセリングの目的をある程度達成しているように思え、それが免罪符の役割をしてくれるため心が軽くなるように感じます。

4. やる気が出る

自分が大切にしているものへの意識が強化された結果、「もっとやってみよう」「似ている別の趣味を探してみようかな」という感情が湧いてきます。 普段は雑な運用している時間/やる気リソースを集中投入できるようになるため、充実感も得られます。

5. 冷静になる

言葉にすることで怒りなどのネガティブな感情がある程度解消され、一歩引いた視点でものごとを見れるようになります。 これは当然のことのようですが、自分はカウンセリングを定期的に受けることでさらに推進できるようになりました。「冷静になる」を十全にはできていなかったことに気付けただけでもかなり前進できたように思います。

6. ものごとの捉え方を考えるきっかけになる

カウンセリングを通じて認知行動療法の存在を知りました。 認知行動療法とはものすごく雑に言うと「嫌なこと発生時用虎の巻」。丁寧に言うと「嫌なことを一歩引いて計測し、現実的な対策を考えるときは手順書にそって考え計画せよの書」といった感じです。 自分は「マンガでやさしくわかる認知行動療法」という本で学びました。 ストレスに対する武器としてこの方法を保持している自覚が、ストレス耐性を引き上げてくれるようにも感じます。

7. 知らないことを知れる

上記で紹介した認知行動療法は業界では著名な方法らしいのですが、自分は名前さえ聞いたことがありませんでした。こういった「知らないということ自体を知る」というのはとても難しいです。自分が専門としていない領域ならなおさらですが、カウンセラーはその道のプロであり自分に合った方法を紹介してくれます。たとえば自分は読書が好きなのですが、読書療法というものも紹介してくれました。

8. プロと会話できる

カウンセラーの方は当然、カウンセリングのプロなので上記をうまいこと引き出す会話をしてくれます。自分は鬱の症状としてはおそらく軽微な方で、会話もままならない方や、パニックになっている方とも一体となって解決を目指す職業がカウンセラーです。そういったスキルを持った人と会話できる機会は価値があると感じます。

どんなことを話しているのか

具体的にどんな話ができるのかを列挙します。カウンセリングでは何でも話して良いのですが、これを見た方がカウンセリングを受けるハードルを下げる狙いです。

  • 自分の仕事はどんなことをしているか
  • 普段の一日の過ごし方
  • 自分の嫌いなところ(私は完璧主義などを話しました)
  • いままでの転職の理由
  • 周りの人や、環境への不満
  • ○○すればよかったと感じたこと(私は今週の仕事はこうすすめればよかったなどを話しました)
  • 仕事の嫌なこと
  • 仕事で楽しいと感じている時間
  • お菓子作りにハマっている話
  • おすすめのケーキ屋
  • 痩せたいけど運動は嫌だ
  • 宿題をだしてもらう(次回カウンセリングまでになにかしらの運動をする宿題をだしてもらうことで、だらける私に発破をかけるイベントにしてもらった)

カウンセリングは鬱の治療だけを目的としなくてよい

この記事を書こうと思った動機なのですが、自分は鬱としては軽微でしかもほぼカウンセリングを必要としないぐらいには良好な状態と言っていただきました。しかし私がメンタルの維持や1on1的な使い方としてカウンセリングをしたいならいつでもウェルカムとも言っていただき、現在までとても良い影響をうけています。 良い仕事のために運動で身体のメンテナンスをするように、良い人生のためにメンタルのメンテナンスとしてのカウンセリングがあっても良いと思います。

オンラインカウンセリングの存在(2024年3月30日追記)

うららか相談室 のようなオンラインでカウンセリングが出来るサービスの存在を知りました。 自分はまだ利用したことがないのですが、心療内科メンタルクリニックに行くという心理的な壁はそこそこ高いと思われるので、こういったサービスを活用するのも良いかもしれません。

さいごに

私はプログラマーなのですが、普段行っている問題解決をメンタル領域で実施することと似ていると感じています。あくまでもメンタルは自分の中にあるものなので、メンタルの問題解決はカウンセラーだけではなく自分も一緒になって解決していく必要があります。

プログラマーの世界には「推測するな、計測せよ」という言葉がありますが、メンタルも同様で、まず計測しボトルネックを見定め適切な対策をする必要があるように思えます。 計測する方法としてカウンセリングは業界のベストプラクティスではないでしょうか。

今すぐカウンセリングの予約をしましょう!

ISUCON12予選に参加しました!

これです。 isucon.net

毎年盛り上がっているのをTwitterで見つつも、自分はインフラが全然わからなかったのでいままで参加したことはありませんでした。 しかし一昨年ぐらいからインフラをちゃんと勉強していこうと決意していたことと、書籍「達人が教えるWebパフォーマンスチューニング」を読んだことでチャレンジしてみようという気持ちになったので思い切って参加してみました。

gihyo.jp

結果は惨敗でしたが、とても学びが多かったので久しぶりブログに記録します。

知識レベル

  • 普段はJavaでバックエンド、VueやAngularでフロントエンドを書く仕事をしています
  • インフラに触る機会はほぼありませんが、たまにデプロイのためにEC2をつかったノーマルな?インフラを触ることがあります

予選でやったこと

  • 開始と同時に展開されたマニュアルを読みました
  • 画面を一通り見ました
  • 初期状態でベンチマークを実行しました
  • 参考実装をJavaに切り替えました
  • この状態でベンチマークを実行しました
  • ソースコードをGit管理しました(ソースコードがどこにあるかを探すのに結構時間をつかいました。sysytemctlのserviceからたどればよかった…)
  • DBの接続情報をソースコードから探してDBアクセスし、テーブルなどを確認しました
  • mysql --help | grep "Default options" -A 1でDBの設定情報を探し、そこからログファイルの場所も探しました
  • ベンチマークを実行しつつtopをみて、DBのCPU使用率が支配的だったのでDBから着手することにしました
  • スロークエリログの設定をONにしました
  • pt-query-digestをインストールし、visit_historyテーブルに対してのクエリをチューニングすることにしました
  • SELECTで指定されているカラムを狙い複合INDEXを作成しましたcreate index player_id__created_at__idx3 on visit_history(tenant_id, competition_id, player_id, created_at);
  • 実行計画でINDEXが使われていることを確認し、再度ベンチマークを実行しました
  • 再度ベンチマークを実行しつつtopをみて、アプリの方がCPU使用率が高くなったので、alpをインストールしnginxのログフォーマットをalp用に変更しました
  • alpの結果からランキングを取得するエンドポイントが重い事がわかったので、処理内部にストップウォッチを仕込み、一番重そうな箇所を特定しました
  • プレイヤー情報取得部分がN+1になっていたので、処理前に一回のSQLで全取得するようにしました
  • 再度ベンチマークを実行し、スコアが上昇することを確認しました
  • スコアの上昇具合が他のチームと乖離しすぎていることに疑問を抱き始めました
  • 再度マニュアルを読み返したところ、initのエンドポイントがスコアにとてもかかわっていることを認識し、処理の内容を確認しました
  • SQLiteのファイルをのぞいたところ、何をやっているのかよくわからず、しかしファイルの名称からテナント関連の処理をしてそうということだけわかりました
  • SQLiteの改善をあきらめ再度topでDBが重くなっていることを確認し、replaceのクエリを改善することにしました
  • そもそも一意のIDを払い出せればよさそうだったため、JavaでUUIDを生成しSQLは実行しないようにしました
  • 再度ベンチマーク
  • 18:00になったので終了

振り返り

やったことを列挙しましたが、一つ一つのオペレーションに慣れておらず、時間がかかっていました。たとえばスロークエリログを有効にした場面ではログローテートをしたあとに書き込みがされなかったりして、その解決に時間をとられたりなど普段触っていないこと起因のような機動力の遅さをとても感じました。 上記が一番強く感じたことですが、それ以外にも

  • 全体を俯瞰する能力がなさすぎる(nginxのことをしばらく忘れてた)
  • ソースコードを見つけるのに時間がかかった(セオリーを知らない)
  • Gitを活用出来ていない(一人チームであった・ソースコード以外の設定ファイルはcpコマンドでバックアップとるだけだった)
  • Javaで実行時間を計る方法を、LocalTime.now()以外の見やすい方法を考えておくべきだった
  • アプリケーションの全体を詳細までつかめていない
    • 各エンドポイントが何をするのかわかっていない(そこから呼ばれているメソッドのシグネチャぐらいまでしか目を通していなかった)
  • インスタンスが3つあるのがなぜなのか理解していない
  • DBのスロークエリログと、アクセスログで一番上の事象を改善してもスコアにあまり反映されないことの理由に気付くのが遅い
    • 一番のボトルネックを解消しないと他のアクションの効果が薄いという旨の記述が書籍「達人が教えるWebパフォーマンスチューニング」にあったのに
  • 最後に再起動実験をしなかった(レギュレーションを読んでの、当日やることリストを作るべきだった)
  • MySQLやNGINXの設定のセオリーがわかっていない
    • 設定項目を見ても何についての設定なのか理解できない
  • 触ったことの無い技術要素であるSQLiteに忌避感が出てしまった
    • なにをやってるか理解できなかった
  • Gitを経由せず、サーバーのコードを直接書き換えた方が機動力があったかもしれない(VScodeでできたような…)
  • 自分はインフラ関連が未熟で、ソースコードを見ることしかできないのだから最初の時点で気合いを入れて全部のコードを見て分かりやすいようにリファクタリングするぐらいの強い気持ちを持てばよかった
  • 一緒に参加する友達がいなかったorz

総じて…

あまりにも広い範囲で能力が足りていませんでした。普段の仕事が整備されたものであることや、自分で作るアプリケーションは作りきりで終わりだったり複雑なインフラを必要としていないこと等、知識・経験両方が不足していることを強烈に感じています。 今回参加することでこれらの課題に気付けただけでも大きな収穫になったはず…

ネガティブなことが多いですが、曲がりなりにも計測し改善するというサイクルを予選中にできたことや、業務でほぼ経験のない高パフォーマンスのためのSQLチューニングを少し実践できたことなど、成功体験も積めました。

次回の開催の時までにもっと力をつけて来年も参加したいと思います!!

最高に楽しいカンファレンスbuilderscon tokyo 2019に参加してきました(自分用メモ&感想)

昨年初めてbuilderscon2018に参加した際、楽しく技術発表するお祭りといった珍しい雰囲気のカンファレンスだったので好きになり、光の速度でチケットを購入しました。 カミオカンデコンパイラライブコーディングの話は聞けなかったのですが、がすごく盛り上がっていたらしく、動画が後ほど公開されるのであればみたいです。

続きを読む