Lock in $30 Savings on PRO—Offer Ends Soon! ⏳

ISUCONに強くなるかもしれない日々の過ごしかた/Findy ISUCON 2024-11-14

ISUCONに強くなるかもしれない日々の過ごしかた/Findy ISUCON 2024-11-14

FUJIWARA Shunichiro

November 13, 2024
Tweet

More Decks by FUJIWARA Shunichiro

Other Decks in Technology

Transcript

  1. 自己紹介 @fujiwara (X, GitHub, Bluesky) 面白法人カヤック SREチーム ISUCON 優勝4回 /

    運営(出題)4 回 github.com/kayac/ecspresso github.com/fujiwara/lambroll
  2. 「ISUCONという競技に慣れるための練習」 競技のルールを理解する 競技をスムーズに実施できるようになる 1. インスタンスを起動してsshで入る 2. GitHubにprivate repoを作ってコードをpush 3. コードを編集

    / commit / デプロイ(再起動) 4. ベンチマークを実行して結果をまとめる …などなど 参加したことがない人は1回はやってください (当日まごつくと単に時間がもったいない)
  3. 全プログラマーが知るべきレイテンシー数 nano sec L1キャッシュ参照 0.5 分岐予測失敗 5 L2キャッシュ参照 7 Mutexのロックとアンロック

    25 メインメモリー参照 100 Zippy[Snappy]による1KBの圧縮 3,000 1Gbpsネットワーク越しに2KBを送信 20,000 メモリーから連続した1MBの領域の読み出し 250,000 同一データセンター内におけるラウンドトリップ 500,000 0.5 msec ディスクシーク 10,000,000 10 msec ディスクから連続した1MBの領域の読み出し 20,000,000 20 msec パケットをカリフォルニア→オランダ→カリフォルニアと送る 150,000,000 150 msec http://norvig.com/21-days.html#answers
  4. ISUCONの場合 # ISUCON13 ruby実装 get '/api/tag' do tag_models = db_transaction

    do |tx| tx.query('SELECT * FROM tags') end json( tags: tag_models.map { |tag_model| { id: tag_model.fetch(:id), name: tag_model.fetch(:name), } }, ) end 「DBにSQLを発行して結果をJSONにしている」のが分かりやすい 実際に発行しているSQLも書いてある
  5. 実際のWebアプリケーションの場合…… @items = current_user.items .is_active .preload(:tags) .page(page).per(per) 見た目ではおそらく…… DBで items

    テーブルをクエリしていそう tags テーブルにもクエリしてそう(preload) でも本当にそうなのかはもっとよく調べないと分からない Redisやメモリにcacheしているかもしれない 外部APIにリクエストを発行しているかもしれない(!!?)
  6. マイクロベンチマークを手癖にする 例:「Goでsliceに要素を追加する場合、先にキャパシティを確保したほうが速い」 func AppendFromEmpty(n int) { var s []int //

    sliceを宣言するだけ for i := 0; i < n; i++ { s = append(s, i) } } func AppendFromPreallocated(n int) { s := make([]int, 0, n) // capacityをn個分確保したslice for i := 0; i < n; i++ { s = append(s, i) } }
  7. Go標準のtestingモジュールでベンチマークができる import "testing" func BenchmarkAppendFromEmpty(b *testing.B) { for i :=

    0; i < b.N; i++ { AppendFromEmpty(10000) } } func BenchmarkAppendFromPreallocated(b *testing.B) { for i := 0; i < b.N; i++ { AppendFromPreallocated(10000) } } $ go test -bench . -benchmem (他の言語でも同じようなものがあります)
  8. $ go test -bench . -benchmem goos: linux goarch: amd64

    pkg: example.com/bench cpu: AMD Ryzen 5 3400G with Radeon Vega Graphics BenchmarkAppendFromEmpty-8 9975 121229 ns/op 357627 B/op 19 allocs/op BenchmarkAppendFromPreallocated-8 43009 27803 ns/op 81920 B/op 1 allocs/op 事前にcapacityを確保する=メモリのアロケートが減る 4倍速い、ことがわかる
  9. 実例: ISUCON 11 優勝の分岐点 Zipを生成してダウンロードさせる機能 初期実装は zip 外部コマンド呼び出し → Go

    の archive/zip で作成するように fujiwara組: zip.Store (非圧縮)を指定してCPUコスト削減 NaruseJun: 圧縮(deflate)したZipを生成 ← 非圧縮だったら逆転していたらしい