MF KESSAI開発合宿運営のgarsueです。 前回に引き続き、チーム対抗パフォーマンス改善合宿の様子をお送りします。
今回は結果編として、実際にどういう改善が行われたかをお伝えします。
パフォーマンス改善サイクル
合宿でパフォーマンス改善に取り組む前日、GoogleでCloud Profilerをご担当なさってる山口(ymotongpoo)さんのご協力のもと、Cloud Profilerのハンズオンを実施していただきました。 ハンズオンの概要についてはチーム対抗パフォーマンス改善合宿 準備編をご覧ください。
そのおかげで「プロファイルを取る」「ボトルネックを見つける」「改善に向けて改修する」「実際に改善できたか再度プロファイラーで確認する」というパフォーマンス改善サイクルを各メンバーが身についていました。
このサイクルのなかで見つけたボトルネックと、実際に効果のあった改善について紹介していきます。
目立ったボトルネック
ぼかしているのであまり参考にならないですがCloud Profiler上で見た実際のフレームグラフはこのようになっています。
ぼかしを入れたあたりからアプリケーションロジックのスタックが表示されています。
これらの中から比較的多くのCPU時間やヒープなどのリソースを消費している関数、すなわちフレームグラフ上で広く幅をとっている関数がボトルネックになっている可能性が高いです。 それらを中心に改善を試みていきました。
視覚的に目立つ形でボトルネックになっている関数が見つかるのでとにかく便利です。
改善アプローチ
各チームとも具体的な改善のアプローチは概ね以下のようなパターンになりました。
キャッシュする
まず単純で効果的なアプローチとして、時間がかかっている関数の結果をキャッシュしてしまう方法があります。キャッシュが使われるようになれば関数呼び出しがまるごとなくなるので改善に繋がります。
ただし、大抵それらの関数はデータベース・外部サービスからのデータ取得などの副作用があるので、キャッシュして良いかどうかは注意して検討しましょう。
特定の条件下でしか使わない関数の呼び出しを後回しにする
エラー時にのみ行う追加データの取得をエラー発生前に行っていたため、エラーが起きなかった場合には不要なデータ取得になっているところがありました。
このような呼び出し結果を必ずしも使わないところを見つけだして後回しにするのも改善に繋がりました。
O/Rマッパーの使用やめる
今回の改善対象のアプリケーションではO/RマッパーとしてGORMを使用していました。Go界隈では比較的メジャーで当社でもサービス開始当初より複数のサービスで採用しています。
ただGORMが行っているレコードのシリアライズ・デシリアライズにそれなりのコストが掛かっていることがCloud Profiler上で見て取れました。
そこでパフォーマンスが求められる箇所ではGORMを経由せず、database/sql
パッケージを使用することでそれらのコストを回避しました。
結果
合宿中のパフォーマンス推移は以下のようになりました(前回掲載した可視化画像の再掲です)。
チームごとにそれぞれ系統(折れ線など)を分けて表示しています。「satisfaction」「growth」「buyer」などがチーム名です。
上半分のスコアについてパフォーマンスを抽象化した数値なので詳細は省きますが、高いほど改善されていることを示していて、全体的に上昇トレンドになっています。
わかりやすいのは左下の秒間リクエスト数です。具体的な数値は都合により伏せていますがざっくり2.5倍くらい上がっています。 これは途中で計測時の負荷が足りなくなったので負荷自体を上げたことが影響しています。 言い換えれば負荷が足りなくなるくらい改善されたということでもあります。
1日でここまで改善できたのは自分たちのことながら驚異的です。 もともと改善の余地がかなりあったというのもありますが、それを差し引いてもかなりの成果だと思います。
まとめ
以上、3回に渡ってお送りしてきたチーム対抗パフォーマンス改善合宿のレポートでした。
参加したメンバーからもCloud Profilerの使い方が身につき、さらに競い合って楽しめたとのフィードバックをもらっています。
リアルな成果も出すことができたので運営側としても大変満足しています。
フルリモートでも充実した開発合宿を行えることがわかったので、まだまだ開発合宿は続けていこうと思います。