【負荷試験】ISUCONの練習環境 private-isu をAWS上に構築してみた
こんにちは、ゲームソリューション部の入井です。
最近、負荷試験やパフォーマンスチューニングの勉強のために以下の書籍を読んでいます。
達人が教えるWebパフォーマンスチューニング 〜ISUCONから学ぶ高速化の実践 | | Amazon
この本の中でprivate-isuという負荷試験の練習ができる環境が紹介されていたのを見て、実際にAWS上で構築してみたので、今回はその手順について書いていきます。
private-isuとは
LINE株式会社が主催するISUCON(Iikanjini Speed Up Contest)というイベントがあります。これは、『お題となるWebサービスを決められたレギュレーションの中で限界まで高速化を図るチューニングバトル』という内容の大会で、毎年様々な企業から参加者が集まって盛り上がっており、今年も11月25日に開催することが予告されています。
ISUCON13開催決定!今年は本選のみ開催! #isucon : ISUCON公式Blog
このISUCONを社内で開催するため、2016年にピクシブ株式会社の金子氏が中心になって作成した問題がprivate-isuです。この問題は、Go言語、Ruby、PHPといった言語別に開発されたWebサービスと、Go言語で実装されたベンチマーカーで構成された環境となっています。Webサービスにパフォーマンチューニングを施した結果、どの程度性能を上げられたかをベンチマーカーでスコアを計測できるようになっており、実践的にWebサービスの負荷試験やチューニングの方法を学ぶことができます。
ソースコードやAMIについては、以下のGitHubリポジトリで公開されています。
GitHub - catatsuy/private-isu: 社内ISUCON
当初は社内向けに作成されたものでしたが、問題公開後は様々な会社の社内ISUCONの題材として採用され、上述の書籍でもパフォーマンスチューニングを実践するための環境として活用されています。
社内ISUCONを公開したら広く使われた話 - pixiv inside [archive]
AWS CLIによる構築手順
ここからは、private-isuをAWS上に構築する手順について記載していきます。
前述の通り、private-isuのWebサービス、ベンチマーカーの実行環境はAMIが公開されているので、その周辺のVPC環境を整えるのがメインとなります
基本的なEC2+VPCの知識があれば簡単に構築できるシンプルな環境ですし、既にCloudFormationテンプレートが公開されていますが、個人的なAWSの勉強のためにAWS CLIで作ってみました。
なお、AWS CLIはAWS CloudShellから使っています。ローカルにセキュリティキーを持ってくる必要がないため、安心してAWS CLIを使うことができオススメです。
VPCの設定
最初にVPCを作成します。CIDRの設定については適当で特に何か意図があるわけではありません。
$ aws ec2 create-vpc --cidr-block 172.16.0.0/16
続いて、先ほど作成したVPC内にサブネットを作成します。今回作成するサブネットは1つで、インターネットゲートウェイを設置するいわゆるパブリックサブネットです。
private-isuのWebサービスは、外部から接続できるようにする必要があるためパブリックサブネットが必要ですが、ベンチマーカーはWebサービスへアクセスできれば良いだけなので本来ならばプライベートサブネットに設置した方が良いでしょう。今回は小さな検証環境なので1つのサブネットにまとめてしまいます。
$ aws ec2 create-subnet --vpc-id [作成したVPCのID] \ --cidr-block 172.16.0.0/28 \ --availability-zone ap-northeast-1a
インターネットゲートウェイ(IGW)を作成し、それをVPCにアタッチします。
$ aws ec2 create-internet-gateway $ aws ec2 attach-internet-gateway --internet-gateway-id [作成したIGWのID] \ --vpc-id [作成したVPCのID]
次に、ルートテーブルを作成します。
$ aws ec2 create-route-table --vpc-id [作成したVPCのID]
インターネットとアクセスできるように、デフォルトルート (0.0.0.0/0) をIGWへルーティングするルートを作成します。
$ aws ec2 create-route --route-table-id [作成したルートテーブルのID] \ --destination-cidr-block 0.0.0.0/0 \ --gateway-id <作成したIGWのIDD>
先ほど作成したサブネットでこのルートテーブルが適用されるように紐付けします。
$ aws ec2 associate-route-table --route-table-id [作成したルートテーブルのID] \ --subnet-id [作成したサブネットのID]
さらに、サブネット内でEC2インスタンスが起動されたとき、パブリックIPv4アドレスが自動的に割り振られるように設定します。
$ aws ec2 modify-subnet-attribute --subnet-id [作成したサブネットのID] \ --map-public-ip-on-launch
EC2インスタンスへアクセス可能な IPを制限するために、セキュリティグループ『private-isu-sg』を作成します。
$ aws ec2 create-security-group --vpc-id [作成したVPCのID] \ --group-name "private-isu-sg" \ --description "Security group for private-isu"
まず、SSHでのアクセスを特定のIPからのみ可能なように設定します。 EC2インスタンスへのアクセスは、AWS CLI同様CloudShellを使って行う想定のため、最初CloudShellの実行環境のIPアドレスを確認します。
$ curl https://ifconfig.io
続いて、確認したIPからのみSSHアクセス(ポート22)を許可するように、セキュリティグループへインバウンドルールを追加します。
$ aws ec2 authorize-security-group-ingress \ --group-id [作成したセキュリティグループのID] \ --protocol tcp --port 22 --cidr [CloudShell実行環境のIPアドレス]
また、HTTPでのアクセス(ポート80)も制限します。一般的なWebサービスの場合、基本的にポート80への制限をかけることはありませんが、今回構築するのは負荷試験を実施するための環境であるため制限します。
負荷試験を適切に行うには、どのようなリクエストを実行した際にどのような結果になったかを正確に把握する必要があります。ポート80へのアクセスを制限しなかった場合、世界中から意図しないアクセス(特にボットによるもの)を受け、それが原因で正確な試験結果が得られなくなってしまう可能性があります。
こちらのインバウンドルールについては、現在操作しているPCのIPアドレスのみ許可します。これにより、手元のブラウザからprivate-isuのWebサービスへアクセスすることができます。
$ aws ec2 authorize-security-group-ingress \ --group-id [作成したセキュリティグループのID] \ --protocol tcp --port 80 --cidr [操作しているPCのIPアドレス]
ベンチマークをするには、同じサブネットに存在するベンチマーカーインスタンスから、Webサービスインスタンスへアクセスできるようにする必要があります。そのため、同じサブネット内のプライベートIPからのアクセスを許可するルールも追加します。
$ aws ec2 authorize-security-group-ingress \ --group-id [作成したセキュリティグループのID] \ --protocol -1 --cidr 172.16.0.0/28
EC2インスタンスの作成
EC2インスタンスへCloudShellからSSHでアクセスできるように、PrivateIsuKeyPairというキーペアを作成します。
$ aws ec2 create-key-pair --key-name PrivateIsuKeyPair \ --query 'KeyMaterial' --output text > PrivateIsuKeyPair.pem
作成したキーペアは、以下のように権限設定します。
$ chmod 400 PrivateIsuKeyPair.pem
キーペアの準備が完了したため、最初にWebサービスを実行するEC2インスタンスを作成します。
インスタンスは、公開されているAMIを元に作成します。AMIのIDなどの情報は、private-isuリポジトリのReadMeに書かれています。
GitHub - catatsuy/private-isu: 社内ISUCON
インスタンスタイプについては、推奨されているc6i.largeを使用します。その他、セキュリテイグループなどもあらかじめ作成したものを使用します。
$ aws ec2 run-instances \ --image-id ami-0d92a4724cae6f07b \ --instance-type c6i.large \ --key-name PrivateIsuKeyPair \ --security-group-ids [作成したセキュリティグループのID] \ --subnet-id [作成したサブネットのID]
続いて、ベンチマーカーのインスタンスも作成します。2つのインスタンスに分けているのは、ベンチマーカーの処理によってWebサービスが影響を受けてしまうと、純粋な計測ができなくなってしまうためです。今回は練習環境ですが、実際の負荷試験でも可能な限り本番同等の環境を用意することは重要になります。
こちらも、ReadMeの推奨通りインスタンスタイプはc6i.xlargeを指定しています。Webサービスインスタンスよりも高性能なものを指定しています。
$ aws ec2 run-instances \ --image-id ami-0582a2a7fbe79a30d \ --instance-type c6i.xlarge \ --key-name PrivateIsuKeyPair \ --security-group-ids [作成したセキュリティグループのID] \ --subnet-id [作成したサブネットのID]
ここまでエラーなどなく正常にコマンド実行が完了したら、private-isuの実行環境は準備できました。
private-isu環境の確認
SSHでの接続
2つのEC2インスタンスに正常にSSHでアクセスできるかを確認します。
以下のように、ユーザー名はubuntuを指定します。
$ ssh -i "PrivateIsuKeyPair.pem" ubuntu@[それぞれのインスタンスのパブリックIPアドレス]
Webサービスの内容
Webサービスにブラウザから接続し、正常に動作しているかを確認します。http://[WebサービスインスタンスのパブリックIPアドレス]を開き、以下のようにIscogramというWebサービスの画面が表示されたら正常に動作しています。
httpsではエラーになるためご注意ください。
ベンチマーカーによる計測
ベンチマーカーインスタンスにSSH接続した上で以下のようにコマンドを実行すると、ベンチマークを実行できます。
$ sudo su - isucon $ /home/isucon/private_isu.git/benchmarker/bin/benchmarker \ -u /home/isucon/private_isu.git/benchmarker/userdata \ -t http://[WebサービスインスタンスのプライベートIPアドレス]
ベンチマークでは、様々なリクエストが自動的にWebサービスに対して行われ、その内容を元にした結果が以下のように表示されます。スコアのほか、タイムアウトなどでリクエストが失敗した場合はその情報も表示されます。
{"pass":true,"score":641,"success":579,"fail":2,"messages":["リクエストがタイムアウトしました (POST /login)","リクエストがタイムアウトしました (POST /register)"]}
スコアは、Webサービスへ適切なチューニングを行うことで数十万点以上まで上昇するようです。初期状態ではあえて様々なアンチパターンが実装されているようで、実際のアクセス時もレスポンスがかなり遅く感じます。
ベンチマークでどのようなリクエストが行われるかについては、ドキュメント等で記載は見つかりませんでしたが、GitHubで公開されているベンチマーカーのソースコードからシナリオを見ることができます。単純なページアクセスだけでなく、ログイン試行なども行われることがわかります。
private-isu/benchmarker/scenario.go at master · catatsuy/private-isu · GitHub
まとめ
private-isuの環境をAWS上に構築する手順について書きました。
負荷試験やパフォーマンスチューニングの勉強は、書籍などを読むだけでなく実際に手を動かすことによって学習効率をかなり上げられると思うので、このような練習環境がオープンソースで公開されているのは非常にありがたいことだと思います。