いつものチーム白金動物園( @mirakui, @sorah, @rosylilly )として7回目の参加をしました。自分の ISUCON との関わりを振り返ると以下のような感じです。
- 2012 ISUCON 2: kamipo, do_aki とともに出場。この頃はまだ小規模で、予選というのは無かったですね
- 2013 ISUCON 3: sorah, rosylilly とチーム白金動物園を組み、本選出場。 Fail で0点フィニッシュです…
- 2014 ISUCON 4: 白金動物園で出題側として参加。 二度とやるかと思うくらい大変だったけど、本当に良い思い出です
- 2015 ISUCON 5: 白金動物園として本選2位の成績を残す。 この年が今のところわれわれの最高成績ですね
- 2016 ISUCON 6: 白金動物園、初の予選敗退!! 大会のレベルが上がっているのを痛感
- 2017 ISUCON 7: 本選出場を果たす!! 本当によかった。が、本選が難しすぎて手も足も出ず、無になりました
- 2018 ISUCON 8: また予選敗退…。が、白金動物園として本選の事前テストに参加することができ、本選運営に貢献することができました
- 2019 ISUCON 9(今回): 本選出場!!
ISUCON は年々大会の規模が大きくなってきていて、若くて強い人達がどんどん参戦してくるので、もう本選に出るのはかなり難易度が高く、「多くの人にとって予選こそが ISUCON である」とさえ言われています。そんななか、僕の大好きなチームでまた本選に出られただけでも嬉しいし、出られたからには優勝を狙いにいきます。
予選でやったこと
参考実装としては Ruby を選びました。自分の担当はいつものようにプロファイリングがメインで、いつもは自前のスクリプトや alp を使って分析をしているのですが、今回はたまたま別件で間違って Annual Subscription を自腹契約してしまった New Relic の個人ライセンスがあったので、それを使いました。分析できることは自前のスクリプトでやってるときとだいたい同じなんだけど、僕だけじゃなくてメンバーがベンチ結果分析に参加したり、同じ数字を見て語れるところが便利でした。教科書で見た DevOps ってやつですねこれは。
最初は外部 API へのリクエストがネックだったので、Redis でキャッシュを入れるなどして API リクエストを減らしたり、 Expeditor で並列にしたりしていきました。そのあとは DB のネックに移ったので N+1 を潰したり、更新のない categories をハードコードにしたり、 users テーブルから統計情報を分離したりしました。しかし、スループットが上がるにつれ DB トランザクションのロックがネックになり、10,000 イスコイン あたりからさっぱり点が上がらなくなりました。
いつだってこういう状況を打ち破るヒントはレギュレーションの中にある事をわれわれは学習しているので、読み直していたところ以下の文を発見しました。
商品が出品・編集された場合は、カテゴリ毎新着一覧、ユーザ毎一覧、取引一覧、商品詳細APIに即座に反映してください。 編集・購入された商品については、全ての商品一覧・詳細取得APIで即座に情報を更新してください。 古いデータの削除、非表示はベンチマーク上で許可されません。各商品一覧取得APIが一度に返す商品数は初期実装と同じ状態を保つ必要があります。 新着一覧については、上記の制限を満たした上でよりユーザにあわせた商品の一覧を返すことで、購入の機会を増やすことができます。
なんか日本語がむずいですが、「各商品一覧取得」は「並び順や商品数」を変えてはいけないが、「新着一覧」だけは例外的に、度合いはよくわからないものの、商品の出し方を変えることが許されていると解釈しました。そこで、初期実装では新着一覧において、全てのユーザに全てのカテゴリの椅子を返していましたが、これを、ユーザ(ID の mod)によって表示する椅子のカテゴリを制限してみたところ、ベンチマークは通りました。これは、購入が特定カテゴリに集中しないようにして、ロック競合を減らすことが狙いでした。結果として、スコアが 12,000 あたりまで伸びました。
他にもいろいろやりましたが、メンバーの記事に任せるとして、最終的には、New Relic のロギングを撤収していくことで最終スコアは 15,100 イスコインとなりました。
成果物はこちらです。
後悔としてはいくつかあって、MySQL 5.7 を 8.0 に上げようぜ速いらしいよってなったときに、僕がインストール作業にまごついて「(どうせスコア上がんないし)他の改善に時間使おう」と提案しその通りにしてしまったことがまずあります。他チームでは 8.0 にしたことでスコアが伸びていたらしいので、後で sorah と rosylilly に詰められました。すまん! あとは、新着商品一覧を絞る発想まではよかったものの、購買ユーザごとに好みのカテゴリがあって、買ってくれるカテゴリを優先的に表示してあげることでスコアが伸びたそうなので、それはしっかりセッション傾向を分析するべきだったなと。競技中に気づくのは難しいけど、僕のかつての専門はこういうアプリケーションに入り込んだチューニングだったので、もっとこうできたな〜とワクワクしました。よく言われているログインの bcrypt については、確かに most time consuming で見ると /login が上位3位以内くらいにありましたが、われわれの実装ではボトルネックはまだ DB のトランザクションにあると見て、後回しにしていて、結局何もしませんでした。
今回の問題の感想としては、とにかく驚異的なまでにベンチマーカーのスコアが安定していて、何回実行しても近いスコアになったので、運の要素がかなり少なかったと感じます。これはいままでの大会のベンチマーカーに比べても最高の出来だったと感じます。人気者出品や、出品者からのサービスへの信頼(=購入成立数)に応じて出品金額が上がっていくなど、ユーザや事業の特性をみてチューニングをしようという、事業会社ならではの発想が盛り込まれていて大変楽しめました。よくここまで作り込めたな、と、出題経験者のひとりとして出題チームには尊敬の念を抱きます。
ISUCON について
最初に参加した ISUCON 2 では、僕はまだインフラエンジニアとしては経験が浅く、何もチームに貢献できませんでした。そんな若手のころから、エンジニアとして脂の乗っていた時代に出題の経験をしたり、準優勝をしたりと、僕のエンジニアとしての成長は ISUCON とともにありました。そして長い年月が経ち、多くのライフステージの変化がありました。僕は現場のエンジニアではなくなり、マネージャーになったのち、CTO になり、あと子供が2人生まれました。最初に組んだとき16歳だった sorah とはもう合法的に酒を酌み交わせるようになり、社内でもシニアな立場になっています。やんちゃだった rosylilly は起業し会社経営者になりました。
僕自身、ISUCON 7 あたりから、チームに貢献することが難しくなってきたなと感じるようになりました。現場を離れて久しく、かつては手癖でできていたオペレーションにもまごつくようになり、鈍っていくのを感じました。エンジニアとしてそういった自分の衰えと向き合うのは精神的に辛く、また、35歳になった僕がメンバーであり続けることでまだ若く優秀な2人の可能性を奪っているのではないか、他の若者と組んでもらった方が勝てるのではないか、ということばかり考えるようになりました。
そういった心境から、今回の ISUCON 9 は、当初、参加しないつもりでいました。
しかし、そこからさらに心境の変化がありました。出ないと決めたら、急に、いままで自分の成長が ISUCON とともにあったということを強く意識するようになったのです。そしてあのヒリついた競技時間の中に自分の大切にしていたものがあったことを思い出し、どうしてもまたあの時間を過ごしたくなりました。
あの時間というのは、開始時間が近づいてもロージーなかなか来ねーな大丈夫か〜とか、レギュレーションの意味ありげな記述を見つけて盛り上がったりとか、初歩的なミスに対して初心者かよ! って罵声が飛び交ったり、意見の食い違いでちょっと険悪になったり、ロージーちょっと今から Go で専用のプロキシサーバ書いてよ→ハァ!?→書けたわ、であったりとか、何をやってもエラーが解消しない焦りとか、すごい速度で実装していく sorah の姿をただ見守るしかない無力さとか、スコアが跳ね上がったときの歓声であったりとか、あの時間のことです。
あの時間の中でギャーギャーやってるとき、僕は一人のエンジニアであることを強く実感することができます。それだけのことですが、僕にとっては、長年積み重ねてきたかけがえのないものです。
長年関わってきたことで、僕は ISUCON のいち参加者というだけでなく、大会運営の一部を担っていると考えています。優勝経験こそ無いものの、ISUCON の歴史や慣習を作り上げてきた一人である自負があるからです。多くのものを与えてもらったからこそ、僕は ISUCON という仕組みや、参加者、運営スタッフの名誉を守りたいし、どういう恩返しができるだろうと、このところ考えていました。そして僕に今できる最大の貢献とは、とにかく誰よりも自分自身が本選を楽しむことだろう、という結論に至りました。心からあの時間を楽しんだならば、それは誰にも否定することができないだろうから。
予選を勝ち抜いたみなさん、おめでとうございます。勝負だ!