梅の仁 | カオスの坩堝 https://anqou.net/poc Chaos is not kaos. Sat, 03 Oct 2020 14:58:05 +0000 ja hourly 1 https://wordpress.org/?v=6.1.1 https://anqou.net/poc/wp-content/uploads/2018/02/9dc10fe231765649c0d3216056190a75-100x100.png 梅の仁 | カオスの坩堝 https://anqou.net/poc 32 32 愛と悲しみのISUCON10決勝 https://anqou.net/poc/2020/10/03/post-3336/ https://anqou.net/poc/2020/10/03/post-3336/#respond Sat, 03 Oct 2020 14:51:56 +0000 https://anqou.net/poc/?p=3336 TL:DR;

  • isucon10決勝でfailしました
  • 僕の注意不足です
  • つらい

なにがあったのさ

デーモンファイルにRestartSec=10sとかを入れないまま、問題が発覚しない形で再起動試験をしてしまったのでサービスが死んでた。具体的には、golangのサーバーがredisがロードし終わる前にconnection貼りに行ってて死んだ。

なにしてたの

  • 10:00 sshとかの環境整えてansibleでbootstrap
    • git configしたりいつものツールを突っ込む
  • 11:00 プロファイル取って様子を見る・デプロイ環境の若干の用意
    • 方針を決めてチームメンバーに改修をよろしくした
  • 12:00 query改善
    • generated columnとか使ってクエリをいい感じにしてた
    • 生の点と減点を引いたスコアをSTORED
    • indexも多少貼った
    • team_idとかにうまく貼られてなかったのを改善
    • あとは見つけ次第クエリの改善(? = TRUEとか。)
  • 14:00 redis導入
    • jobQueueを実装したかった
    • anqouに託した後断念している
  • 15:00 いろいろなパラメーターのチューニング
    • mysqlの設定値とか
    • interpolateParamsとか
    • envoyのLimitNOFILEとか(envoyなんもわからんかったけどファインプレーだった様子)
    • /etc/security/limit.confとか
  • 16:00 sessionを外(redis)に出す、envoyをいい感じに複数台構成
    • ぱっぱと出来たのはよかったけど…
    • ここのせいで再起動試験落ちの結果になってしまった
    • 本当に鬱
  • 17:00 indexを追う
    • チームメンバーがキャッシュを導入してくれてたおかげでmysqlの負荷がだいぶ減っていた
    • それでも変なクエリを書き換えたりindexきかせていた
    • 変なOR文にmergedIndexした
  • 17:30 再起動試験
    • 1台ずつ順番にやってしまった
    • 依存関係のあるサーバーは同時に起動すべきだった
    • つらい
    • つらい
    • つらい

おえて

チームメンバーには本当に申し訳ない気持ちでいっぱいです。多分再起動試験通ってたら3位圏内だったので本当につらい。しばらくチームメンバーにはまともに顔向けできないです。ごめんなさい。なお、**daemonの定義ファイルは最初にちゃんと覗くようにしましょう。**

そして私が事前にメモ書きしていたことの中に、

再起動試験をする

– `sudo reboot`
— 最悪起動しないときのために、1台ずつ再起動する
可能なら3台同時再起動なども行うべき?

メモ書きより

とありました。3台同時再起動すべきでしたね。とんでもない鬱。すいませんでした。

辛い気持ちのまま書きなぐってるので書きなぐりです。具体的なことがなくてごめんなさい…

暗い話はさておき

それでも楽しい思いをさせてもらいました。運営のみなさまありがとうございました。

]]>
https://anqou.net/poc/2020/10/03/post-3336/feed/ 0
ISUCON10生は2度目です https://anqou.net/poc/2020/09/13/post-3323/ https://anqou.net/poc/2020/09/13/post-3323/#respond Sat, 12 Sep 2020 19:20:44 +0000 https://anqou.net/poc/?p=3323 TL;DR:

お前だれ

俺は梅の仁。特にとりえもない平凡な男子大学生だ。ある日大学への道を歩いていたら、トラックにはねられて異世界転生しちまった。転生した世界は魔法、剣、そして椅子が存在している世界で、美男美女の椅子に言い寄られる羽目になっちまったぜ。彼/彼女たちに、ちゃんとドアに入る家を案内するために、俺はisuumoを開発することになったんだ。こうなったら、現代エンジニア知識で無双してやる!

ちゃんと書け

こんにちは、皆さんにももう知っていただけていることと思います、梅の仁です。去年、ISUCON9でなんやかんやあって本戦に出ていました。しかし、スコアは振るわず15位。本当に悔しい気持ちを抱えながら今年の7月を迎えました。

「上限」が目に飛び込んできて、もうね、秒だよね、秒。絶対に参加したい思いを抱えていたので、1人でもいいからと申し込みをし、去年のメンバーであった@jumon_jp@ushitora_anqouを誘いました。すぐに快い返事を頂け、院試や研究といった勉強をしつつ、ISUCONへの気持ちを高めていました。2人のステータスはこちら。

  • @jumon_jp
    • ナウでヤングな音声処理の達人
    • すごい猫
    • アプリ(Golang)をお願いしてた
  • @ushitora_anqou
    • コンパイラと論理学の名人
    • GPAポケモンの開発者(それが紹介でいいのか?)
    • すごい深海魚
    • アプリ(Golang)をお願いしてた
    • チームビルドをした
    • インフラを眺める人
    • discordのサーバーでふざける人

前日まで

ISUCONの練習と称して、ISUCON8予選とISUCON9本戦のインスタンスを建て、チームメンバーと色んなツールを動かしたりする練習をしました。

ソースを読みながら頑張って建てたISUCON8の予選ポータルサイト。大変だった

前日までこれに参加していたので、予選前日は疲労困憊で早めに就寝。見事朝7時に起きたのでISUCON優勝です。そして1時間後にこのようなアナウンスが来ました。

もう2時間寝たくなりました。さすがに起きておこうと思い、コーヒーを体に流し込みました。

競技開始

12:30 競技開始

さて、Ansibleを使って、用意していた初期化や「いつものツール」を入れるやつをやりましょう!

…できんのだが?てかwslからはsshできるんだけど、え、なんでwinからだとssh出来ないの?は?

どうやら原因はここだったみたいなのですが、焦りに焦ってAnsibleの内容を手で実行する羽目になりました。それに、win上からVSCodeでsshもできなくなったため、自動的にssh上でrawなvimを使うことになりました。本当につらかったのですが、まあどうにかなるにはなるので、まずは各サーバーにswapを作りましょう。

sudo dd if=/dev/zero of=/swapfile bs=1M count=4096

所で、df -hの結果をご覧ください。

/dev/vda1       9.6G  8.7G  917M  91% /

なんと全体が10GBしかないんですね。4GBもスワップを作ることは不可能でした。disk fullを起こしてしまい、「やばいサーバー死んだらやばい」とすぐに rm -f /swapfile。めちゃくちゃ焦りました。良い子は空き容量を確認してからswapを作りましょう。その後いつものツールなどを投入しながら、マニュアル読みを2人にお願いしていました。アプリの仕様を知らないため、「なぞって検索がやばい」というメンバー2人の会話を、「『謎って検索』するってなんなんだ…?曖昧検索かfeeling lucky…?」と思いながら作業していました。

13:00- nginxないし開発環境整備

nginx.confのひな型を導入し、デプロイのための環境を用意していました。後ろで最初のベンチマークが走っているのを聞きながら、「MySQLのCPU負荷がすごそう」みたいな話を聞いていましたが、「CPUだったらappな気もするなあ」などと発言していました。この後すぐ、その見立ては外れます。ここでコーヒーブレイク。

13:30- mysql設定投入、stock

mysql.cnfのひな型を投入し、slowqueryを眺めることに。どう考えてもやばそうなクエリのオンパレードでめまいがします。これはいかんとMySQLWorkbenchをつなげ、ER図を取ることにしました。案の定初手はつながらなかったため、 bind-addressをコメントアウトし、権限が足りないと怒られたため、権限付与を行いました。そして現れるこれ。

クソでかテーブルが2つ、インデックスがない。ああ、神よ。

もうめまいですよね、めまい。コーヒーを飲みます。「どう考えてもMySQLのCPUやば~~~~!!!!!」となり、急いでslowQueryを考えることにしました。
クエリを眺めてるにあたって、あまりにも stock > 1のWHERE条件が多く、indexが効かせにくい、indexよくわからん問題に出会いました。@jumon_jpと一緒にstockをDBから外し、インデックスをそれに合わせた構成にしました。

14:30- ずっとMysqlと向き合う

マジで何にもわからん。テーブルが参照系が多いようなので、インデックス貼って貼って、貼りまくって、クエリが使われてる文脈を聞いて、貼って、貼って、消して…それを繰り返していました。
クエリを眺めている途中で、椅子がドアに入るように回転させ、6個もOR条件を発行するわけのわからんクエリを発見。@jumon_jpに競プロっぽい解決をいい感じにお願いしていました。また、なぞって検索を良しなによくするのを@ushitora_anqouにずっとお願いしていました。

16時も近づいてくると、どうしてインデックスを貼っても貼ってもうまく動かないのか、見当がつくようになってきました。大体、ユーザーの入力条件によってWHERE句の中身が変わり、DESCオーダーとASCオーターの組み合わせを行うのじゃ、WHERE句の条件が選択的だったり選択的じゃなかったりします。なぞって検索で、クソ小さい丸を書いたならindexが効くかもしれませんが、クソ広い丸を書いたならindexが効く理由がありません。optimizerが、インデックスを使うより、全件検索を行うが良い、と判断するようなユーザーの入力もあるでしょう。どうしようもありません。@ushitora_anqouと「検索はクソ!!!!!」と叫びながら、インデックスじゃどうにもならんケースも多そうだと感じていました。そう思いつつも、よく来るようなクエリの組み合わせで、かつ、「条件が絞り込めそうなクエリ」にindexを貼っておくことにしました。それでも全く減らないCPU負荷に焦りを抱えていました。

17:30- 複数台構成・mysql8導入

optimizerの改善と、desc indexの利用に期待し、mysql8にあげる決断をします。ですが、あらかじめ複数台構成を始めよう、と決めていた時間が迫ってきていました。私がインフラ担当なので、本来なら複数台構成は私がやるべきなのです。ですが手が足りず、@ushitora_anqouに依頼しました。(本当にごめんなさい)その傍らで、mysql8のアプデを行いました。アプデ後、すぐに設定をチューニングし、DESC indexを使うと点数が良く伸びました。

それでも劇的な伸びとは言えず、CPUは100%に張り付いたまま。ここらへんからつらくなってきました。去年はなんやかんやありつつ本戦出たんですよ。今年こそはと1年間、いろいろなことの合間合間にweb系に触れ続けてきたんです。誘った側としても、web系ちょっとは触ってて、インフラ担当って名乗ってる人間としても、ISUCON大好きな私としても。予選落ちしたらチームメンバーに申し訳立たねえよマジでどうしようかと思い始めます。

そんな思考はさておき、@ushitora_anqouとDBの根本的な相談をします。「インデックスを貼ったうえでもどうも無理なリクエストが出うる」「多角形の内側を判定する部分をどうにかできないか」「latitudeとlongtitudeの絞り込み問題で何とかインデックスが効くようクエリを分割できないか」などと会話をしました。MySQLのレプリケーションを行って、Read SlaveとMasterにわけ、負荷分散を行うといいのでは、という結論になりました。ですが、インフラ担当の癖にレプリケーション、やったことないんです。残り時間も少なくなり、見送ることにしました。

20:00- カーネルパラメーター調整

もう最後のダメ押しだと、mysqlサーバーのカーネルパラーメーターをチューニングし始めます。ですが全く意味はありません、なぜならCPU負荷は下がってないからです。iowaitだって出てないのです。ですが焦ってしまい、知ってる手法で早くなることを願ってしまいました。

「推測するな、計測せよ」

本当にこの一言に尽きると思います。案の定スコアは変わらず、再起動試験の時間を迎えました

20:30- 再起動試験、ガチャ

再起動試験をします。あらかじめチェックすることをチームメンバーが記述してくれていたので、滞りなく再起動を行えました。振り返ってみると、個人が検証用にfailしたことはあったものの、全員の成果を組み合わせたベンチは一度もfailすることなく進められていました。それもあって、再起動後に動きさえすれば、再起動failにはならないだろうとメンバーを信頼していました。

そしてISUCON名物ベンチガチャ。あまり振れ幅が変わらなかったものの、まあ最高点に近い点数で撤退。「DBの負荷どうやって下げたら良かったんだろうなあ」「わからんねえ」「わからん」と言いながら、ISUCON10予選を終えました。冷たかったコーヒーはすっかりぬるくなっていました。どうやら500mlぐらい飲み干していたようです。

21:00 – 0:08 そして

雑談をしたりしなかったり、寝たり寝なかったり、ご飯を食べたり食べなかったりして、運営の皆さんの動向を監視していました。discordのrandomにはいろいろな人の感想が流れてきたので、「うわーそれは賢い」「それも賢い」「すごい」「なんやねんその概念」とわいわいしていました。圧倒的なDB律速、そしてその対処のための知識の奔流に、まだまだ若輩者だと実感させられました。特に、「テーブルごとにDBを分割する」アイデアは本当に素晴らしいと感じました。なんで気づかんかったんやろう。@ushitora_anqouと私で悔しがっていました。

0:00を回り、運営の皆さんの終電が心配されるようになったころ、運命の時間がやってきます。最初少し聞き逃したため、一般枠の25位までをよく理解しないまま、941さんのひとこと「計算機科学実験及演習5」。ああ、学生枠2位です!!!本当にうれしかったです。

去年は本戦に出れて「ラッキー」でしたが、今年は正直安心しました。チームメンバー全員そろって本戦に出れるわけです。本当に、本当にうれしかったです。

悔いのない本戦を戦いたいですね。そして、できれば良い成績を。本戦をご一緒できるチームの皆さんと戦えることを待ち望んでいます。

そして、大変な思いをされ、終電を心配され、深夜の3時に起きてる運営の皆様。本当にお疲れ様です、そして、ありがとうございます。めいっぱい楽しい思いをさせていただきました。本戦でも楽しませていただきます。本稿が少しでも大会を盛り上げることを願って、締めとさせていただきます。

末筆ですが、読了ありがとうございました。

]]>
https://anqou.net/poc/2020/09/13/post-3323/feed/ 0
異世界転生してISUCON9に参加しました https://anqou.net/poc/2019/09/09/post-3069/ https://anqou.net/poc/2019/09/09/post-3069/#respond Mon, 09 Sep 2019 12:26:52 +0000 https://anqou.net/poc/?p=3069 TL;DR:

ISUCON9で予選敗退しました。悔しい!!!!!!!!

これはなに

初めまして。皆さんご存じ梅の仁です。

ひょんなことからISUCONに初参加してしまったフロントエンドマン、梅の仁!「フロント改善してやる」と思ってたら、フロントはほぼいじれないしバックエンドが迫ってきた!

果たして持ち前の才能で「あれ?俺、なんかボトルネック解消しちゃいました?」となるのか!?

いきさつ

ISUCONの存在を学友から聞き、興味が湧いていた所に@_nemohemからお誘いを受けました。「わ~い@_nemohemと一緒うれしい参加する~」と伝えた所、@_nemohemが@anqouを連れてきたので、「あれ?2人ともヤバくね?マジ卍」とか思っていました。

私は二人とも面識があったんですけど、@_nemohemと@anqouにはあまり面識がなかったようで、最初の顔合わせの時にげらげら笑った記憶があります。私の認識の中でのチームメンバーはこんな感じ。

わし:フロントエンドマン

担当する予定だったこと

  • それとなくインフラ担当
  • クエリを見つめる担当
  • スピリチュアル・エンジニアリング担当

@_nemohem:アプリや人工知能系などモダンな開発にお強い人

@anqou:C++と言語処理大好きな深海魚鯖管。言語を理解するのにコンパイラを実装するやつ。

二人に任せる予定だったこと

  • Golang

前日譚

ISUCONの過去問を解くまでは、フロントエンドを普段書いているのでせっかくならフロントを改善しようと思っていました。「フロントってそんなに改善ポイントあるのかなあ」と思っていたら、フロントは競技自体に含まれないと発覚。他チームメンバーがGolangを理解しそうで、かつ自分がMySQLぐらいしかわからなかったので、MySQLを主軸としてインフラを担当すると決意しました。

そこからは、MySQL知識に特化すべきと、書籍を数冊読んでみたり、App-Go-Tourをかじったりしました。さらに、ISUCON過去問をvagrantで提供してくださっているrepoがあったので、「vagrantってなんやdockerとはちゃうんか」とアワアワしながら解いたりもしていました。

あと、「インフラ担当は全体の司令塔になるべきだよ」という参加記を読んでいたので、他のチームの過去問の解法を見て、様々な構成を知識として仕入れるようにしていました。しかし私では司令塔になり切れず……アプリをやってくれる二人、割と司令塔いらずだったと思います。

当日

08:30 0次戦

起床成功です!!!!!ISUCON優勝!!!!!

09:40 0.5次戦

現着です!!!!!ISUCON優勝!!!!!

10:00 始動

@_nemohemがインスタンス建てと初期設定、@anqouがマニュアルを読んでいる横で、環境構築とレギュレーションを一読しました。

SSH通ってからは、まずみんなでアプリの動作確認、ベンチマーカーの挙動を確認しました。 「椅子借(?)り」は最高の命名センスだと思います。

アプリを一通り理解したのち、MySQLのログの収集を始め、スロークエリの把握と伝達を行いました。次にER図が欲しいよなあと、MySQL WorkbenchをSSH接続させようとしましたが、過去問のようにうまくいかず断念。

ここらへんでスキーマを眺めてると、mediumblobを使ってるテーブルがあったため「ISUCONの過去問で見たやつだ!」とわくわく。また、@_nemohemが固定データのDBを調査していた気がします。

11:00 インデックス貼り

N+1問題を解決してる人(@anqou)やコード読みをしている人(@_nemohem)の横で、あれやこれやとインデックスを貼り、初期段階でのスロークエリを撲滅。ついでにMySQLのパラメーターの初期設定を投入しました。

あと画像ファイルの配信がshippng.img_binaryなのかを@_nemohemが特定し、DBは関係ない?ぽいと分かったので、nginxの設定をしようとしましたがよくわからず断念。

ガバポイント:そう!インフラ担当と宣いながら!nginxの勉強がおろそかだったのである!

原因としては、/webapp/publicのパス間違えと、locationの指定ミスでした。静的ファイルの場所を突き詰められてなかったのが原因です。このせいで@anqouの負担が2倍になりました。ほんとごめんなさい。

12:00 ごはん

一つ目のN+1が解決の目を見たらしいので、ベンチを回すとなんか動かない。負荷が足りないのかとcampaignを増やしてもらうとMySQL側がToo many connectionsで死んだので、max-connections, wait-timeoutの調整で対応しました。ここらへんは過去問を解いていたのが活きました。

ここで名残惜しいながらもいったん昼食。@anqouと食べたものが一緒だったので、以下@anqouの参加記から引用します。

諦めてご飯を食べに行く。店に入るほどの余裕はなかったのでローソンで冷やし中華を買って食べた。麺がゴムっぽかったが、お腹も減っていたのでまあまあ美味しかった。タレで味がついていれば大抵の物は食えるんだなぁ。みつを。

みつを。

13:00 いつも心にB+tree

スロークエリをさらに切り詰めると、categoriesがそろそろ無駄になってきていたのでGolang側に乗せてもらうことに賛成する。インデックスがうまく効いてなさそうなクエリをexplainして眺め、あれやこれやと解決方法を試しUsing filesortは殺しきる。Using indexはきもちええんじゃ。

いったん置いておいて、12時ごろの作業の続きとして、fs.file-maxipv6の無効化などのカーネルパラメーターの調整を行う。

14:00 nginxなんもわからん

nginxのキャッシュ、圧縮、パラメーター調整を行う。これによって304がブラウザ上でしょっちゅう帰ってくるようになったが、多分実装ミスの気がしている。あまりスコアが伸びず、nginxが悪いと推測しキャッシュと圧縮を外す。

ガバポイント:推測ではなく計測結果で語るべき。

「15時には複数台構成を導入しよう」と@anqouから提案を受けていたため、ちょっと焦りつつも@_nemohemがインスタンスの用意を始める。

15:00 複数台へ

複数台構成にするにあたって会議。@anqouがnginx,app,dbサーバーを提案し、私がnginx(+app),nginx+app,nginx+dbサーバーを提案。この構成については、ISUCON7予選を突破したチームのものを参考にしてました。nginxレイヤーで画像のアップロードに対応できるのがよいという話になり、構成を決定。

今までのconfファイルなどを突っ込んだrepoを@anqouが用意してくれたため、nginx+DBサーバーを用意し、パラメーターの調整を始めました。

ガバポイント:カーネルパラメーターの設定ファイルをrepoに移すことを提案しそびれる。

16:00 やらかし!!!

nginx-MySQL間の通信がTCPベースでどうもうまくいかず、@anqouに見てもらうように依頼。(ごめんなさい!)

anqou「MySQLってTCP3306よね」

ガバポイント:わし「多分そう」

などと会話しながら、 あれやこれやと試すもどうもつながらない。解決できず悶々とする。

もちろん試すわけですから、mysql -h hoge -u piyo -pコマンドとか、mysqlコマンドとかをいろんなターミナルで叩くわけですよ。ログとかもたくさん出るわけですね?その時梅の仁に激震走る。

$ mysql Can’t connect to local MySQL server through socket ‘/hogefuga/mysql.sock’

ガバポイント:わし「あっあっあっUNIX DOMAIN SOCKETでいいやん!!!!!!!!!!!!!!!!!!!!!」

ここに気づいてからはチームで爆速で修正し、画像のアップロードにも何とか対応してくれました。ブラウザ上で動くようになりました。マジでごめん。

17:00 ラストスパート

クエリを最後まで見つめる。

`status` IN ('on_sale','trading','sold_out','cancel','stop')

とかが確実に不要と気づき、修正すると当該クエリが10倍速くなりご満悦。

ベンチが再起動直後にfailする不安と闘いながらも、無事通ることが確認できたため再起動試験に移行。プロファイルの除去、サービスの再確認、ロギングの削除を行って再起動。数回ベンチを回すと、17:45に過去最高得点が出たので撤退。最終スコアは9670でした。

打ち上げる

モダン焼きを食べながら打ち上げ。感想部屋を見ながら「デッドロックか」「非同期API~~~!!!!!」と叫ぶ。確かにFOR UPDATEあったもんなあ、とクエリを見つめる側から大反省。打ち上げ中に順位の発表があり、10000点ほどがボーダーと知り死ぬほど悔しがる。でも初参加にしてはいい点が取れたよね、と大満足。

私も無料で新宿に行きたい人生だった…椅子から100万円手に入れたかった…(?)と思いながら帰路につくと、9880点がボーダーと変更になりさらに悔しがる。

さらに参考スコアの発表となり、9880点のすぐ下につけていたと分かり泣く。再起動試験に通っていたかは定かではない…けどね!

反省

今回のISUCONではアプリ側の改善の量が多く、いくらインフラ担当と宣えどもGolangの修正を担当すべきでした。例えばN+1問題のクエリをもらい、すぐ解消できるようなクエリを発行するとかならできたでしょうね。アプリ側の人に任せっぱなしなのはよくなかったなあと。

実装速度が遅いのも考え物ですね。タイピング鍛えます。

あとアクセス解析という観点があることを感想戦で知りました。スコアの出し方が「売上のコイン数」であることをマニュアルからちゃんと読み取れば、アクセスの偏りや、売り上げを伸ばすために表示を調整するなど、まだまだ取り組めたことがあるように思います。

新着一覧については、上記の制限を満たした上でよりユーザにあわせた商品の一覧を返すことで、購入の機会を増やすことができます。

↑↑↑これとかね…!!!(マニュアルより引用)

あとガバ大杉な!!!!!!!!!!!!!!!!!!ア!!!!!!!!!!!!!!!

次があるなら、まずnginxを理解して参戦したいですね。そしてもっとインフラチューニングができるようになりたい。

チームメンバーと、過去問の情報を提供してくださってる皆様、楽しい大会作ってくださった運営の皆様に感謝し私のISUCON参加記は終了です。お疲れさまでした!

]]>
https://anqou.net/poc/2019/09/09/post-3069/feed/ 0