性能改善入門

こんにちは、エンジニアのぴよたろうです。お仕事では、インフラとかセキュリティとか見てます。アプリも好きです:D

はじめに

弊社サービスには多様なデータが集まっており、活用するために Elasticsearch を利用しています。
その Elasticsearch のレイテンシが、上昇傾向にあるため性能改善しました。 行ったことを以下に挙げます。
  • 現状の認識
  • 仮説を立てる
  • 問題となる事象の再現
  • 仮説の検証
  • 本番環境適用
本記事では、 Elasticsearch を題材に一般的な性能改善を行なって行きます。
以下へ、具体的に記述していきます。

現状の認識

性能改善を行うためには、現状を知ることが重要です。現状を知り、ボトルネックを探っていきます。 そして、現状を知るためには、時系列でメトリクスを見ることが有効です。性能劣化したタイミングと平常時のメトリクスを比較することで見えてくるものがあります。(データが足りない場合など、見えないこともあります。) 弊社では、日々アプリケーションやミドルウェアのメトリクスを収集しており、 Elasticsearch のメトリクスも収集しています。 レイテンシが上昇するタイミングでは、以下の傾向を確認しました。
  • サーバの CPU が Busy
  • JVM のメモリ(Old領域)使用率が急上昇
また、ログを見ることも重要です。ログは私たちに事実を教えてくれます。(逆説的に、事実を教えてくれない文字列は、ログではありません。) Elasticsearch のログを確認したところ、レイテンシが上昇するタイミングで、以下の傾向を確認しました。
  • Old GC が頻発

仮説を立てる

これまでの情報から、 JVM のメモリ周りで異常が起きていると考えました。そこで、JVM のメモリ周りの設定を確認したところ、 New 領域への割り当てが少なく感じました。
そのため、 New 領域を調整することでメモリ使用効率が改善し、問題を緩和できるのではないかと仮説を立てました。

問題となる事象の再現

状況が許すのであれば、仮説を検証してから本番環境へ適用するべきです。
仮説を検証するには、前述した現状の認識へ記載した高レイテンシ状態を再現した環境を用意する必要があります。 弊社では、アプリケーションから Elasticsearch へのリクエストに使われているクエリをアプリケーションのログへ出力しています。 そこで、ログからレイテンシ上昇時のクエリを収集しました。また、レイテンシ上昇時は、 Elasitcsearch へのリクエストが高頻度であることがわかりました。 次に、収集したクエリで高頻度に Elasticsearch へリクエストを投げるスクリプトを作成しました。このスクリプトを実行することで、高レイテンシ時の Elasticsearch と同等の状況を作ることができると考えられます。 実際に実行したところ、高レイテンシ時と同等の環境を再現することができました。

仮説の検証

ここまでで以下を用意しました。
  • 仮説
  • JVM の New 領域を調整することでメモリ使用効率が改善し問題を緩和できる
  • 事象の再現
  • クエリで高頻度に Elasticsearch へリクエストを投げるスクリプト
JVM の New 領域を調整する ということですが、どれほど与えれば効果があるのか、そもそも効果があるのか検証していきます。そのために次のモノを準備します。
  • 本番同等の情報量を持つ Elasticsearch
  • メトリクス収集スクリプト
検証の精度を高めるために、できるだけ本番環境に近い環境で行う必要があります。そのため、本番同等の情報量を持つ Elasticsearchを用意しました。弊社では、 Elasticsearch を VM 上で動かしているため、コピーすることが容易に行えました。 そして、 JVM の New 領域を調整する ことが効果的であったか確認するために、メトリクス収集スクリプト を作成します。ここで収集したメトリクスを元に検証を進めて行きます。
スクリプトは、 JVM のメモリ使用率、JVM の GC実行回数、サーバの状態(CPU使用率等)を1秒毎に収集しました。具体的な手段としては、JDK に含まれる jstat コマンドや top コマンド、 vmstat コマンド等を用いたスクリプトとなっています。
また、事象を再現するスクリプトでは、Elasticsearch からのレスポンスタイムとElasticsearch が検索の実行にかかった時間を出力するようにしました。意味合いとしては、主目的である高レイテンシの解消を確認するためです。 ここから実際に検証を行っていきます。
New 領域を以下の順で変更していくとともに、メトリクスの収集を行いました。
  1. 1GB(初期設定値)
  2. 2GB(様子見で少しあげてみる)
  3. 5GB(1GBと2GBの違いがわずかであったため大きくあげてみる)
  4. 10GB(5GBで効果があったため試してみる)
  5. 15GB(10GBでも順当に効果があったため試してみる)
結果として、5GB~10GBで改善が見られました。 検証を進めていく上でのポイントとして、変数は1つにします。 ここで変数が指しているのは、 New 領域の値のような性能へ繋がるであろう値です。
変数が2つ以上あることで、検証結果が曖昧なものになります。例えば、今回であれば CPU のスペックアップも仮説としてありえます。しかし、New 領域の調整と同時に検証を行ってしまうと、 CPU のスペックアップした上で New 領域を増やさないと効果が無いという可能性を捨て切れません。今後、同様の事象が発生した際に、応用を効かせるためにも不確定要素残さないことが大切です。

本番環境適用

仮説の検証で効果がありそうなことを確認しました。性能劣化する可能性も少ないことが分かっていたため、本番環境へ適用しました。
しばらく運用した結果、今回の問題が発生することはなくなりました。

まとめ

  • 問題が発生したら現状を認識するところから始めよう
  • 仮説を立て、問題が起こる状況を再現し、検証しよう
  • 多くのことを一度にやらず、一つのことをうまくやろう
  • 日々メトリクスは取ろう

一緒に働くエンジニアを募集中!

ビザスクではエンジニアを大募集中です!

ビザスクに少しでも興味のあるWebエンジニアの方がいましたら、ぜひお話を聞かせてください!詳しい募集要項は下記リンクからアクセスしてください。

エンジニアを募集しています

ビザスクでは、エンジニアとして働きたい方を募集しています。
ご興味のある方は下記よりお気軽にご連絡ください。