ISUCON10 予選

ISUCON10予選に参加しました。

  • ISUCON7: MSA
  • ISUCON8: 問題作成
  • ISUCON9: ソロ参加

で、今回もソロ参加になりました。 ソロで参加した理由はこんな感じです。

次男の年長の運動会で長男から5年通った幼稚園の最後の運動会を欠席するという選択肢はありえないので、もし予選を通過しても本線は辞退する予定です。

最終スコア

(追記) 残念ながら予選敗退しました。スコアが足りなかったのか再起動試験でfailしたのかは不明です (T_T)

まだ結果が出ていないのでわかりませんが18:30頃2000点を超えてからはほとんど伸ばせず 2635 で終了しました

たしか2000になったときは chairのindexからstockを外したタイミンだだったと思います。

以後、色々と検討したものに一人チームということもあり、思い切ったことはできず、終了しちゃった感じです。

あー面白かった。

やったことなど

前日までにやったことや当日やったことは、まんまgithubを晒します

github.com

あー、そうそう、nginxの設定や、mysqlの設定はシンボリックリンクにしていて、 ./sync.sh conf/ conf/ みたいな感じで配ってました。 コードは ./sync.sh home/isuumo/webapp/go/main.go isuumo/webapp/go/main.go あとは ./all.sh sh ./server-scripts/restart.sh を実行という感じで事前に用意していたスクリプトを使って 3手で更新してました

館山に惨敗

前回このブログを書いたのが、いざ館山というタイトルだった。

あれから一年と少し…

 

その間、館山に二度負けた。

一度ならず二度だ。。。

 

しかも直近2019/1/27に行われた館山若潮ラソンに至ってはマラソンを始めて4シーズン目にしてワースト記録となってしまった。

今年に関しては、過去最高にポイント練習が充実していたと思う。

サブスリーペースでのペース走や、キロ4分以下のインターバルを何度もやった。

 

しかし、ふたを開けてみたら、ハーフ手前で脚が終わった。こんな事は初めてだった。

なんなら15kmくらいまでは今回は行けるぞ!という気持ちすらあったのに突然終わった。

それからの地獄のような21キロは一生忘れられない気がする。300人くらいに抜かれただろうか?

あと残り10キロをなんとかキロ6分以内でしのぎたいという情けない目標を受け入れざる得なかった屈辱は忘れるわけにはいかない。

 

原因は自明だ。圧倒的走り込み不足である。

言い訳になるが、2017年から本格的にオープンウォータースイミングにはまった。ハマってしまった。

そのためマラソンシーズンが終わって一休みしたら、スイムの練習ばかりの生活をしてしまった。 それ自体は悪いことではないが、走らなくても良い言い訳にして肺は鍛えられていると言い聞かせて月間50km程度の自分を許していた。(もっと少なかったかもしれない)

その結果、いくら心拍が鍛えられても所謂30kmの壁を高く高く築き上げてしまっていたんだと思う。

しかし、やるべきことは明確だ。走ればいい。走り込めばいい。 今まで「月間走行距離を気にするなんて無駄だ」とバカにしていたような面もあったが、彼らを尊敬し自分もそこに足を踏み入れよう。

まずはやってみる。月間300kmを最重要KPIとして2ヶ月継続する予定だ。

そして、それに慣れたら1000mを全力で3分切れるように一発のスピードを上げていく。 1000m2分台で走れるようになっていたら、サブスリー本のメニューには対応できるはずだ。

というわけで、OWSシーズンが終わるまではランに関しては、月間300kmと1000m2分台を目標にする。

とりあえず、これから2ヶ月のスケジュールはこれだ。吐きそうだ・・・

曜日 通勤(行) 通勤(帰) After memo
6km 3km 3km Swim +3000m runは全てjog 帰宅3kmはSwim優先で歩可
6km 3km 13km - Long帰宅ランSlow
6km 3km 3km (Swim +3000m) 朝は可能ならTTする Swimは疲労と相談
6km 3km 13km - Long帰宅ランSlow
6km 3km 3km Swim +3000m runは全てjog 帰宅3kmはSwim優先で歩可
10km - - - 朝スピード練習
+20km - - - 朝2時間走(ラスト2kmはハイペース)

週110km (達成率85% = 93.5km)

93.5 * 4 = 374km

いざ館山!

昨年二度とタイム狙いでは出ないと誓った館山若潮マラソンがいよいよ明日。

 

今年も出ます。もちろん今シーズン唯一のガチガチの本命レースとして。

 

仕上がりはまあまあ、去年より体重はやや重いけど去年よりスピードには慣れた。

 

シューズは、adizero takumi sen 去年のrenから一個上げた。

ソックスは、変わらずtabioのレース用五本指

ウェアは、上下adizeroのタンクトップとランパンで揃えるつもりだけど、寒かったら変える

そして、ザムストのゲイターとアームスリーブ

 

軽量化!

 

携帯食は

スポーツようかん×2

magon×3

メダリストのアミノ×4

これらをFlipBeltに入れて腰の安定を兼ねて装着

 

作戦は4:10イーブン

これまでは突っ込んで粘って来たけど、今回はイーブンでいく

 

補給プラン

※ 各給水手前で補給食取ってから水を飲む

6km アミノ

11km マグオン

15km アミノ

21km スポーツようかん

27km アミノ

32km マグオン

37km アミノ or マグオン 

40km スポーツようかん or 余ってるやつ

 

ハーフ 1:28:00くらいで通過 

30km 2:05:00 くらい

ここまでイーブンでいけたら

30kmからの激坂を根性で4:45 くらいで乗り切って押し切る

 

以上、イメトレ完。

 

 

 

 

 

schemalexの神機能

この記事はOSS紹介 Advent Calendar 2017 の 5日目の記事です。

schemalexとは

schemalex/schemalex

Generate the difference of two mysql schema

と書いてある通り、2つのMySQLスキーマの差分(ALTER)を表示するプロダクトで、@soh335が中心となって開発をしており、 僕も業務でも使っているのでたまにpatchを送っています。

perlだとSQL::Translator::Diffにあたり、 このschemalexはMySQLにしか対応していないのですが、Go製のプロダクトのためバイナリが提供されているため、コマンドラインツールとして簡単に使えるところがSQL::Translator::Diffより使いやすいと思って気に入っています。

紹介したいこと

@lestrratによる#34 のPullRequestが個人的にライフチェンジングだったので是非紹介させてください。

この機能でできるようになったことはスキーマの比較方法の拡張です。

これまでは以下の用にbefore/afterのsqlを用意して比較していました。

$ schemalex /path/to/before.sql /path/to/after.sql

このPRで以下の3パターンの入力に対応されました。

1. mysqlデータソース

$ schemalex /path/to/file mysql://user:password@tcp(host:port)/dbname

2. gitのコミットハッシュ

$ schemalex local-git:///path/to/repo?file=foo.sql&commitish=deadbeaf /path/to/file

3. 標準入力

.... | schemalex - /path/to/file

何が嬉しいの

例えば、普段業務においてDBのmigrationでgitのコミットハッシュと比較するgit-schemalexGitDDLを使っているのですが、 残念ながらうっかり直接ALTERをしてしまったり、ALTERの途中でFK制約に引っかかったりしてしまい、あるべき状態になんとか戻したくなったりすることがあります。 また、gitlogの任意のバージョンに戻したい場合もあります。

そういった時に下記の用にコマンド一発でalter分を出力できるのです。

schemalex mysql://user:password@tcp(host:port)/dbname /path/to/file > revert.sql

最後に

あんまり必要性にピンと来ないかもしれませんが、手元の環境がーーー!テストデータの入れ直しはしたくなーーーーい!となったときに、助けてくれるツールだと思いますので、 ご活用いただけますと幸いです。

マコピー書いたよ!

ISUCON7で優勝しました

まずは、素晴らしい問題と素晴らしい会場、素晴らしいインフラを提供してくれた運営に関わる皆様、本当にありがとうございました。
また、腰の重い僕を引っ張ってくれた会社の同僚の皆さんありがとう。

ISUCON7に同僚のmizkeisuzukiとMSAで参加して優勝してきました。

勝因はこれです。


というのは冗談ですが、初参加のため過去の大会のことはわかりませんが、今回の問題は僕たちのチーム編成にとってとにかく相性が良かったというのが大きかったです。
チーム編成や基本的な作戦については下記の予選のブログに書いていますが、今回の問題はインフラはほとんど関係なく、膨大かつ複雑なアプリをどうするかみたいな感じで、手数を打てる僕らに有利だったと思います。

 

ken39arg.hatenablog.com

問題概要

決勝の問題はクッキークリッカーのソーシャル版で複数のユーザーでルームを共有できるというもの。
ポイントは以下

  • 扱う数字が64bitintの桁数を遥かに超える巨大な正数を扱うこと
  • サーバーは4台構成
  • 通信の殆どがWebSocketでルーム毎にサーバーを固定することが可能
  • 更新系アクションaddIsuとbuyItemの成功数がスコアに直結する
  • 参照系getStatusが重く1秒以内に結果を返せないとwsクライアントは切断する
  • websocket以外がアクセスするサーバーは予選同様チェックボックスで選べる

より詳しいことは本戦の問題が公開されたら見てください

事前準備

予選での反省を生かして本線ではモニタリングにmackerelを入れるだとか、静的型付け言語であるGoでも検知できないような文字列のタイポをしづらくするだとか、Redisを迷いなく使うための準備だとか、そういうのをするつもりでしたが、予選後に突然仕事が忙しくなってしまい何一つ準備することはできませんでした。

結局予選と同じchefを準備する程度のことはsuzukiがやってくれたようですが、予選とは異なり事前に集まったり、issueにメモしたりだとかは一切できませんでした。

あと、ノートとかホワイトボードを用意しようと思っていましたが、それすらも忘れてしまい、かろうじてsuzukiのカバンに入っていた病院の明細の裏が僕達のホワイトボードの代わりでした。

結果論ですが、そうしてノープランで挑んだことが、いつもどおりやるという結果につながり、そのいつもどおりがこの結果に繋がったと思っています。

やったこと

mizkei が既に書いているし、suzukiも書くだろうけど、何をやったのかをいろんな視点で見るのは興味深いと思うので僕も書いておきます。

ドキュメントをよむ
  • redisのincrby使うと良さそうだ!
  • 1ルーム1サーバーにしてスタンドアロンで完結できそうだ!
  • addIsuとbuyItemがスコアになる!
サーバーログイン〜環境準備

やること

  • まずサーバーに入って準備
  • mizkeiはコードリーディング

ログ

  • 自分のPCの.ssh/configを設定し `ssh isu{1..4}` でログインできるようにした
  • 10:30 用意したchefなどをgit pull (suzuki)
  • 10:30 webapp/go db以下をgit push (suzuki)
  • 10:42 isu1〜4の/etc/{nginx,mysql} を集めてgit push それぞれシンボリックリンクにする(ken39arg) → 一応shellコマンド
初期実行

やること

  • alpなltsvとslowlogを出し、golangでアプリを動かし最初のスコアを見る

ログ

  • 11:00 nginxのログフォーマットをltsvに変更(ken39arg)
  • 11:05 MySQLのスローログ設定(mizkei)
  • 11:08 初期設定のままisu1,isu2,isu3に向けてベンチ実行 Score:7211

感想

  • slowlog特になさそう
  • websocketのせいででaccesslog意味ねーみたいな感じでさらっと流す。
  • suzuki曰くdbがボトルネック

アプリ修正 その1

戦略

  • Redisのincrbyとか使え無さそうという初見であるが一応Redisを入れておこう
  • キャッシュ戦略を取りやすくするため1ルーム1サーバーにしよう
  • roomnameからの逆引きは、普段DBやredisをシャーディングする時の用にincrementな採番をして永続化できるようにroomnameをuniqにしてAUTO_INCREMENTなidを持つテーブルで行く
  • とりあえず明らかに無駄なクエリを削ろう

ログ

  • 11:40 deploy するためのmakefile作成(suzuki) ※ミスがあり12:35にfix
  • 12:02 getCurrentTimeはdb見ずに`time.Now().UnixNano() / time.Millisecond`に (ken39arg) Score:5103
  • 12:30 mitemは初期化時にmapにキャッシュ(ken39arg) Score:10401 ※ ただしこのスコアに再現性はなかった
  • 13:07 ルーム:サーバーの1:1対応 (mizkei) Score:9784 ※ Scoreは変化無いが後の戦略のためmerge
アプリ修正 その2

戦略

  • additem buyitem getscore で呼ばれるupdateroomtimeはオンメモリ管理に変更しforupdateのlockを削る
  • addIsuの確定スコアをdbに保存し過去分のスコア計算を削る
  • gzipとか基本的なnginxの設定見直しをしておこう

ログ

  • 13:25 nginxの設定変更 (suzuki) ※ スコア落ち不採用
  • 13:40 addIsuの確定スコアをDBで管理するのは難しいので諦めることにする(ken39arg)
  • 13:55 updateroomtimeのオンメモリ化 (mizkei) Score:4836 ※スコアが減ったのでmerge見送り

アプリ修正 その3

戦略

  • その2は全滅だったので冷静にpprofを取ろう
  • オンメモリ前提でキャッシュしDBはメモリ復元に使うことにする

ログ

  • 14:17 pprof (mizkei)
    → big.Int 周りをなんとかすべしな感じ
  • 14:36 ルーム毎の共有メモリと管理方法を確定(ken39arg)
  • 14:42 GetPower GetPriceをcount毎にcache(mizkei) Score:8654 ※スコアが減ったのでmerge見送り
  • 15:05 addingsをキャッシュし`INSERT ON DUPLICATE`,`SELECT FOR UPDATE`,`UPDATE`の3クエリをINSERT or UPDATE 1回で済むようにした (ken39arg) Score:7746 ※スコアが減ったのでmerge見送り
  • 15:29 nginx.conf のgzipstaticなどを間違いないのを修正(ken39arg) Score:9259
アプリ修正 その4

戦略

  • その3やその2で入れたキャッシュ関連の修正はどう考えても効かないわけが無いのに、なぜスコアが全く伸びないのかということに思い悩む
  • mizkeiがレギュレーションを読み直し、そもそもgetScoreを1秒間隔で返せなくなるとベンチが上がっていかないという記述に気づく。
  • これまでの変更は効果を発揮する前に足切りにあっていた可能性が高いということで、ダメ元でお互いのレビューでOKなものはmergeしつつ、getStatusを最適化していこうという話をする。
  • インフラ担当のsuzukiは暇させてしまっていたのでhttp2試しますみたいなことで、よろしくみたいなノリ

ログ

  • 15:47 14:42に見送ったGetPower GetPriceのキャッシュ化PRをmerge(mizkei) Score:7012
  • 15:57 13:55に見送ったupdateroomtimeのオンメモリ化PRをmerge(mizkei) Score:7921
  • 16:07 15:05に見送ったaddingsのキャッシュPRに確定addingsを纏めて総量を減らす変更を加えてmerge (ken39arg) Score:6404
  • 16:27 buyingsもオンメモリ化(ken39arg) Score: 8744
  • 16:31 getStatusでDBへの参照がきえたのでtxなどDBを触っているところをすべてなくす(ken39arg) Score:5773
  • 16:36 1000回loop内の`totalMilliIsu.Cmp`で使っている`new(big.Int).Mul(itemPrice[itemID], big.NewInt(1000))` をloopの外にだしloop内で初期化させないようにする(mizkei) Score:48745
アプリ修正 その5

戦略

  • isu1〜3のCPUが圧倒的に支配的になりDB担当のisu4がスカスカになったので、isu4にもwebsocketを向ければ多分特別賞超えられるからやろう
  • 再起動時にキャッシュを復元するのを据え置いていたが、50000を超えたらとりあえず復元に取り掛かろう
  • getScoreまだイケるところ無いか探ろう

ログ

  • 16:45 isu4にもwebsocketを2:2:2:1で向ける(ken39arg) Score:57103

  • 17:00 再起動時にキャッシュを復元 (ken39arg) Score:61750
  • 17:30 big.NewInt(1000)を、グローバルにもつ (mizkei) Score:63404
再起動試験そしてチャレンジ

戦略

  • とりあえず再起動試験をしてScoreを確実にしていこう
  • 他のチームも壁を作ってくる事を想定し優勝スコアは15万くらいと予測、その結果まだあげる必要があるだろう。
  • 予選では「チャレンジしない」と言っていたが決勝は「チャレンジしよう」ということで、最後の最後まで粘ることにする。

ログ

  • 17:45 logとpprofをけす(ken39arg) Score:62871
  • 17:50 最高スコア(たまたま) Score:65218
  • 18:00 getStatusにおいて結果をキャッシュし、最後の取得時間とcurrentTimeと比較し同じならキャッシュを返す(ken39arg) Score:49963 ※不採用
  • 18:18 最終スコア Score:64847
もっとこうしたかった

Schaduleという名前にあるように、addItem,buyItemのタイミングでreqTimeから1秒分のスケジュールを更新するという戦略をゴールにしていたら、getStatusのタイミングでは参照だけで済むようになり、1000回ループの回数を更新アクションの回数と一致させることができ、最低限に抑えることができたはずだと思う。

そこで2回めのブレイクスルーになるのだが、次第にaddItem,buyItemの処理に時間がかかるようになり、そこの改善という一歩先に勧めたと思う。

おそらくそこまで行ったら、今度はbuyItemをaddItem同様にitem毎にmergeするとcalcの計算がまた早くなりじわりとスコアが上がる。

最後はaddItem,buyItemがかなり短い周期で来るようになるのでbuyItem,addItem直後のスケジュール作成を止め、スケジュール更新キューみたいなものにぶち込んでいってその更新キューの間引き調整で最後はねるみたいなストーリーが待っていたと思う。

あくまでも勘であるが、、、

こうやって勝っても悔しさが残って後を引きづられる感じ、ISUCONって初めて参加したけどとっても素晴らしいものだったんですね!!

感想

途中までPRの効果を確認できなくて、マージできてなかったんだけど、アプリ担当の自分とmizkei の関係性から、お互いレビューしあって問題なければ結果が出なくてもマージしていくという決断をしたのは大きかった。

この辺は普段の業務でも同じチームでお互いレビューしあっているということの強みが本当に出た。

あと、予選は1人のミスをみんなで解決するみたいなロスがあったけど、ダメな時はレビューに丸投げして、また別のことに取り組むみたいないい意味の丸投げ体制が取れたのは良かった。

基本的に1回でいい処理は一回しかしないという普段から気をつけていることを黙々とこなした結果ブレイクスルーを踏めたから勝てた。

まあ、正直踏んだ修正が僕じゃ無くてmizkei だったのは悔しいけど、さっさとgamestatusの1000回ループを改善して、個別修正の効果を実感できるような流れだったらもっと楽しかった。

予選もそうだけど、基本的に普段やらないことはやらないで、やってることをガンガンやり、お互い信頼するというのができたのが良かった。

今回のようにpprof以外にすぐできる有効なボトルネック特定手段が無いようなときは、コードリーディングで確信は無いけどほぼ間違いなく効果があるであろうことにアタリを付けて、それを改善するということは業務でもよくある。特に小一時間で終わるような小さな修正に対して、いちいち絶対に効くか確認をするなんてことは大抵しない。影響が無いように小さな単位でPRしmergeしていくことでローリスクな手をたくさん打てる。

僕たちは普段からそういう感じでやっていることが多いので、ハイリスクなcalcStatusのアルゴリズム変更のようなトライをせずに、コツコツと積み重ねて結果を残せたのは今後の自信にもつながって誇らしく思う。

 

さて、これで私の所属するKAYACに4個目のトロフィーが届いたわけであります。

強さの秘密がどの辺にあるのかわかりませんが、受託サービス(主にキャンペーン)とゲーム、チャットサービス、その他自社サービスと多岐に渡るwebサービスを身近に感じられることや、3度優勝している人が身近にいるとか、まだまだ富豪的アプローチでじゃんじゃんお金で解決しますというわけにはいかないこととか、なんだかワチャワチャしているところが強さの要因かもしれません。

 

最後になりますが、取り急ぎ gistに最終的なコードを張っておきますね。

ISUCON7 予選1日目を1位で通過しました。


大会運営者の皆様ありがとうございました。 本戦もよろしくお願いいたします。

まとめ

決勝に行くことはできたけど、打倒組長は達成できず...

  • 勝因: /icons/*/fetch をなんとかできたこと
  • 敗因: nginxを2台にしていたこととswap対策できなかったこと

参加経緯

ISUCONの存在は同僚の組長が無双していたこともあり最初から当然知っていて、 自分も出たら結構いいところまでいけそうだなあみたいな気持ちはあったのだが、 惨敗したときの恐怖が勝って、あれこれ言い訳をして出てこなかった。

今年も、本番当日がつくばマラソンかぶっているので「参加できないわー残念!!」と言いながら心のなかでホッとしていたけど、 うっかりつくばマラソンのエントリーをし忘れてしまい、本番当日が空いてしまったということで言い訳ができなくなってしまった。。。

そんななかここ2年くらい業務で一緒にやっているGoの実装がクソ早い @mizukei が新卒の@jet_zousanと残り1名のメンバーを探しているという情報をつかんだので、それに食いついたというのが参加した経緯。

結果的にかなりいいメンバー構成でチームが組めてラッキーだった。

チーム編成

  • @jet_zousan 弊社インフラの期待の新人 あの組長の弟子
    • インフラを一任
    • 最初は環境構築を担当する
  • @mizkei11 Goを愛しGoに愛された男
    • アプリ担当(主にGoの言語依存の問題を潰す)
    • 最初はコードリーディングを担当する
  • @ken39arg 10年戦士
    • アプリ担当(主にDBの使い方の問題を潰す)
    • 最初はslowlogの解析とIndexチューニングを担当する

とにかく自分と @mizkei11 はコードを書くのが早いというのが強み

インフラ面について@jet_zousanの知識は申し分ないけど業務経験が少ないのが不安要素 (経験的に俺がインフラ補えれば良いのですが最近さっぱりで…)

そういうチームなんで、とにかく当たり前の事を当たり前に積み上げて、手数でぶん殴ろうというのが唯一の作戦。

事前準備

  • チーム組んだ瞬間に Slackとgithubのprivate repoを作った
  • 1週間前に集まって、決勝に絶対に行くこと、打倒組長を誓いあった
  • issueにsnipetsとTODOを各自書き込んでおいた
  • infra担当の @jet_zousan がなんかchefで準備してた(よくわからん)
  • 自分たちのいつものフィールドで戦うことを決めておいた(nginx,golang,mysql,redis)
  • apache→nginxやpostgresqlmysqlの移行ブログなどのリンクをブクマ

当日競技前

開始が遅れたので、作戦とマニュアルの確認をクドいほど行った。

  1. ホワイトボードに「おちつく」とでかく書いた
  2. ホワイトボードに「チャレンジしない」とでかく書いた
  3. 事前に決めたチェックポイントでタイマーのアラートを設定した。内容は記憶が曖昧だがこんな感じ
    • 30分 達成指標
      • いじるファイルのgit管理
      • alp用nginx-logの設定
      • slowlogの設定
      • アプリをgoに切り替える
      • 最初のベンチが終了
      • pt-query-digestとalpでボトルネックを立て作戦を立て直す
    • 2時間 達成指標
      • 自分たちの当たり前を終わらせる
        • Index
        • N+1を解消
        • 言語依存の基本的な改善
    • 7時間 達成指標
      • 基本これより先はいじらない
      • 再起動テストなどを行う

競技開始

13:13 ~ 14:15頃

  • まず全員で当日マニュアルを読み込んだ。
  • とりあえず1人1台サーバーに入り構成を確認
  • nginxの設定を手で書き換えてalpで集計できるようにlogformatを変更
  • mysqlはクライアントでログインしset globalでslowlogを出力するように変更
  • systemdでアプリをgoに切り替える
  • 1回目ベンチ
  • githubにgoのコードをコミット
  • alp, pt-query-digestを実行
  • pprofを仕込む
  • buildを1台でできるようにする

ここまでで当初の想定より30分ほど送れていたけど、「おちつこう」と声を掛け合って冷静になれていた

ここで、/icons/をどうにかしないとslowlogすらまともに見れないという事になり、一度立ち上がって作戦会議

(ちなみにこの後最後までpt-query-digest は見れなかった...)

たてた作戦

下記をそれぞれサクッとやってしまおうということになる

  • @mizkei11
    • 画像を静的ファイルに保存する
    • 初期画像を取り出す
  • @jet_zousan
    • DBサーバーでアプリを動かし各appサーバーからPOST /profileGET /icons をDBサーバーに回し画像サーバーを1台にする
  • @ken39arg
    • slowlogがまともに見れないのでコードリーディングをして自明なIndexを張る

14:15頃〜19:30

僕に割り振ったMySQLにIndexは、必要なのが少なくてすぐに貼り終えてしまった(messageとimageのみ)

暇になったのでやることリストを確認しながら静的ファイルをgzにしgzip_staicで配信するなどをやった。

そうこうするうちに、15:30くらいに画像の静的ファイル化が完了してスコアが上がりだしたと思う。

ぼくは簡単に出来そうな最適化が見当たらないので/fetch の修正に取り掛かることにした。

この時たしか16時前で17時までにキメるぜ!と宣言して16:30くらいに書き終えた。

ただそこから、くだらないタイポとかでなんやかんやと時間が過ぎて結局投入したのが17時過ぎになってしまった。(今回僕に限らず3人とも普段しないようなくだらないミスが目立った。パスを間違えたり、タイポしたり、、、)

ここでスコアが一段階跳ねたところで、インフラ担当の@jet_zousanが、cacheヘッダーを入れたら、スコアが爆上げして、超盛り上がった。

この結果、DBサーバーが完全なるボトルネックになって、isu1と2でtry_file&proxyでプロキシしあう構成(通称クロス)に移行するが、またしてもくだらない設定ミスとかでなかなかすんなりいかない時間を過ごしてしまい実投入は少し先になった。

nginxの設定に手間取っている間に jsonyfy みたいな名前でに隠された /messages/history のループクエリの解消が@mizkei11 により投入されて確かトップにたったと思う。

そしてクロス構成が決まったところで46マンまで伸びて2位以下とダブルスコアがついてきたので、予選突破の安全策を取りに行くことにした。

そう、僕たちの作戦は「チャレンジしない」

19:30

ここまで手をつけていなかったmysqlのチューニングに取り掛かろうととりあえずinnodb_buffer-pool-sizeの調整をしたところ、スコアが半分くらいになってしまった。

さらにベンチを回すとさらに半分くらいに。。。

ここで設定を戻したりしたが、一向によくならない。

何をしたのか振り返るが、よりにもよってmysqlの設定に関してのみコミットしておらずdiffが不明。

絶対にinnodb-buffer-pool-sizeしかいじってないとのことだが@jet_zousanを信じきれずDBサーバーばかりをガン見するという状態がしばらく続いたところで、ようやくアプリがswapしていることに気づいた。

画像ファイルの名前を画像ののsha1で生成していたのだが、readallで画像を一度に読み込んでいたのだ。

よく考えてみると、今までベンチを回す時は必ずコード修正後でアプリをビルドし直していたからメモリが解放されていたのだが、DBのチューニングの時はDBしか再起動しなかったため、メモリを食いつぶしたままのアプリでベンチがかかっていたため性能が著しく劣化してしまったと予想。

ようやくそこに気づいたので、アプリを再起動すれば少なくとも30万はスコアが出るということが確認できたので、再起動後はちゃんとスコアが出るだろうと判断し、対策しないことにした。

20時の時点で30万まで行っていたのはチームは他にいなかったので3位以内には入れるという判断だった。

そういうわけで、余計なことはやめておこうと、ログもそのまま、欲を出さずに20:30には競技をやめて反省モードに入った。

結果として、この判断は正しく、ベストスコアとの隔たりは大きかったものの1日目1位をキープしたまま決勝の切符を手に入れることができた。

めでたしめでたし。

感想

判断は正しかった。ただ、本当にいつも通りできていたらあと2手くらいは打てたし、冷静になっていたら最後チャレンジではなく当たり前の判断でswapの解消ができたと思う。

いや、そもそもモニタリングしていたらもっとはるかに早くswapに気づけたはず、、、

決勝は同じミスをしないように、そして決勝はチャレンジします。勝つだけなので

10月のトレーニング計画

1/28の館山若潮マラソンに出ることにしました。

そこでサブスリー達成します!

 

さて、そのための練習ですが4カ月前の10月はポイント練は週一くらいにして、無理せずしっかりと距離を踏んでいこうと思います。

ここ1カ月はダラダラ過ごしましたが、それでも心拍はスイムで鍛えてたので4ヶ月前としては問題ないはずです。

 

10月の基本メニュー

 

月 : スイム (ジムのマスターズクラス) 3km弱

火 : ラン (帰宅コース) 15km

水 : ヨガ&バイク(片道15km×2)

木 : ラン (帰宅コース) 15km

金 : スイム (ジムのマスターズクラス) 3km弱

土 : ラン 20km 又は 3時間走

日 : off (土曜日と入れ替わりあり)

 

平日のランは基本スピードを気にせず気分で走る。

速く走りたい気分なら速く走るしのんびりでもOK

 

ポイント練は週末朝で距離を踏む系の練習LSDな感じで、11月にスピード練習できる下地を作る。

ただ、もしスピード練習する気分になったらその時はやる。

とにかく気分を優先する。

 

あまり月間距離は気にしないことにしているけど、計算上は200kmくらい走るはず。

量より質派だけど、怪我しないようにここで下地をしっかり作るのが10月のノルマ。

 

11月から1月前半ははインターバルとペース走のポイント練二本立てに切り替える予定。

 

達成できると良いけど明日は早速雨予報??