この記事は、ニフティグループ Advent Calendar 2023 1日目の記事です。
はじめに
こんにちは。ニフティ株式会社の会員システムグループの上原です。
2023年ニフティグループAdvent Calender1日目に滑り込みの投稿です。
今回は、ISUCONという競技イベントにニフティ社員でチームを組んで参戦したので、そのご報告になります!
ISUCONとは?
ISUCONとは制限時間8時間でお題となるwebアプリケーションを限界まで高速化して性能を競いあうコンテストです。
今年は11/25(土) 10:00-18:00に開催されました。
LINEヤフー株式会社が主催しており、優勝すると100万円を獲得できます。
※ 「ISUCON」は、LINEヤフー株式会社の商標または登録商標です。
チーム「nisucon-bu」のメンバー
- なおき(私)
- アプリケーション・データベースのチューニング・コード内部調査
- 初参加
- yukiex
- 環境構築・インフラ
- たくさん参加している
- mito
- アプリケーション・データベースのチューニング・マニュアル読み込み
- 2回目
お題
ライブ配信サービス「ISUPipe」の高速化
お題に対する所感
- こんいす〜
- 今回のお題は動画配信サービスなのでドメイン知識の理解は辛くない
- スコアはベンチマーカーが配信中に投げ銭をして、どれくらい売上を獲得できたかで決まる
- いつもはエンドポイントの実行結果で決まるが、今回は売上でスコアが決まるので面白いなと思った
- 動画配信をチューニングするかと思って驚いたが、動画配信はチューニング対象外
- 運営が用意したCloudFrontから動画配信されるので、どう頑張ってもチューニングできない
- 最悪ブラウザから動画を見れなくても構わない(らしい)
- リバースプロキシ(nginx) + go(アプリケーション) + データベース(mysql) + DNS(PowerDNS)の構成
- DNS以外はいつも通りの構成
- DNSが選手のサーバー上にあり、ベンチマーク実行中はDNS水責め攻撃が行われる
- いつも通りアプリケーションやデータベースを頑張ってチューニングしても、DNS水責め攻撃を対策しないとスコアが上がらない
- DNS水責め攻撃とは、適当なサブドメインをくっつけてどんどんDNSサーバーに問い合わせることで、DNSをダウンさせる攻撃
- 例えばnifty.comであれば、hogehoge.nifty.comのIPアドレスは?、fugafuga.nifty.comのIPアドレスは?、puipui.nifty.comのIPアドレスは?… とランダムにサブドメインをつけてDNSに問い合わせていく
- DNSサーバーに対するDDoS攻撃
- DNS水責め攻撃とは、適当なサブドメインをくっつけてどんどんDNSサーバーに問い合わせることで、DNSをダウンさせる攻撃
- これまでのISUCONで出てこなかった内容なので、全然対策できていない
- この辺りの知識が必要らしいが、全く知らなかった…
- いつも通りアプリケーションやデータベースを頑張ってチューニングしても、DNS水責め攻撃を対策しないとスコアが上がらない
やったこと
- アイコンの静的配信、トランザクション削除(mito)
- PowerDNS Recursor による水責め対策(TTLを減らす、タイプANYリクエストを抑制)(yukiex)
- 統計(LivestreamStatistics, UserStatistics)のN+1を改善(なおき)
- 【反映せず】icon のハッシュ値をDBに保持(yukiex)
- TAG処理のN+1をIN句に変更、インデックス追加(mito)
- NGワード除去処理を修正、インデックス追加(mito)
- 【反映せず】DNS 用 records テーブルに対するindex追加(なおき)
- Livestream のキャッシュ機構を追加(なおき、mito)
- サーバの分散化(yukiex)
- その他(themes、reservation_slots、livestreams)のインデックス追加(mito)
https://github.com/niftyisucon/isucon13
タイムライン
環境構築、初回ベンチマーク(46分)
- 10:00 ISUCONのポータルサイトに置いてあるCloudFormationのYAMLファイルをダウンロードした後、自分のAWS環境にサーバー構築を行う(なおき)
- 10:00 マニュアルなどを読む(yukiex, mito)
- 10:08 サーバー構築が終わったので、サーバー内のファイルをGit管理にしたり必要なコマンドを導入する(yukiex)
- 10:08 引き続きマニュアルを読む(mito)
- 10:08 データベースのスキーマや実行しているプロセスの調査(なおき)
- 10:12 初回ベンチマークを実行。3757点。
- 10:37 alpとpt-query-digestによるログ解析が完了。
- 10:46 環境構築完了
チューニング
午前
- 10:39 スロークエリに対してインデックスを貼る(mito)
- 11:00 DNS水責め攻撃の対策のため調査(yukiex)
- 11:35 PowerDNS Recursorの導入(yukiex)
- 設定方法とかもChatGPTに聞いたらしいです
- 11:35 PowerDNS Recursorの導入(yukiex)
- 11:00 – 12:00 ブラウザでアプリケーションを触りながらAPIのエンドポイントをまとめていく(なおき)
午後
- 12:00 ユーザーのiconをDBからはがしディスクに保存、nginxで配信するようにする(mito)
- https://github.com/niftyisucon/isucon13/pull/12
- 13:15 nginxの設定に手こずり、苦戦したが完了(mito)
- 6905点
- 12:00 配信のstatisticsエンドポイントで使用しているクエリを変更(なおき)
- https://github.com/niftyisucon/isucon13/pull/16
- https://github.com/niftyisucon/isucon13/pull/19
- 配信の順位や投げ銭の最大値などを返すエンドポイント
- N+1問題でパフォーマンスが落ちていた
- キャッシュさせて回避するか、クエリを変更するかで迷った挙句、yukiexさんからアドバイスを受けクエリを変更することにした
- 13:30 ランキングの順位がバグりまくって大変だったが、ベンチマークの指摘とデータベースの中身をにらめっこしつつ直す(なおき)
- 6422点
- 13:30-14:15 トラブルでベンチマークがうまく動かなくなり、何もできなくなる
- 14:15 iconのハッシュ値をDBに追加(yukiex)
- マージせず
- 15:12 タグのN+1問題を解消、インデックス追加(mito)
- 15:20 ユーザーのstatisticsエンドポイントのN+1問題をクエリを変更して解消(なおき)
- https://github.com/niftyisucon/isucon13/pull/24
- ユーザーの順位などを返すエンドポイント
- こちらもランキングの順位がバグりまくったが、ベンチマークの指摘とデータベースの中身をにらめっこしつつ直す
- 8703点
- 15:30 DNSサーバーのisudnsデータベースのrecordsに対しインデックスを追加したが、スコアが下がったため巻き戻し(なおき)
- インデックスを貼った結果、INSERT UPDATEの時間が悪化したのだと思われる
- 9972点
- 15:35 icon取得にかかっている不要なトランザクションを除去(mito)
- 16:15- サーバーを1台から複数台構成に変更するための準備(yukiex)
- サーバー3台のうち2台を複数台構成に変更するために使用
- 残り1台でアプリケーション・データベースのチューニングを試してみる
- 15:45 ライブ配信で投稿できるコメントのNGワードにインデックスを追加(mito)
- 16:15 ライブ配信で投稿できるコメントのNGワード削除処理を修正(mito)
- https://github.com/niftyisucon/isucon13/pull/34
- NGワードを追加すると過去のコメントも含めて削除する処理になっていた
- N+1問題の解消
- 11795点
- 16:30 – 17:15 配信情報を取得する関数にキャッシュを導入(なおき)
- https://github.com/niftyisucon/isucon13/pull/35
- 自分の書いた章を読みながら実装( NIFTY Tech Book #1:ニフティ執筆部)
- 21743点
- 17:30 インデックス追加(mito)
- https://github.com/niftyisucon/isucon13/pull/40
- 残り時間30分でやったチューニング
- 16449点
終盤(複数台構成に変更、ログ出力停止、再起動試験対策)
- 17:15- 2台構成に変更(yukiex)
- isu1: nginx, app(Go), PowerDNS Recursor, PowerDNS, mysql (PowerDNSのバックエンド)
- isu2: mysql (app)
- 17:45 ログ出力停止(mito)
- 17:49 ベンチマーク実行 25,674点
- 18:00 競技終了
結果
- 661チーム中81位(上位12.04 %)
- スコア 25,674
- 自チームのスコア変動をグラフ化してみると17:00からの伸びがすごい
- 他のチームの状況
- 1位のスコアがすごい(468,006点)
- 2位のスコアと2倍近く差をつけている
うまくできたこと
- 1時間以内に環境構築・準備を終えることができた
- 練習ではごたつくこともあったが、事前準備でなんとかなった
- 練習でやったことは確実にこなすことができた
- N+1問題の解決やキャッシュを入れ込むことができた
- 自分の書いた本のおかげ
- ニフティ社員で執筆した技術総合誌「NIFTY Tech Book #1」のダウンロードよろしくお願いします(宣伝)
- NIFTY Tech Book #1:ニフティ執筆部
- ChatGPTやCopilotを駆使して素早く問題の解決ができた
- AIすごい
- 役割分担がうまくいった
- 自分はゴリゴリコードを直していきつつ、マニュアルを読み込んで仕様を完全理解していたmitoさんに軌道修正してもらいながら、yukiexさんがインフラに手を入れる
- 17:00からグイグイ点数が上がった
反省点
- 個人練を頑張りたい
- 低レベルな技術を理解することは大事
- DNS様
- まだまだやりたいことはあったが、時間が足りなかった。
- 無駄な時間を削ぎ落としたい
- プリペアードステートメントを切ったり、コネクション数を増やすのを忘れた
- 1,2行追加するだけでスコアが上がるのに…
- 次回参加時は手順に入れておく
- 途中ベンチマークが動かないトラブルがあって何もできなかった
- 何も検証できない時でも何をするか決めておく
- ランキングを作る部分はISUCONでよく出てくるなぁと感じたので、Redisを使っていい感じにしたい
- これから練習していって知見をためていく
学び
- GoでDNSを自作できるらしい
- github.com/miekg/dnsというライブラリを使えばいけるらしい
- 実装例 https://gist.github.com/ryotarai/2938ac139c23417da222c1a387415836
- 上位層は当たり前のように知っていて驚き
- discordにGitHubの通知を入れるのは便利
- 他の人が何をやっているのかわかって安心感がある
まとめ
- 自分は初参戦のため普段の練習の力が出せるか不安でしたが、N+1問題を解消したりキャッシュを導入できたので十分成果は出せたのかなと思います。
- ISUCONで初めてDNSの話が出てきたのでギョッとしてしまいましたが、結局基本が大事
- 午後は1万点を超えずになかなか辛い気持ちになっていましたが、17:00からぐんぐん点数が伸びていったので興奮しました。
- 途中、1時間くらいトラブルでベンチマークが実行できず手持ち無沙汰な時間を過ごしたのは残念でしたが、全体的には問題の質が高く楽しく解くことができました。
- 終了後はISUCON13の参加者全員が集まるdiscordで感想ややったことが共有され非常に勉強になりました。
- 次回ISUCONではさらに成長して上位層に食い込めるよう挑戦していきたいと思っています。
8時間という長丁場でパフォーマンスチューニングだけを考え、ひたすらボトルネックを解消していく機会はISUCON以外にはないと思います。皆さんもぜひISUCONに参加してパフォーマンスチューニングを身につけてみてください。
明日は、fu9shimaさんの「【祝10000MAU!】エンジニアブログ運用チームの活動まとめてみた」です。 どんなことをしているか気になりますね!お楽しみに!