その手の平は尻もつかめるさ

ギジュツ的な事をメーンで書く予定です

ISUCON 9 決勝を AWS 環境に本番さながらに構築するメモ

github.com

今日 (2020-09-24) の時点では「ローカル環境」で動かす方法については記載がある一方で,何らかのリモートの環境に「本番」っぽく動かす方法についての記載が無いので,それを AWS 上に構築するためのメモを記します.

競技用 application のデプロイ

isucon.net

これを見る限り,参加者側の環境は以下の通り:

アリババクラウドさんの ecs.sn1ne.large を採用しました。
CPUは2コア (Intel(R) Xeon(R) CPU E5-2682 v4 @ 2.50GHz)、メモリは4GBの、オーバーコミットのないインスタンスです。ネットワーク帯域も100Mbpsです。

ただし、今回のアプリケーションではメモリに全ての切らない環境を再現するために、Linuxにはメモリを1GBしか認識させていません。CPUは2コアで、メモリ1GBの環境を再現しています。
参加者にはこちらのインスタンスを3台提供しました。
デプロイには Docker Compose を採用しており、ホストのUbuntu 18.04にはDockerとNginxのみをインストールしています。

AWS で言うところの c5.large で良さそうに見えます.
c5.large だとメモリが 4GB なのでメモリを絞る必要がありそうですが,コレは大丈夫でした (後述).

application のセットアップについては普通に userplaybook 流したら動きました (ansibleのバージョンによっては細々手直しする必要はありそう,実際あります).

前述したメモリの量については ulimit かなんかで素朴に制限かけるかな〜と思っていたところ,playbook がいい感じで /etc/default/grub を以下のように (mem=1G) 書き換えて制限してくれたので問題ありませんでした *1.ただし reboot が必須.

...
GRUB_CMDLINE_LINUX=" net.ifnames=0 vga=792 console=tty0 console=ttyS0,115200n8 noibrs mem=1G"
...

「ハーンなるほど,それであればこの mem=1G を外して reboot すればフルでメモリ使えるから優勝だな? ガッハッハ!!」と悪巧みをしていたところ,それは以下のレギュレーション項目によって潰されていたのでズル不能でした.しっかりしていますね.

OSのメモリサイズが提供時と同じ状態であること

帯域幅については「ネットワーク帯域も100Mbps」とのことで制限が必要そうなのでこれは tc によって行いました *2

tc qdisc add dev ens5 root tbf rate 100mbit burst 50kb limit 500kb

これを手っ取り早く /etc/rc.local にでも書いておくと再起動しても適用されるので便利ですね.

ところでこの素朴な tc による帯域制御は egress にしか適用されないので,ingress にも適用しようとすると若干工夫をする必要があります.まあちょっと頑張って ingress にも適用できるスクリプトを書くか〜と思ったのですが,冷静に考えるとベンチマーカーと外部 APIインスタンスの egress にも帯域制限を適用すれば,とりあえず通る経路が一通り 100Mbps に制限されるのでそれで良しとしました.

あと TLS 対応しているのでなんとかする必要があるのですが……これについては諦めました. HTTP:80 で listen させるようにして,ベンチマーカーにはネットワーク内の private IP を参照してもらうようにしました.

ベンチマーカーと外部 API のデプロイ

ISUCON 9 のベンチマーカーおよび外部 API の動作環境についての記載がなかったので,代わりに ISUCON 8 決勝の環境を参照しました:

ベンチマーカー x 1
 - CPU 3コア : Intel(R) Xeon(R) CPU E5-2640 v4 @ 2.40GHz
 - メモリ 2GB
 - ネットワーク帯域 1Gbps
 - ディスク SSD
外部API x 1
 - vCPU 3コア : Intel(R) Xeon(R) CPU E5-2640 v4 @ 2.40GHz
 - メモリ 2GB
 - ネットワーク帯域 1Gbps
 - ディスク SSD

ISUCON 9 決勝の環境と大差なさそうだったので,ひとまずコレに従うことにしましょう.パッと見 c5.xlarge で良さそう.
メモリはgrubで絞れば良いとして,vCPUは……まあ良いかということで放置.あと tc は application と同様に適用する.

セットアップについては bench playbook を流し込めばOK.

こちらについても TLS 証明書を用意してあげる必要があり,まあ application と同じく平文でやっても良いか……と思ったのですが,なぜか気分が乗ったので certbot + nginx で乗り切りました (手動オペレーション,この辺読みながらやった: How To Secure Nginx with Let's Encrypt on Ubuntu 20.04 | DigitalOcean).




とりあえずコレで動きます.1GB しかメモリがないので mysqlinnodb_buffer_pool とかを潤沢に使うとインスタンスごとポシャったりして大変でした(なお潤沢に使わなくてもポシャる).swap が無いことに起因する話題な気がする.大変でしたね.

*1:それはそうとしてgrub書き換えてくるansible,良いですね……ちょい怖!

*2:本番は tc ではなかったでしょうが