ナチュラル @rch850

ナチュラル丼発祥の地、福井からお届けします。技術的な話題とか、雑談とか。

ISUCON 7 予選敗退しました

ISUCON 5 のときと同じチーム「へしこず」で、2年ぶりの本戦出場を狙いましたが、本戦出場ラインには倍ぐらい届かず敗退しました。また来年会いましょう。

今回の主な装備

  • vim
  • kataribe
  • pt-query-digest (percona-toolkit), mysqldumpslow
  • beer (alcohol free)

序盤

予習で golang も検討したんですが、これまでの ISUCON で慣れてた ruby でやることにしました。

bundle install できないぞってことで sudo apt-get install -y ruby-bundler とか適当に叩いたのがアダ。 ~/xbuild 眺めたりして気づいたんですが ~/local/ruby/bin/bundle を使うのが正解だったようです。

まず POST /login のクエリがイケてない感じだったので、LIMIT 1 つけたり * を必要なものだけに書き換えたりして 10007 点になりました。その後何回か微調整してベンチマークして 15191 点あたりまで伸びました。このあたりはとりあえず API 1台だけでベンチマーク走らせてました。

この時点で2時45分ごろ。開始から2時間弱といったところでした。

中盤:icons をどうにかする

どうみても GET /icons/*.png なんとかしないとだめだよね。ってことで、なんとかすることに。画像を mysql から取り出して redis に入れる班と、nginx の設定いじってキャッシュさせる班のふた手に分かれて行動しました。俺たちを苦しめた icons の一部。

f:id:rch850:20171023012846p:plain

イコン画像が数百KBとか、仕事だったらありえないサイズだよねとか話してました。nginx 側は

 location ~ /(css|js|fonts|icons)/ {
        proxy_set_header Host $http_host;
                proxy_pass http://puma_app;
        proxy_ignore_headers Cache-Control;
        proxy_cache zone1;
        proxy_cache_valid any 1m;
        expires 1m;
        etag on;
        add_header Cache-Control "public";
    }

と書いてみたり、ruby 側では

configure do
  # 略
  set :static_cache_control, [:public, :max_age => 90]
end

とか

get '/icons/:file_name' do
  # 略
  etag file_name
  # 略
end

とか書いて、kataribe で見た icons の状況はこのようになりました。

Top 20 Sort By Total
Count     Total      Mean    Stddev     Min   P50.0   P90.0   P95.0   P99.0     Max   2xx   3xx  4xx  5xx  Request
 3097  6351.049  2.050710  3.120888   0.000   0.007   7.722  10.000  10.001  10.007  1646  1451    0    0  icons

100Mbps 使い切ってたネットワーク帯域にも少し余裕が出てきました。

あとは GET /fetch での SELECT COUNT(*) as cnt FROM message ... のコストが高いと考えて、件数を redis に入れるなどしました。

18:43 時点で 45124 点。他のチームが数十万点を出してて、だいぶ焦りが出てきました。

終盤:積み重ねでフィニッシュ

  • nginx → ruby (puma) をソケット経由にする
    • /etc/systemd/system/isubata.ruby.serviceExecStart = /home/isucon/local/ruby/bin/bundle exec puma -b unix:///tmp/puma.sock
    • /etc/nginx/sites-enabled/nginx.confupstream puma_app { server unix:/tmp/puma.sock; }, proxy_pass http://puma_app;
  • puma のプロセス数、スレッド数を増やす
    • /etc/systemd/system/isubata.ruby.serviceExecStart = /home/isucon/local/ruby/bin/bundle exec puma -w 2 -t 25 -b unix:///tmp/puma.sock
  • 既読メッセージIDを redis で管理する。
  • mysqld の max_connection を 1024 に。

などといった工夫を重ねて、終了直前には 125550 点まで伸ばせました。

f:id:rch850:20171023021054p:plain

感想

開始時間が遅れはしましたが、ベンチマークとダッシュボードは ISUCON 5 からの中で(自分が参加した中で)一番良かったと思います。

  • ベンチマークキューが詰まる気配がなかった
  • 「負荷レベルが上昇しました。」がエキサイティング!
  • レスポンスが遅いため負荷レベルを上げられませんでした。/message?channel_id=7466&last_message_id=0エラーが発生したため負荷レベルを上げられませんでした。2017-10-22 20:57:58.647006618 +0900 JST m=+31.152077525 リクエストがタイムアウトしました (POST /profile ) といった具体的なアドバイス

問題についても、icons をクリアしたら、さらに次の課題が出てくるような形で、なかなかのスルメゲーでした。これまでの ruby 実装とは違って unicorn ではなく puma、mysql2-cs-bind ではなく mysql2 だったので、調べ物に少し時間がかかってしまいました。

また、参加者連絡が discord になったわけですが、蓋を開けてみれば isubata ってのもクスリと来ました。

運営、出題の方々、ありがとうございました。残念ながら予選落ちしてしまいましたが、来年も参加したいです。いや、参加します。