私をご存知の方は知っているでしょうが、私はいつも高速に動作するコードかどうか気にしています。
最近、簡単なクエリーを実行したところ、1つのタスクに年間16万ドル近く費やしていることが判明しました。
幸運なことに、私たちは3月にメトリクス・ベータを立ち上げました。
ここ1ヶ月ほど10人のSentryエンジニアは、カスタム・データ・ポイントを追跡するためにMetricsを活用し、この無駄なインジェスト・コストにつながる問題を突き止めるために、多くの機能にわたって協力しました。
解決すべき重要な問題の特定
save_event_transaction
私はSentryのSearch and Ingestチームにいます。
同僚のJernej Strasnerと私は、Sentryのインジェストパイプラインを最適化できるかどうかを調べたいと思いました。最近のクエリで、save_event_transaction タスクに週に6,000ドル近く費やしていることがわかりました。
パフォーマンスとメトリクスが、どのように問題特定に役立ったか
これはMetricsの完璧なユースケースだと思いました。
このタスクの計算時間を可視化するためにMetricsをセットアップしたところ、save_event_transaction タスクに過去7日間で1.37週間の計算を費やしたことがわかりました。
save_event_transationタスクから始めるべきだということがわかったので、このオーバーヘッドを減らす方法を特定するために、発見の旅に出ました。
トレース・ビューは、どの関数が最大の違反者であるかのヒントを与えてくれました。下のスクリーンショットでわかるように、この特定のトレースでは 8.00s秒のうち7.37s秒がset_subkeysに費やされていることが分かります。
set_subkeys 関数はmemcachedを通してキャッシュを設定し、私たちのインフラストラクチャで重要な役割を果たしている。
この時点で、 set_subkeysの実際の影響を突き止めたいと思いました。
そこで、Metricsを使用して、抽出されたトランザクションとスパンのメトリクスをプロットし、save_event_transaction. に関連してset_subkeysが費やす時間の割合を得ました。実際には、インジェストされたトランザクションごとに、最小で27%、最大で81%をキャッシュの設定に費やしていることになります。
要約すると、トランザクションの処理時間の平均51%をキャッシュの設定に費やしているということです。
財務用語で言えば、私たちはキャッシュの設定に1週間あたりおよそ3060ドル(年間16万ドル)を費やしていることになります。
セーブイベントからSentryを保存する
save_event_transaction:によって引き起こされる時間(とお金)のコストを削減するのに役立つ、Metricsの助けを借りて特定した主な方法は4つありました。
- キャッシュを設定するタイミングを慎重にする。
- memcacheサーバー間のトラフィックのバランス配分を改善する。
- サードパーティツールのバックグラウンドスレッドを有効にする。
- Twemproxyから代替へ移行する。
これらの変更により、Sentryのコードベース全体のパフォーマンスが向上し、全体的なコスト削減につながりました。
インパクトのある変更は一行で可能
慎重に検討した結果、トランザクションごとにキャッシュを設定し、別の書き込み操作を必要とする代わりに、最初の読み取り操作の際にキャッシュを設定すればよいことにしました。この変更はGitHubでご覧いただけます。
このマイナーチェンジを行った直後から、平均で300msから100ms以下に短縮されたのがお分かりいただけると思います。
そしてこの変更は、他のceleryタスクにも大きな影響を与えました。
トラフィック配分を改善するためにオペレーション・チームを巻き込む
オペレーションの2人の同僚、Anton OvchinnikovとAlex TarasovもSentryのmemcachedサーバーの前にあるロードバランサー、twemproxyのKubernetes設定に問題があることを発見しました。彼らはtwemproxy-saveサービスをclusterIP Noneから通常のclusterIPに切り替えて、memcacheサーバ間のトラフィックを適切にバランスよく分散させる実験を行いました。
その結果、ユーザースペースに費やされるCPU時間の割合が大幅に減少し、接続がより均等に分散されたため、CPU使用率が安定しました。
実験の結果、sentry.tasks.store.save_eventのp95が大幅に減少しました。
C
また、sentry.tasks.store.save_eventの時間が10ms(~13%)短縮しました。
さらに、sentry.tasks.store.save_event_transaction p95も減少しました。
サードパーティツールからのブロック解除
メトリクスを詳細に分析した結果、インフラ監視ツールのSDKがstatsdプロキシに逐次的なリクエストを送信し、ブロックしていたため、Sentryのホットパスで高い実行回数が発生していることがわかりました。
私たちはクライアントを更新し、メインのスレッドをブロックしないように別のスレッドでメトリクスを送信するバックグラウンドスレッド機能を有効にしました。
一部のプロファイルでは、インフラ・モニタリング・ツールがプロキシにイベントを送信するのに非常に時間がかかり、トランザクション全体の30%を占めていました。
この変更により、sentry.tasks.store.save_event_transaction.が11ms改善されました。
Twemproxy からMcrouterへの移行
最後に、我々のセキュリティ・エンジニアの一人であるAlex Tarasovが簡単なベンチマークを実行したところ、Twemproxyはmemcachedサーバーに直接アクセスするよりも3倍遅いことがわかりました。
処理チームのエンジニアの一人であるArpad Borsosは、twemproxyの削除とPythonからの作業負荷の分散に取り組んでいます。
彼の作業の結果、Alex Tarasovが発見したオーバーヘッドを減らすことができました。
キャッシュの問題を調査している間に、アセンブルの状態が memcache に保存されていることにも気づきました。
これは問題で、memcacheには永続性がなく、古い読み込みがないことを保証することもできないため、別のmemcacheクラスタリング・システムに移行することが難しくなります。Sebastian Zivotaが今後数週間のうちにこの問題に取り組み、オーバーヘッドが大幅に削減されることを期待しています。そのアップデートにご期待ください!
メトリックスは時間とコストの節約に役立ったか?
以下は「save_event_transaction」p95の概要です。
グラフが物語っていますね。
まとめ:メトリックスを試してお金を節約しよう
Metricsを試してみたいと思われた方は、現在Beta版をお試しください。SentryアカウントにMetricsが表示されるようになります(まだMetricsが表示されていない場合は、こちらからサインアップしてください。)
Discordで体験談やご意見をお聞かせください。
謝辞
これは巨大な共同作業であり、私がそのことを伝えることになりましたが、以下9人のエンジニアの助けなしには、これほど大きな勝利にはならなかったでしょう。
この場をお借りして感謝いたします。
IchizokuはSentryと提携し、日本でSentry製品の導入支援、テクニカルサポート、ベストプラクティスの共有を行なっています。Ichizokuが提供するSentryの日本語サイトについてはこちらをご覧ください。またご導入についての相談はこちらのフォームからお気軽にお問い合わせください。