このブログはURLが変更になりました

新しいブログはこちら→ https://matsuu.hatenablog.com/

isucon3本選に└('-'└)└)└)<HEARTBEATSとして参加した&予選本選を通して得た知見

11月9日に開催されたisucon3本選にチーム「└('-'└)└)└)<HEARTBEATS」*1として参加してきました。
結果は惨敗だったのですが、当日やったことと、予選本選を通して得た知見を書き留めておきます。

当日やったこと

画像のサムネイル作成をなんとかするためImager使ったら孔明の罠

ベンチマーク中にtopを眺めているとconvertコマンドがボトルネックになっていたのでここをなんとかしようと試みてみました。
convertを呼び出す代わりにImagerを使ってサムネイルを作成してみたのですが、Imagerだと差分検出でエラーになってしまいました。見事な孔明の罠ですね。やられた。

Image::Magickのインストールに手間取る

Imagerが差分検出で引っかかるので早々にあきらめてImage::Magickを使おうとしたのですが、cpanfileに

requires "Image::Magick";

を追記してcartonを実行してもインストールがエラーになって入らない。
includeするファイルが足りないのどうのと言われるので

yum install ImageMagick-devel

を実行してからインストールしてもダメ。なんだ。あ、もしかしてバージョンの問題か!幸いremiリポジトリが入ってたので、

yum remove ImageMagick ImageMagick-devel
yum install ImageMagick-last ImageMagick-last-devel

とすることでcartonでImage::Magickのインストールはできた…のだが、何故かStarletが起動する際にはImage::Magickがないって怒られる。なんでや。local::lib環境でXSはあかんのん?

よくわからないままApp::cpanminusでImage::Magickをインストールしてみたら

cpanm Image::Magick

あれ、なんかいけたっぽい。

Image::Magickで再実装するもエラー解消できず

PerlMagickのドキュメントを見ながらImage::Magickを実装するも、何故かうまく実装できず。試行錯誤するも時間がもったいないので途中で断念しました。

413 Request Entity Too Largeが出てて時間を若干とられた

あるタイミングでベンチマーク実行時のエラーで413 Request Entity Too Largeが出ててなかなか解決せず。nginxからapacheに戻すと解消したことからclient_max_body_sizeを指定してなかったことに気づいたわけですが、上記Image::Magickでの再実装とタイミングが重なっていたので原因究明に時間がかかってしまいました。

/tmpをtmpfsでマウントしたが性能下がった

Image::Magickによる実装がうまくいかないのでconvertコマンドのまま実装を進めていたわけですが、convertコマンドはtempfile()を吐き出し先として使っていたため、/tmpをtmpfsでマウントすればちょっとは性能上がるんじゃね?と思いマウントしてみたのですが、逆に性能が下がってしまったので断念。キャッシュに割くメモリの領域を食ってしまったからですかね?よくわからず。

サムネイル作成時にファイル保存

サムネイルを作成するタイミングでしておき、ファイルが存在する場合はファイルを直接返すことで性能が改善しました。サムネイルを作成するタイミングを変更するといった処理変更は実施してません。

timeline表示のSLEEPを2秒から1秒に

timelineで値が取得できなかった場合に2秒間待機する処理が入っていましたが、これを1秒に変更、またtimelineで都度ユーザ情報を取得してた部分をPerl上でキャッシュ、UPDATEがかかったときはPerlのキャッシュを削除*2するなどいたところ、6100程度までスコアが伸びていました。が、このあたりが自分の限界でした。

スケールアウトの方法をきちんと考えておらず1台構成のままフィニッシュ

終盤に複数台を活用する方法を考えるも良い案が思いつかず、とりあえず

  • 5台ともフロントにする
  • 画像投稿の時だけ1台目にproxyして1台目で処理
  • 投稿された画像はlsyncdで他4台に同期
  • 投稿以外は5台それぞれで処理

なんてザックリ考えていて、その準備が終わらずフィニッシュ。ついでに試行錯誤してるうちにスコアもだだ下がりしてて散々な結果となりました。チーン。

予選本選を通して得た知見

Varnishはできる子

予選の復習をしてる際に思ったのが、Varnishはとてもできる子なんじゃないか説。
httpdStarmanの間にvarnishを挟むだけで良しなにキャッシュしてくれてスコアが1100→2000と改善しました。
さらに予選のようにそのままではキャッシュしにくいパターンでもESIを駆使することで比較的簡単に部分キャッシュが可能なのでかなり使えるのではないかと感じました。
本選のようなパターンだと素直にキャッシュできないので簡単には使えませんけどね…。でもモジュールが豊富で

とかあるし結構いけるんじゃないかと思います。

apachetopとwtopは惜しい子

アクセスログからどのクエリが多いか、時間がかかっているかを調べるのにapachetopwtopが便利でした。
単純にログを見るだけなので、Apacheと同じ形式でログ出力すればnginxと組み合わせても使えます。

wtopはクラスを定義すればログの種類をまとめることができるのでとても良いのですが、HTTPメソッド毎の分類ができないのがちょっと残念です。改善してpull requestを送りたい。そのうち。

今回もプロファイラのDevel::NYTProfを使いこなせなかった

isucon予選でDevel::NYTProfをうまく使いこなせなくて、そのことをツイートしたらmiyagawaさんから

とヒントを頂いたのですが、それでもうまく使いこなせず。Devel::NYTProfは今後の課題です。

追記:検証してみたところ、最新版のPlack::Middleware::Profiler::NYTProfを使うと Kossy::__ANON__が上位にくることもなく綺麗にプロファイリングできていい感じでした。

最後に

└('-'└)└('-'└)└('-'└)└('-'└)└('-'└)
 "ISUCON 準備お疲れさまでした!!"
    ありがとうございました!
 来年もよろしくお願いいたします!
└('-'└)└('-'└)└('-'└)└('-'└)└('-'└)

*1:予選のチーム名は└('-'└)でした

*2:今思えば複数台構成にするとこれダメね