kavo’s diary

備忘録

ISUCON練習準備メモ

ISUCONの練習準備

チーム内部向けに、久しぶりにISUCON練習やるとき、諸々の操作を思い出すためのメモ。とりあえず上から順にやっていけば感覚が蘇る・・・はず。

クラウドコンソール
ツール
  • RLoginでログイン
  • VSCodeでRemote Development接続
  • Slack
よく使うaliasを思い出す
0 #ベンチ一式実行
br #vi bash profile
so #source bash profile
sli #サービスリスト
sre #アプリ再起動
アプリ・ベンチ・ログ
  • ブラウザでアプリにアクセス
  • ベンチマークを実行、slackで結果確認
  • ログ出てるか確認
  • ログ分析結果が出てるか確認

メモ

スコアを追っていけるダッシュボード的なのが欲しい

ISUCONのススメの商業版・同人版の違い

サークルFrattyが技術書典9で頒布した「Webサービスチューニングコンテスト ISUCONのススメ」ですが、商業版の出版が決まりました。同人版から内容が増強されており、いくつか違いがあるため本記事にてまとめます。

同人版・商業版の差異は次の表の通りです。

同人版 商業版
販売プラットフォーム 技術書典オンラインマーケット 各種プラットフォーム
媒体 電子版のみ 電子版/印刷版
価格 500円(税込) 電子版1,600円(税別) 印刷版 2,000円(税別) ※1
発売日 2020/09/12 2021/02/05
内容 詳細はこちら 左記にリソースモニタリング、N+1問題・処理並列化・サーバ間リソース分散のトピックを追加
  • ※1 それぞれのプラットフォームのセール等により価格が変化する場合があります。

(参考)目次の差分 f:id:kavohtn:20210202191905j:plain

技術書典9で技術同人誌を出した記録(時間推移、やったこと、ツール選定等)

2020/09/12-22に開催された技術書典9で、チームFrattyとしてWebサービスチューニングコンテスト ISUCONのススメ:Frattyという本を出した。 そのときの時間推移とやったこと、使ったツールや選定理由の記録。

大体3人で1ヵ月で79ページの本を作成・出版した。

技術書典終了後に記念に作った物理本:

タイムライン

  • 6/27 チームのLINEグループで技術書典でISUCONの本出してみない?と言ってみる
  • 7/3 打ち合わせ1 本のネタ出し
  • 7/10 技術書典9の日程(9/12-22)発表、改めてチーム3人で本を出そうと決める
  • 7/18 打ち合わせ2 本のネタ出し
  • 7/25 リポジトリ作成
  • 8/1 技術書典9参加フォーム公開
  • 8/2 打ち合わせ3 チーム名検討、アイコン検討、参加申し込み
  • 8/8 打ち合わせ4 ゆるい目次書き出し
  • 8/10 18:20 技術書典9参加申込審査結果[参加]メール通知
  • 8/11執筆本格開始~
  • 8/21 チームアイコン決定
  • 8/22 打ち合わせ5 目次リファクタ
  • 8/30 打ち合わせ6 タイトル決定
  • 9/4-11 追い込みレビュー
  • 9/8 夜 暫定版入稿
  • 9/9 23:36 暫定版 販売審査[承認]メール通知
  • 9/11 夜 完成版入稿
  • 9/12 0:18 完成版 販売審査[承認]メール通知
  • 9/12 10:00 技術書典9販売開始
  • 9/22 技術書典9終了

データ

  • 執筆期間:8/11~9/11の約1ヵ月
    • A5 表紙込79ページ
    • PDF
    • 電子版のみ
    • 表紙は表表紙のみ(電子版なので)
  • Gitリポジトリ
    • 消化issue:116
    • コミット数: 257
    • ビルド数: 270
    • PR数: 40

コミットグラフ:

f:id:kavohtn:20201011194516p:plain

進め方

f:id:kavohtn:20201011195613p:plain

  • discord打ち合わせでissueを棚卸しする
  • 執筆はPRであげてレビューしてもらう(ただ、実際にはPR上でレビューするというより、先にマージしてから読むことが多かった)

苦労した点

  • 正解がないもの
    • 本タイトル、チーム名、アイコン、表紙デザインなど、なかなか決まらなかった
  • 権利関係
    • 重要だが調べるのが大変
  • 環境整備・インストール
    • ビルド環境、校正ツールあたりでかなりエラー対処に時間食ったが、あまり頑張らず素直に動いてくれるものだけで良かった気がする
  • ハマったこと
    • .gitignoreのpdf除外設定の無効化をミスっていてpdfがpushできていなかった
    • VSCode上でID: constimage1 にマッチする画像が見つかりませんでした。とかエラーメッセージが出てるけどビルドしたら表示されてた

使ったツール・サービス、選択理由など

全体

技術検証

  • Google Cloud Platform
    • バウチャーがあったのと、使い慣れていたので。

文章執筆

  • Re:VIEW Template TechBooster
    • Re:VIEW Starterというテンプレートもあったが、併用はできないことが分かり、どちらを使うか迷った。Re:VIEW Starterは綺麗な装飾が魅力だったが、結局ベースバージョンが新しいRe:VIEW Templateを選んだ。
  • VSCode
    • .reのリアルタイムプレビューができる
    • prhでlintしてくれる
  • GitHub プライベートリポジトリ
    • 今は複数人で使ってもタダ。太っ腹。
  • GitHub Actions
    • 最初はRe:VIEWのビルド環境をWindowsに作ろうとしたがまずdokcerが動かずダメだった。結局はActionsでなんとかなった。pushするたびにビルドしてくれ、2分くらい経つとダウンロードできるようになる。脱稿まで270回(x2分)ビルドしたが無料枠(2000分/月)で収まった。
  • Google docs音声入力
    • 最初のドラフトとか、とりあえず喋って原文を作るのに良かった。口に出すことで整理される効用もある。

校正

prh、redpen、JustRightProなどlintツールを色々試したが、インストールの苦労のわりにそこまで効果があった感じはなかった。後半の方になるとそんな些末なことより・・・という感じになっていく。とりあえずVSCodeにprh extention for VSCodeはさっと入るのでそれくらい入れておけばいい気がする。

表紙作成

Google spreadsheetはフォント追加ができないので、Powerpointで全部やった。PDF出力も可能。画像がはみ出てても削ってくれる。

図作成

ベクタ画像が欲しくて結構苦労した。 最終的なやり方としては、作成途中では仮のpngをおいてしまい、最終工程で一気にepsを作る。画像編集の段階では編集/共有のしやすさからgoogle slideで作り、pptxでエクスポート後、パワポで該当の図形だけを選択→図として保存(png/emf)→Metafile to EPS Converterでeps作成。

今回は使わなかったがvscode拡張で編集できるdraw.io統合もある。

内容議論

広報

  • Twitter
    • チーム用アカウントを作って本の宣伝をした

アンケートフォーム

アイコン

  • hatchful

感想

  • 技術書典運営様のサポートが凄い。新規サークル向けにYouTubeで解説動画を連載したり、チャットサポートがあったり。チャットサポートレスが爆速かつ親身。ありがとうございます。
  • ISUCON運営様が快く許諾を下さったので本が出せました。ありがとうございます。

ISUCON10予選問題の疑似環境をGCP上に作る(初期スコア400前後)

概要

ISUCON10予選をなるべく当時と同じように解きたいので、疑似環境を作るためのメモ。

初期スコアが456だったので、近い値が出るようにしたい。

結論

N1の1vCPU/2GBメモリ、ゾーン永続ディスク20GBで作ったインスタンスでは(ベンチマーカー内包で測って)初期スコア400前後になる。 cloudshellですぐ起動したい場合以下のスクリプトインスタンス作成可能。

gcloud beta compute instances create isucon10q --zone=asia-northeast1-b --machine-type=custom-1-2048 --subnet=default --network-tier=PREMIUM --maintenance-policy=MIGRATE --scopes=https://www.googleapis.com/auth/devstorage.read_only,https://www.googleapis.com/auth/logging.write,https://www.googleapis.com/auth/monitoring.write,https://www.googleapis.com/auth/servicecontrol,https://www.googleapis.com/auth/service.management.readonly,https://www.googleapis.com/auth/trace.append --tags=http-server --image=ubuntu-1804-bionic-v20200923 --image-project=ubuntu-os-cloud --boot-disk-size=20GB --boot-disk-type=pd-standard --boot-disk-device-name=isucon10q --no-shielded-secure-boot --shielded-vtpm --shielded-integrity-monitoring --reservation-affinity=any

サーバスペック

GitHub - isucon/isucon10-qualify: ISUCON10予選より基本スペックは以下の通り。

  • 問題用 (3台)
    • CPU: 1 Core (AMD EPYC 7352)
    • Memory: 2 GiB
    • IO throughput: 100 Mbps
    • IOPS limit: 200 (Read / Write)
    • Interface: 1 Gbps
  • ベンチマーカ用 (1台)
    • CPU: 1 Core (AMD EPYC 7352)
    • Memory: 16 GiB
    • IO throughput: 100 Mbps
    • IOPS limit: 200 (Read / Write)
    • Interface: 100 Mbps

OSはUbuntu 18.04.5 LTSだった。

$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 18.04.5 LTS
Release:        18.04
Codename:       bionic

GCPで再現する

スペック選定

CPU/Memory/Interface

GCPマシンタイプ  |  Compute Engine ドキュメント  |  Google Cloudから似ているスペックの構成を探すと、 共有ではないコアで1vCPUが選べるのが汎用(N1)だけのようである。 汎用(N1)のカスタムで1vCPU2GBにできる。 カスタム時のネットワーク下り(外向き)帯域幅(Gbps)は書いてない気がするが、近いn1-standard-1の帯域幅は2Gbps。

インスタンス自体が1コアでなくても、maxcpus=1を指定する方法もあるらしい。

#「vCPU」と「Core」の対応関係が調べてもいまいちよくわからない

IO throughput/IOPS

Storage options  |  Compute Engine Documentation  |  Google Cloudによると、ゾーン永続ディスクの最大持続 IOPS、最大持続スループット(MB/秒)は

ゾーンバランス永続ディスクの最大持続 IOPS、最大持続スループット(MB/秒)は

らしい。とはいっても、この最大持続 IOPS、最大持続スループットが本番インスタンスのIO throughput/IOPS制限と近い意味の数値なのかは不明。

IOPS(Input/Output Per Second)とは - IT用語辞典 e-Words

装置の特性により、読み込み(リード)か書き込み(ライト)か、シーケンシャルアクセス(連続した領域にアクセス)かランダムアクセス(飛び飛びに様々な領域にアクセス)か、転送するデータの量がどれくらいかによって1回の動作に要する時間が異なる。

このため、実用上は「4KBランダムライトIOPS」のように計測条件を明示することが多い。この例では、4キロバイトのデータを装置内の不連続な箇所に飛び飛びに書き込む動作を行った際のIOPSを表している。

例1:ゾーン永続ディスク20GB

カタログ上以下のはず。

fioを使ってストレージの性能を計測してみた - Qiitaを参考にfioというツールで測ってみる。fioのドキュメントは1. fio - Flexible I/O tester rev. 3.23 — fio 3.23-28-g7064-dirty documentation

IOPS/スループット測定目的×シーケンシャル/ランダム×R/Wの8パターン。

sudo apt update
sudo apt-get install -y fio
head -c 10G /dev/urandom > /tmp/test2g
ls -l /tmp/test2g 

fio -filename=/tmp/test2g -direct=1 -rw=read -bs=4k -size=2G -numjobs=64 -runtime=10 -group_reporting -name=file1           > 1--4k-seq--r.log
fio -filename=/tmp/test2g -direct=1 -rw=write -bs=4k -size=2G -numjobs=64 -runtime=10 -group_reporting -name=file1          > 2--4k-seq--w.log
fio -filename=/tmp/test2g -direct=1 -rw=randread -bs=4k -size=2G -numjobs=64 -runtime=10 -group_reporting -name=file1       > 3--4k-rand-r.log
fio -filename=/tmp/test2g -direct=1 -rw=randwrite -bs=4k -size=2G -numjobs=64 -runtime=10 -group_reporting -name=file1      > 4--4k-rand-w.log
fio -filename=/tmp/test2g -direct=1 -rw=read -bs=32m -size=2G -numjobs=16 -runtime=10 -group_reporting -name=file1          > 5-32m-seq--r.log
fio -filename=/tmp/test2g -direct=1 -rw=write -bs=32m -size=2G -numjobs=16 -runtime=10 -group_reporting -name=file1         > 6-32m-seq--w.log
fio -filename=/tmp/test2g -direct=1 -rw=randread -bs=32m -size=2G -numjobs=16 -runtime=10 -group_reporting -name=file1      > 7-32m-rand-r.log
fio -filename=/tmp/test2g -direct=1 -rw=randwrite -bs=32m -size=2G -numjobs=16 -runtime=10 -group_reporting -name=file1     > 8-32m-rand-w.log

$ grep IOPS *
1--4k-seq--r.log:   read: IOPS=15.0k, BW=58.7MiB/s (61.5MB/s)(3521MiB/60018msec)
2--4k-seq--w.log:  write: IOPS=15.1k, BW=59.1MiB/s (61.9MB/s)(3546MiB/60017msec)
3--4k-rand-r.log:   read: IOPS=145, BW=600KiB/s (614kB/s)(36.2MiB/61714msec)
4--4k-rand-w.log:  write: IOPS=296, BW=1201KiB/s (1230kB/s)(71.4MiB/60849msec)
5-32m-seq--r.log:   read: IOPS=3, BW=111MiB/s (116MB/s)(6688MiB/60238msec)
6-32m-seq--w.log:  write: IOPS=2, BW=71.9MiB/s (75.4MB/s)(4320MiB/60096msec)
7-32m-rand-r.log:   read: IOPS=2, BW=79.9MiB/s (83.8MB/s)(4960MiB/62094msec)
8-32m-rand-w.log:  write: IOPS=0, BW=11.9MiB/s (12.4MB/s)(736MiB/62051msec)

値が多いが、おそらくカタログのIOPSと比べる対象は4KBランダムリードライトの3,4だと思う。R/Wで145/296とカタログから想定した値の10倍くらいになっている。 スループットは32Mのシーケンシャルなのかランダムなのかわからないけどシーケンシャルだとすれば、R/Wで111/71.9MiB/sとカタログから想定した値の30~40倍くらいか。

例2:ゾーンバランス永続ディスク30GB

カタログ上以下のはず。

同様に計測する。

$ grep IOPS *
1--4k-seq--r.log:   read: IOPS=445, BW=1797KiB/s (1840kB/s)(107MiB/60851msec)
2--4k-seq--w.log:  write: IOPS=294, BW=1196KiB/s (1224kB/s)(71.1MiB/60853msec)
3--4k-rand-r.log:   read: IOPS=295, BW=1197KiB/s (1226kB/s)(71.2MiB/60852msec)
4--4k-rand-w.log:  write: IOPS=294, BW=1196KiB/s (1224kB/s)(71.0MiB/60853msec)
5-32m-seq--r.log:   read: IOPS=0, BW=16.9MiB/s (17.7MB/s)(1024MiB/60527msec)
6-32m-seq--w.log:  write: IOPS=0, BW=15.6MiB/s (16.4MB/s)(960MiB/61391msec)
7-32m-rand-r.log:   read: IOPS=0, BW=16.9MiB/s (17.7MB/s)(1024MiB/60515msec)
8-32m-rand-w.log:  write: IOPS=0, BW=15.6MiB/s (16.4MB/s)(960MiB/61404msec)

4KBランダムリードライトの3,4をみるとR/Wで295/294とカタログから想定した値の1.5倍くらいになっている。 32Mランダムリードライトのスループットは、R/Wで16.9/15.6MiB/sとカタログから想定した値の2倍くらい。 RWで揃うのは想定どおりだけど、普通の永続ディスクよりもスループットが下回ったのが想定外だった。単にfio実行パラメータが適切ではないからな気もする。

まあ結局よくわからないのでゾーン永続ディスク20GBで試してスコアを見ることにする。

構築

公式のansibleを使ってみる。普通にaptインストールすると古い2.5.1が入ってしまうので以下のようにする。

$ sudo apt update
$ sudo apt install software-properties-common
$ sudo apt-add-repository --yes --update ppa:ansible/ansible
$ sudo apt install -y ansible
$ ansible --version
ansible 2.9.13
  config file = /etc/ansible/ansible.cfg
  configured module search path = [u'/home/hogehoge/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python2.7/dist-packages/ansible
  executable location = /usr/bin/ansible
  python version = 2.7.17 (default, Jul 20 2020, 15:37:01) [GCC 7.5.0]

Ansible のインストール — Ansible Documentationより

127.0.0.1宛で1回試してみるが、ssh鍵設定していなかったので怒られる。

git clone https://github.com/isucon/isucon10-qualify.git
cd isucon10-qualify/provisioning/ansible
vi inventory/hosts
(127.0.0.1記載)

ansible-playbook allinone.yaml -i inventory/hosts

fatal: [127.0.0.1]: UNREACHABLE! => {"changed": false, "msg": "Failed to connect to the host via ssh: Warning: Permanently added '127.0.0.1' (ECDSA) to the list of known hosts.\r\nno such identity: /home/hogehoge/.ssh/id_rsa: No such file or directory\r\nhogehoge@127.0.0.1: Permission denied (publickey).", "unreachable": true}

鍵追加

touch .ssh/authorized_keys
cat isucon10.pub >> .ssh/authorized_keys
cat .ssh/authorized_keys

chmod 600 .ssh/authorized_keys
ls -l .ssh/authorized_keys

cp isu10 .ssh/id_rsa
chmod 600 .ssh/id_rsa 
ls .ssh/id_rsa -l

#疎通
ssh 34.84.152.xx -i .ssh/id_rsa -l hogehoge

再実行してfailなく完了。 やった後に気づいたけどphpとかrubyのインストールが時間食うので使わないやつは外したほうがよい。

$ ansible-playbook allinone.yaml -i inventory/hosts
...
PLAY RECAP ********************************************************************************************************
127.0.0.1                  : ok=76   changed=72   unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   


Saturday 26 September 2020  22:33:40 +0000 (0:00:05.664)       1:05:45.373 **** 
=============================================================================== 
web-rust : Build Web Application Rust ------------------------------------------------------------------- 1215.58s
langs : Install PHP -------------------------------------------------------------------------------------- 986.44s
langs : Install Ruby v2.7.1 ------------------------------------------------------------------------------ 452.84s
langs : Install perl v5.32.0 ----------------------------------------------------------------------------- 399.46s
langs : Install python v3.8.5 ---------------------------------------------------------------------------- 256.83s
web-perl : Install isuumo.perl Pacakges ------------------------------------------------------------------ 141.91s
common : Install Package(Build) --------------------------------------------------------------------------- 74.59s
web-bootstrap : Build frontend application ---------------------------------------------------------------- 51.67s
web-ruby : Build Web Application ruby --------------------------------------------------------------------- 38.82s
web-bootstrap : Install Package(MYSQL) -------------------------------------------------------------------- 34.19s
web-bootstrap : Make initial data ------------------------------------------------------------------------- 31.82s
web-bootstrap : Install frontend packages ----------------------------------------------------------------- 29.90s
bench : Snapshot isucon10 --------------------------------------------------------------------------------- 25.66s
web-php : Install isuumo.php Pacakges --------------------------------------------------------------------- 20.89s
web-bootstrap : Export frontend application --------------------------------------------------------------- 20.45s
langs : Install Rust -------------------------------------------------------------------------------------- 18.64s
web-deno : Build Web Application deno --------------------------------------------------------------------- 18.59s
web-go : Build Web Application Go ------------------------------------------------------------------------- 14.70s
langs : Install Go 1.14.7 --------------------------------------------------------------------------------- 10.38s
web-python : Install isuumo.python Pacakges ---------------------------------------------------------------- 9.95s

動作確認

インスタンスの外部IPをブラウザで開いてアプリの動作を確認(本番のような転送は不要)。 f:id:kavohtn:20200920045956p:plain

isuconユーザに切り替えてベンチ実行。

su isucon #passはisucon
cd isuumo/bench

$ ./bench --target-url http://localhost
2020/09/26 23:13:24 bench.go:86: === initialize ===
2020/09/26 23:13:27 bench.go:98: === verify ===
2020/09/26 23:13:28 bench.go:108: === validation ===
2020/09/26 23:14:12 load.go:181: 負荷レベルが上昇しました。
2020/09/26 23:14:26 fails.go:105: [client.(*Client).SearchEstatesNazotte] /home/isucon/isuumo/bench/client/webapp.go:367
    message("POST /api/estate/nazotte: リクエストに失敗しました")
[client.(*Client).Do] /home/isucon/isuumo/bench/client/client.go:136
    code(error timeout)
    *url.Error("Post \"http://localhost/api/estate/nazotte\": context deadline exceeded (Client.Timeout exceeded while awaiting headers)")
    *http.httpError("context deadline exceeded (Client.Timeout exceeded while awaiting headers)")
[CallStack]
    [client.(*Client).Do] /home/isucon/isuumo/bench/client/client.go:136
    [client.(*Client).SearchEstatesNazotte] /home/isucon/isuumo/bench/client/webapp.go:361
    [scenario.estateNazotteSearchScenario] /home/isucon/isuumo/bench/scenario/estateNazotteSearchScenario.go:214
    [scenario.runEstateNazotteSearchWorker] /home/isucon/isuumo/bench/scenario/load.go:100
    [runtime.goexit] /home/isucon/local/go/src/runtime/asm_amd64.s:1373
2020/09/26 23:14:28 bench.go:110: 最終的な負荷レベル: 1
{"pass":true,"score":406,"messages":[{"text":"POST /api/estate/nazotte: リクエストに失敗しました (タイムアウトしました)","count":1}],"reason":"OK","language":"go"}

成功。もう少しベンチを実行してブレを確認。

2020/09/26 23:17:05 bench.go:110: 最終的な負荷レベル: 1
{"pass":true,"score":389,"messages":[{"text":"POST /api/estate/nazotte: リクエストに失敗しました (タイムアウトしました)","count":5}],"reason":"OK","language":"go"}

{"pass":true,"score":398,"messages":[{"text":"POST /api/estate/nazotte: リクエストに失敗しました (タイムアウトしました)","count":6}],"reason":"OK","language":"go"}

{"pass":true,"score":389,"messages":[{"text":"POST /api/estate/nazotte: リクエストに失敗しました (タイムアウトしました)","count":3}],"reason":"OK","language":"go"}

大体400前後になった。本番の初回実行が456だったので少し低いが、WSL2上に構築して初期で1310になったときよりはまあ近い感じになったかも。 ベンチとアプリを一緒のサーバに入れてしまってる分は性能が落ちていると思われる。ネットワーク的にも影響あるかもしれない。

ISUCON10予選問題をUbuntu18.04@WSL2(Windows 10 Home)で動かすまでのメモ、トラブルシュート集

ISUCON10予選問題をUbuntu18@WSL2(Windows 10 Home)で動かしたときのメモ。末尾にトラブルシュートもまとめた。

環境

大体は2020/09/19の最新バージョン。

  • ホストOS側(Windows)
    • Windows 10 Home 2004 19041.508
    • WSL2
    • Docker desktop 2.3.0.5 (48029)
  • ゲストOS側(Ubuntu)
    • Ubuntu 18.04.5 LTS
    • Docker-compose 1.27.3
    • Go 1.15.2

ソース

github.com

ゴール

WSL2のUbuntu上でdocker-composeでアプリを立ち上げ、ブラウザでWebアプリ画面を確認し、ベンチマーカーでスコアを出す。

手順

基本的にGitHub - isucon/isucon10-qualify: ISUCON10予選の「問題の起動方法」を中心に色々設定を挟む形になっている。

WSL2インストール

WSL2はWindows 10 バージョン2004に含まれる。 Windows 10 バージョン2004の更新配布は段階的に行われているらしく、私のPCではまだ来ていなかった。 ただ、手動インストールは可能で、少し不安はあったがやってみた(結果問題なく動作した)。 大体以下を参考にすればOK。Ubuntuは本番と同じ18.04を選ぶ。

WSL2導入|WinアップデートからWSL2を既定にするまでのスクショ - Qiita

Install Docker Desktop

Windows 10 Home で WSL 2 + Docker を使う - Qiita

docker-composeをインストール

Install Docker Compose | Docker Documentationを参考にインストール。

$ sudo curl -L "https://github.com/docker/compose/releases/download/1.27.3/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
$ sudo chmod +x /usr/local/bin/docker-compose

再起動しないとパスが通らなかった。PowerShellからシャットダウン(自動再起動する)。

PS> wsl -t Ubuntu-18.04

またコンソールを開く。

$ docker-compose --version
docker-compose version 1.27.3, build 4092ae5d

クローン、諸々インストール、パス設定

$ git clone https://github.com/isucon/isucon10-qualify.git
$ sudo apt install -y gcc make python3-pip
$ pip3 install -r requirements.txt

golangはaptでは入れない。aptだと1.10が入ってしまうが、使用するライブラリwaytが1.13以上を必要とするため、最新版を手動で入れる。

$ wget https://golang.org/dl/go1.15.2.linux-amd64.tar.gz
$ sudo tar -xvf go1.15.2.linux-amd64.tar.gz
$ sudo mv go /usr/local

wgetが進まない場合、後述の # ホストNWとゲストNWのMTU値が一致していないとダウンロードがタイムアウトすることがある 参照。

Goの環境変数を設定する。.profileにexportを追加する。

$ vi ~/.profile
export GOROOT=/usr/local/go
export GOPATH=~
export PATH=$GOROOT/bin:/usr/local/go/bin:$GOPATH/go/bin:$PATH
$ source ~/.profile

$ go version
go version go1.15.2 linux/amd64

ライブラリインストール。

$ go get github.com/orisano/wayt
$ wayt
wayt: subcommand is required:
Available SubCommands:
...

sudoでgo,waytが実行できるようにsudoパスを設定(makeで必要)

$ sudo visudo

Defaults secure_pathにパスを書き足す。 /home/koのところは自分の設定に合わせる。

Defaults secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin:/home/ko/bin:/usr/local/go/bin"

動作確認

$ sudo go version
$ sudo wayt
wayt: subcommand is required:
Available SubCommands:
...

docker-composeのためにPATHに docker-credential-desktop.exeのあるディレクトリを追加し、~/.docker/config.jsonを一度削除しておく(これをしないと認識してくれないことがある)。

echo 'export PATH="$PATH:/mnt/c/Program Files/Docker/Docker/resources/bin:/mnt/c/ProgramData/DockerDesktop/version-bin"' >> ~/.profile
tail ~/.profile
source ~/.profile

rm ~/.docker/config.json

初期データの生成

$ cd isucon10-qualify/initial-data
$ sudo make

エラーなく終わればOK。

  • Windows側でdocker desktopがrunningになっていること。タスクトレイアイコンから状態が分かる。
  • Ubuntu側で3306ポートを使っていないこと。既存のmysqlがあったりする場合停止する。
  • ERROR: error pulling image configuration: unexpected EOFが出て止まった場合、とりあえずもう何回か試すとよい。

問題サーバーを立ち上げ

$ cd isucon10-qualify/webapp/
make isuumo/go
(そのままログtail状態へ)

アプリをブラウザで確認

Microsoft Storeから起動してもう1つ窓を開く。

f:id:kavohtn:20200920050014p:plain

IPを確認する。

$ ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1454
inet xxx.xxx.xxx.xxx netmask 255.255.240.0 broadcast 172.yyy.yyy.yyy
...

PowerShellで先程確認したxxx.xxx.xxx.xxxへポートフォワーディング を行う。Connection resetと出ることがあるがその後も転送は続いている。この手順は ISUCON10 予選マニュアル · GitHubによる。

PS C:\WINDOWS\system32> ssh localhost -L localhost:8080:xxx.xxx.xxx.xxx:80 -N
kex_exchange_identification: read: Connection reset
PS C:\WINDOWS\system32>

ブラウザで http://localhost:8080/ にアクセスし、ISUUMOの画面が見えればOK。 f:id:kavohtn:20200920045956p:plain

ベンチマークを実行

ビルドして実行し、スコアが出れば完了。

$ cd ~/isucon10-qualify/bench
$ sudo make
$ ./bench
...
2020/09/20 02:32:04 bench.go:110: 最終的な負荷レベル: 8
{"pass":true,"score":1310,"messages":[{"text":"POST /api/estate/nazotte: リクエストに失敗しました (タイムアウトしました)","count":40}],"reason":"OK","language":"go"}

トラブルシュート

docker desktopが起動していないとdocker-composeがFileNotFoundErrorで終了する

docker desktopを起動してもう一度やってみる。docker desktopはタスクトレイアイコンから状態が分かる。

$ sudo make
...
docker-compose -f ../webapp/docker-compose/go.yaml down -v
Traceback (most recent call last):
  File "urllib3/connectionpool.py", line 677, in urlopen
  File "urllib3/connectionpool.py", line 392, in _make_request
  File "http/client.py", line 1252, in request
  File "http/client.py", line 1298, in _send_request
  File "http/client.py", line 1247, in endheaders
  File "http/client.py", line 1026, in _send_output
  File "http/client.py", line 966, in send
  File "docker/transport/unixconn.py", line 43, in connect
FileNotFoundError: [Errno 2] No such file or directory
...

参考: During startup check that docker is running · Issue #774 · jupyterhub/repo2docker · GitHub

docker-composeがdocker.credentials.errors.InitializationErrorで終了する

PATHに docker-credential-desktop.exeのあるディレクトリを追加し、また、それでも上手く行かない場合は~/.docker/config.jsonを一度削除する。

$ sudo make
...
Traceback (most recent call last):
  File "bin/docker-compose", line 3, in <module>
  File "compose/cli/main.py", line 67, in main
  File "compose/cli/main.py", line 126, in perform_command
  File "compose/cli/main.py", line 1070, in up
  File "compose/cli/main.py", line 1066, in up
  File "compose/project.py", line 615, in up
  File "compose/service.py", line 356, in ensure_image_exists
  File "compose/service.py", line 1267, in pull
  File "compose/progress_stream.py", line 99, in get_digest_from_pull
  File "compose/service.py", line 1234, in _do_pull
  File "docker/api/image.py", line 396, in pull
  File "docker/auth.py", line 48, in get_config_header
  File "docker/auth.py", line 324, in resolve_authconfig
  File "docker/auth.py", line 235, in resolve_authconfig
  File "docker/auth.py", line 262, in _resolve_authconfig_credstore
  File "docker/auth.py", line 287, in _get_store_instance
  File "docker/credentials/store.py", line 25, in __init__
docker.credentials.errors.InitializationError: docker-credential-desktop.exe not installed or not available in PATH
[7239] Failed to execute script docker-compose
Makefile:22: recipe for target 'verification_data' failed
make: *** [verification_data] Error 255

参考: WSL2上のdocker-composeで認証エラー - roy-n-roy メモ `docker-compose up` fails in WSL 2 environment · Issue #7495 · docker/compose · GitHub

ホストNWとゲストNWのMTU値が一致していないとダウンロードがタイムアウトすることがある

ホスト側でPowerShellでMTUを確認。この場合1454。

PS C:\WINDOWS\system32> netsh interface ipv4 show subinterface

   MTU  MediaSenseState  受信バイト   送信バイト  インターフェイス
------  ---------------  -----------  ----------  -----------------
...
  1454                1  159585932    7359736  ブロードバンド接続
...

ゲスト側でMTUを確認。元がいくつだったか取りそこねた。ゲスト側も1454に合わせて、何かwgetしてみる。ダウンロードが成功すればOK.

$ ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1xxx
...

$ sudo ip link set eth0 mtu 1454

$ ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1454
...

$ wget https://golang.org/dl/go1.15.2.linux-amd64.tar.gz

参考: WSL2 fails to make HTTPS connection if Windows is using VPN · Issue #4698 · microsoft/WSL · GitHub

waytのコマンドが通らない

バイナリが存在するか、PATHにそのフォルダが入っているか、.profileに書いたパスは正確か、.profileを読み込んだか、sudo実行時はsudoにPATH等が継承されているかを確認する。

$ find / -name wayt 2>/dev/null
/home/ko/src/github.com/orisano/wayt
/home/ko/go/src/github.com/orisano/wayt
/home/ko/bin/wayt

$ env|grep GO

$ cat ~/.profile

$ source ~/.profile

$ sudo visudo

$ wayt

$ sudo wayt

go get github.com/orisano/waytが上手く行かない

-u -vをつけてログを出してみる。TLS handshake timeoutしてるようなら上記のMTUのトラブルシュートを試す。

$ go get -u -v  github.com/orisano/wayt

...
package google.golang.org/grpc: unrecognized import path "google.golang.org/grpc": https fetch: Get "https://google.golang.org/grpc?go-get=1": net/http: TLS handshake timeout
...

../../go/src/github.com/orisano/wayt/http.go:45:14: undefined: http.NewRequestWithContextが出てるようなら使っているgoのバージョンが古いので上げる。

技術書典9でISUCONの初心者向け性能改善プロセス解説本を出しました

技術書典9にて、サークルFratty(@team_fratty)として「Webサービスチューニングコンテスト ISUCONのススメ ~初心者向けに環境構築から 計測・改善まで解説する本~」を出しました。技術書典のページは文字数・画像枚数に制限があるため、本記事で+αの内容を紹介します。以下は本書の表紙です。

f:id:kavohtn:20200918025748p:plain:w250

基本情報

概要

性能改善ができるエンジニアになりたい人へ ISUCONに参加しよう!

ISUCONとは、LINE株式会社が運営窓口となって毎年開催している「お題となるWebサービスを決められたレギュレーションの中で限界まで高速化を図るチューニングバトル」です。数百チームの参加者が一斉に、朝から晩まで、同じWebサービスのチューニングに取り組み、性能の高さを競います。6年間毎年参加し続け、同人誌を書いてしまうくらい楽しいコンテストです!参加者がもっと増えたらと思い、これまであまり見かけなかった、ボトルネックを発見・修正するまでの観察や思考の流れを解説する本を書きました。本書がISUCONをより楽しむきっかけになったり、ISUCONや性能改善がうまくなりたいと思う方の役に立つことを期待しています。

【内容】

本書ではISUCON9予選問題(2019年)を題材にしています。 練習用の環境構築からWebサービスの性能計測、修正とその結果評価までを具体的な手順とともに解説します。 本書を読むことで性能改善のプロセスが身に付き、ISUCONでの動き方が分かります。 コマンドやスニペットはコピペできるようにGitHubで公開しています。

https://github.com/team-fratty/rec4isucon

【想定読者】

  • Webサービスの性能改善ができるようになりたい」
  • 「ISUCONに参加してみたいが、どのように勉強すればよいか分からない」
  • 「ISUCONに参加したが、何をすればよいか分からなかった」

という方を想定読者としています。 また、Linux OSの基本的な操作を前提知識としています。

【環境等】

本書の作業手順は次の環境で書かれています。

  • 作業用ローカルPCのOS:Windows
  • 構築するサーバのインフラ:Google Cloud Platform
  • 構築するWebサービスの言語:Go

目次

f:id:kavohtn:20200918032233p:plainf:id:kavohtn:20200918032238p:plain

本文紹介

本書のメインである環境構築、性能改善:計測・修正を抜粋して紹介します。

第3章 環境構築

第3章ではISUCON9予選問題を題材に、GCP上で練習用サーバを構築する方法を解説しています。

f:id:kavohtn:20200918035956p:plainf:id:kavohtn:20200918040016p:plainf:id:kavohtn:20200918040026p:plain

第4章 性能改善:計測

第4章:計測の節では、リクエスト単位・処理ブロック単位・SQL単位での計測と、ボトルネックを特定する流れを解説します。

f:id:kavohtn:20200918040112j:plainf:id:kavohtn:20200918040115j:plainf:id:kavohtn:20200918040121j:plain

第4章 性能改善:修正

第4章:修正の節では、計測結果からWebサービスの修正内容を導出し、修正→再計測→効果測定を行う性能改善のプロセスを解説します。

f:id:kavohtn:20200918040148j:plainf:id:kavohtn:20200918040153j:plain

以上、ISUCONのススメの紹介でした。

ISUCON10予選参加記録

ISUCON10参加してきました。 結果287位で敗退でした・・・。めっちゃ悔しい。どう考えれば解けていたのか分析して来年リベンジしたい。

ISUCON10 オンライン予選 全てのチームのスコア(参考値) : ISUCON公式Blog

607 Fratty

タイムライン

  • 12:20 開始
  • プロキシの書き方が上手く行かず、SSH接続に時間を取られる
  • とりあえずVSCodeでつなぐことに成功、計測用設定を仕込み始める
  • 13:48 練習用に作っていたUbuntuからsshでRLoginでアクセス成功
    • ssh -L localhost:8080:10.xxx.x.xxx:80 isucon-server3
  • 14:11 alpでリクエスト単位の結果初回取得
  • 14:19 処理単位、スロークエリ集計初回取得
  • とりあえずインデックスを貼る→そんなに変わらず
  • 15:32 なぞってのN+1解消を考える→諦める
  • ishihrがなぞってのN+1解消に取り掛かるが、レスポンス不正で通らず
  • サーバ負荷分散に取り掛かり始める。1,2号機で分散してみるが、ほぼ変わらず→アプリ以外の所ネックか
  • DBでリソースサチってるんじゃないかと推測し(NG)、1,2,3号機で3号機をDBのみにし、1,2で分散して3号機に繋がせた。ほぼ変わらず。
  • BOTの排除をnginxのルーティングでやる
  • レスポンス不正が最後まで治らず、切り戻して最終計測

反省

とりあえずそもそもの力不足は棚に上げると、いくらでもあるが、、、

  • アプリ修正にもっとリソースを割くべきだった気がする
  • VSCodeのGo拡張機能が動かなかった→練習の時点で発生していたので原因解明しておけばよかった
  • アプリ書き換えの準備不足 リクエスト・レスポンスの常時出力とかしておくべきだった
  • リソースモニタリングしてない。サーバ負荷分散して効かなかったとき、そこを見るべきだった(推測するな計測せよ)

絶対ISUCON11やってほしい、、、