バックエンドの取り組み「パフォーマンス改善チャレンジ」について
こんにちは!
株式会社ココナラプロダクト開発部バックエンド開発グループでエンジニアをしておりますぴろと申します。
休日は猫🐈お寿司🍣ギター🎸を生きがいにしています。
そんな私が今回はバックエンド開発グループで行っている取り組みの一つの「パフォーマンス改善チャレンジ」について紹介出来ればと思います。
目的
"パフォーマンス改善"と"技術継承"を目的に実施しました。
ココナラは2012年からサービスを運営しており、会員登録数314万人、出品数は71万件に及びます。
長期間の運営、多くのデータ量、それによるパフォーマンスの低下。これらは運営していく上で常に課題に挙がっていました。
また、会社規模も大きくなり新しい人が増えていく中で、上記の課題を解消出来るベテランメンバーのみに頼り続ける状況もよくないと思い、実施に至りました。
問題
パフォーマンス改善には知識と経験、両方が必要と考えており、かつコードの改修か、仕様の調整か、データベースのインデックスの張替えか等、対応方針も実現性とあわせて考える必要があると思います。
そうした中でバランスを取った最適解を今まではベテランメンバーが出し対応を行っていましたが、若手のメンバーがその中に入る機会が少なく、技術継承がしにくかった部分がありました。
そこで、この取り組みの目的である生きた題材を元に学習機会と実戦経験を積んでもらい、技術継承を出来る場を設定しました。
どのような取り組みか
開催は隔週で、参加メンバーはパフォーマンスチューニングに興味のある若手、または業務での経験があまりなかった人が中心で、ベテランのエンジニアもまとめ役として1,2名参加します。
ココナラでは様々なツールでパフォーマンスのモニタリングを行っており、その中で検出されたスロークエリやレスポンスの遅いAPIを対象にブレストの様な形で議論を行います。
議論の結果、ロジックを改修する、データベースのインデックスを修正する、など方針を決めてベテランのメンバーにレビューをしてもらいます。
インデックス修正の際にはどのインデックスが適切かを比較するために本番のデータ分布を再現し、ローカル環境で複数のパターンをテストするケースもあります。
対応方針のレビューまで終わると一旦パフォーマンス改善チャレンジとしては完了となります。
実際のロジック改修、インデックスの修正を本番に反映するのは別タスクとして運用の中で行っていきます。
以下が実際の流れになります
実際に改善を行った例
※ カラム名、テーブル名など濁してあるので実際の挙動とは異なるかもしれないです。。あくまでイメージとして考えていただければ
Before
実行計画
id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
---|---|---|---|---|---|---|---|---|---|---|---|
1 | SIMPLE | <subquery2> | null | ALL | null | null | null | null | null | 100 | Using where; Using temporary; Using filesort |
1 | SIMPLE | table_a | null | ref | PRIMARY,idx_1,idx_2,idx_3 | idx_1 | 5 | <subquery2>table_a.id | 7 | 25 | Using where; Using index |
2 | MATERIALIZED | table_b | null | ref | idx_1,idx_2,idx_3 | idx_2 | 4 | const | 42122 | 100 | null |
rows retrieved starting from 1 in 16 s 819 ms (execution: 16 s 546 ms, fetching: 273 ms)
集計クエリなので重いですね。
以下、おおまかな議論の内容です
- クエリにIN句があり、そこでパフォーマンスが出ていないようなので別のクエリにしたらどうか?
- 一旦上記のように別クエリにしたが、同等のフィルタがサブクエリ内で出来そうだったのでオーバーヘッドを考慮して1つのクエリに戻す
- beforeとafterで実計測。
- explainを見る
- type=ALLだったものがtype=refになった
- eq_refはjoinしたことにより発生。primayなので問題なしと判断
- 実際の実行時間でも改善が見られた
After
実行計画
id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
---|---|---|---|---|---|---|---|---|---|---|---|
1 | SIMPLE | table_b | null | ref | idx_1,idx_2,idx_3 | idx_2 | 4 | const | 42122 | 100 | Using where; Using temporary; Using filesort; Start temporary |
1 | SIMPLE | dmr | null | eq_ref | PRIMARY | PRIMARY | 4 | table_a.id | 1 | 100 | Using index |
1 | SIMPLE | table_a | null | ref | PRIMARY,idx_1,idx_2,idx_3 | idx_1 | 5 | table_a.id | 7 | 25 | Using where; Using index; End temporary |
rows retrieved starting from 1 in 3 s 445 ms (execution: 3 s 380 ms, fetching: 65 ms)
まだ早いとは全然言えないですが、5分の1くらいの実行時間になりました。
まとめ
実際にパフォーマンスの問題にアサインされたメンバーはこの取り組みを元に自身で改善策を提案できるようになったり、ココナラでの新しい施策の設計、コーディング等ではパフォーマンスを意識出来るメンバーが増えてきたと思います。
現在は4名ほどで行っていますが、このメンバーも定期的に入れ替えを行い、常に学びのある会にしようと考えています。
さいごに
私たちココナラでは、一緒にサービスを盛り上げていく仲間を募集しています。
パフォーマンス改善チャレンジ以外にも日々開発、改善など様々な取り組みをやっています。
もし興味をお持ちいただけましたら、カジュアル面談にお越しください。
また、募集求人については以下のリンクからご確認いただけます。
Discussion