見出し画像

社内でISUCON問題(private-isu)に触れてみた 環境構築編

この記事は、2023年のPharmaXアドベントカレンダー6日目の記事となっております。


こんにちは、PharmaX、YOJO事業部エンジニアの江田です。
PharmaXのエンジニアチームでは、月2~3回のペースで勉強会を開催しております。この記事では、その勉強会の中で私が担当した「ISUCONハンズオン」の内容を紹介したいと思います。
ただし、それなりの分量があるので、環境構築編と実践編で2回にわけて紹介します!


ISUCONとは?

ISUCONとは、「いい感じにスピードアップコンテスト」のことで、お題となるWebサービスをどれだけ高速にできるかを競う大会です。
いい感じというふわっとしたタイトルの通り、最低限のレギュレーションさえ守れば何してもいいという自由度の高さがうりとなっています。

運営はLINEヤフー株式会社が行っており、毎年優勝者には賞金100万円がでます。

ISUCONで競うもの

ISUCONではAWSで構成されたサーバーに対してSSHで接続し、サーバー構成、各サーバーの設定やアプリケーション実装などを変更することで高速化していきます。
チューニングしたサーバーがどれだけ早くなったのか確かめるには、ISUCONのポータルサイト上で自分のサーバーに対してベンチマーカーを実行させます。このベンチマーカーがサーバーに大量のリクエストを投げ、エンドポイントの成否によって得点が計算されていきます。
ISUCONではこのベンチマーク実行時のスコアを何点まで上げれるかを競います。

ISUCONの自由度

高速化の手法はかなり自由度が高いです。
以下は2023年開催されたISUCON13のレギュレーションです。
下で解説していきますが、注目すべきは許可されている項目です。

https://isucon.net/archives/57768216.html


禁止事項はざっくり要約すると、アプリケーションの仕様自体が変わってしまう変更は禁止ということです。URL自体の変更やレスポンス構造の変更、配信する画像のクオリティなどを変えることは、そのアプリケーション仕様が変わるため禁止となっています。

許可される事項の欄をみると、ISUCONの自由度がわかると思います。
DBへのインデックス追加や、キャッシュ・非同期処理の実装はもちろん、EC2のインスタンスが複数あるので、サーバー分散などを行うことも可能であり、DBやアプリケーション実装を別のものに置き換えることも可能です。

ISUCONでの作業の流れ

ISUCONは基本10:00~18:00までの長丁場となっています。
ISUCONが朝始まると、まずは仕様の把握とログ分析体制の構築を行います。各レギュレーション・マニュアルを読みながら、環境構築、分析ツールの導入、ソースコードをgit管理下に置くなどの作業をします。

分析体制が整った後は、ひたすら終了まで計測〜改善のサイクルを回し続けます。ログ分析ツール・ベンチマーカーによってボトルネックを探し、改善しては新しいボトルネックを探すという繰り返しを行います。

ISUCONでは各技術領域の知識も重要ですが、この計測〜改善のサイクルをいかに回すかという観点も重要となっています。

ISUCONで得られる知識

なぜISUCONを今回勉強会のテーマにしたかというと、一番はボトルネックの知識が実際の数値と共に得られるからです。
例えば普段バックエンドを実装する際、N+1やインデックスを貼るべきかを意識するとは思いますが、それが実際どれくらいパフォーマンスに影響を与えるかというのは知る機会があまりないのではないでしょうか?
ISUCONでは普段パフォーマンスのために気をつけるべきことが、どれだけの意味があるのかを計測結果とともに知ることができます。

他にもボトルネック調査や改善の引出しが増えるということや、各サーバー(webサーバー、アプリケーションサーバー、DBサーバー)の操作・環境構築の能力がつくというのが、ISUCONを勉強していて良かったと感じた点です。


今回の勉強会でやったこと

最終的には社内ISUCONを開催してみたいのですが、今回はそのための前提知識を得ることを目的としました。

以前僕は、ISUCON研修というイベントに参加しました。
実際のISUCONに近いスケジュールで問題を解いていく方式だったのですが、事前準備を特に何もせず取り組んだ結果、DBにちょっとインデックスを貼って終わるという悔しい結果で終わってしまいました。

以前失敗した原因は、ツールの選択肢・導入・使い方を1からキャッチアップしたことと、計測すべき観点の引出しが少なく場当たり的な改善になってしまったことが大きかったです。

その失敗から、いくら知識としてパフォーマンスチューニングの原理・原則をわかっていたとしても、実際に問題を解いていくには計測ツールや計測する観点の知識がないと全然時間が足りないという学びがありました。

そこで今回は、実際にみんなで環境構築を行い、計測〜改善の流れをいくつかやってみることで、ツールや計測観点の肌感を掴む会にしました!


今回使用したリポジトリ

今回の題材はISUCON本にも取り上げられているprivate-isuを使用しました!

Iscogramという画像投稿サイトをチューニングしていく問題で、ISUCONの練習というと必ず名前の上がる有名なリポジトリです。
メンテナンスがされ続けているので、特にハマらず簡単に環境構築できました。


環境構築

今回はみんなで触ってみることが目的なので、EC2ではなく気軽に触れるdockerで環境構築しました。
手順を紹介します。

リポジトリのクローンと初期データ投入

git clone git@github.com:catatsuy/private-isu.git

cd private-isu/

# 初期データの配置
cd webapp/sql
curl -L -O https://github.com/catatsuy/private-isu/releases/download/img/dump.sql.bz2
bunzip2 dump.sql.bz

# dockerの起動
cd ..
docker-compose up

ベンチマーカーのビルド

cd /benchmarker/userdata
curl -L -O https://github.com/catatsuy/private-isu/releases/download/img/img.zip
unzip img.zip
rm img.zip
cd ..

docker build -t private-isu-benchmarker .

# ベンチマーカー実行
docker run --network host -i private-isu-benchmarker /opt/go/bin/benchmarker -t http://host.docker.internal -u /opt/go/userdata

nginxとmysqlのログをホストのlogsディレクトリに出力するようにする

docker-compose.ymlを編集し、logsディレクトリをマウントする。

nginxのvolumeに以下を追加

- ./logs/nginx:/var/log/nginx

mysqlのvolumeに以下を追加

- ./logs/mysql:/var/log/mysql


mysqlのスロークエリログを有効にする

/webapp/etc/my.cnfを以下に置き換え

[mysqld]
default_authentication_plugin=mysql_native_password
slow_query_log=1
slow_query_log_file=/var/log/mysql/slow-query.log
long_query_time=0.0

この辺の設定の意味などは、実際に解くタイミングで説明しようと思います。

nginxのログ出力設定

/webapp/etc/nginx/conf.d/default.confを以下に置き換え
後でalpを使って分析するため、ltsv形式でログを保存するようにする。

log_format ltsv "time:$time_local"
  "\thost:$remote_addr"
  "\tforwardedfor:$http_x_forwarded_for"
  "\treq:$request"
  "\tmethod:$request_method"
  "\turi:$request_uri"
  "\tstatus:$status"
  "\tsize:$body_bytes_sent"
  "\treferer:$http_referer"
  "\tua:$http_user_agent"
  "\treqtime:$request_time"
  "\truntime:$upstream_http_x_runtime"
  "\tapptime:$upstream_response_time"
  "\tcache:$upstream_http_x_cache"
  "\tvhost:$host";
  
server {
  listen 80;
  client_max_body_size 10m;
  root /public/;

  location / {
    proxy_set_header Host $host;
    proxy_pass http://app:8080;
  }

  access_log  /var/log/nginx/access.log ltsv;
}


dockerを再起動し、再度ベンチマーカー実行

ベンチマーカーを再度実行し、ログを出力させる

docker-compose up

docker run --network host -i private-isu-benchmarker /opt/go/bin/benchmarker -t http://host.docker.internal -u /opt/go/userdata


nginxのログ分析ツールの導入

alpをmac側に導入。

brew install alp

# ログ確認
cat logs/nginx/access.log | alp ltsv -m="^/posts/[0-9]+","^/image/[0-9]+\.(jpg|png|gif)","^/@[a-z]*" --reverse


mysqlのログ分析ツールの導入

pt-query-digestもmacに導入。

brew install percona-toolkit

# ログ確認
sudo pt-query-digest logs/mysql/slow-query.log


以上で環境構築は完了です。


おわりに

以上で環境構築は終わりです。
次回は実践編として、解く際の観点を解説しながら、実際に計測〜改善の流れを3つほど紹介したいと思います!

実践編はこちら

PhramaXでは、connpassにて定期的にエンジニア向けイベントを開催しております。ご興味のある方は是非ご参加ください!


この記事が気に入ったらサポートをしてみませんか?