Redisパフォーマンス測定入門:レイテンシ分析の基本と実践ツール

前回の記事では、Redisインスタンスが遅くなるのを防ぐためのトピックやアプローチについて解説しました。今回はいよいよ、パフォーマンスを測定するための方法を見ていきましょう。
何を測定すべきか
今回取り上げるのは、コマンドのレイテンシ(遅延)とその構成要素です。なぜなら、Redisサーバーやライブラリを通じて処理できるコマンド数は、個々のコマンドの速度に依存するからです。1コマンドあたりの所要時間が分かれば、スループットの上限もおのずと見えてきます。
手軽に試せるCLIでの計測
コマンドのレイテンシを確認する最初の方法は、コマンドラインクライアントredis-cliを使うことです。手軽に実行でき、すぐにベースラインとなる数値を得られます。ここでは説明を簡単にするためにlocalhostを使用しますが、実際の環境では-h <host>オプションを使い、必要に応じて-a <auth>(認証)や-p <port>(ポート番号)も指定してください。
基本のレイテンシ測定
基本的なレイテンシ結果を取得するには、redis-cli --latencyを実行します。最小値(min)、最大値(max)、平均値(avg)、そして反復回数が出力されます。この反復は、開かれた接続に対してPINGコマンドを実行するものであり、サーバーへの接続時間は含まれません。そのため、毎コマンドで接続を確立するようなコードでは、このコマンドが示す数値よりも大幅に悪いパフォーマンスになる点に注意しましょう。
このコマンドはCTRL-Cなどで停止するまで実行され続けます。レイテンシの単位はミリ秒です。例えば次のような結果の場合:
min: 0, max: 1, avg: 0.11 (11369 samples)これは「最小レイテンシは1ミリ秒未満、最大は1ミリ秒、PING1回あたりの平均は0.11ミリ秒」を意味します。もちろんこれはlocalhost接続の例です。これらの数値は11,369件の「サンプル」、つまりPINGコマンドの実行結果から算出されたものです。
あるいは、--latency-historyオプションを使う方法もあります。こちらは一定時間ごとの区切りで結果を出力できるオプションです。redis-cli --latency-historyを実行すると、デフォルトで15秒のウィンドウが使用され、出力は次のようになります。
min: 0, max: 1, avg: 0.11 (1475 samples) -- 15.01 seconds range
min: 0, max: 1, avg: 0.10 (1474 samples) -- 15.01 seconds range--latencyと同様に、停止するまで実行が続きます。間隔を変えたい場合は-iオプションで指定できます。例えば:
redis-cli --latency-history -i 10
min: 0, max: 1, avg: 0.11 (984 samples) -- 10.01 seconds range
min: 0, max: 1, avg: 0.11 (983 samples) -- 10.01 seconds range
min: 0, max: 1, avg: 0.11 (983 samples) -- 10.01 seconds rangeこれらの操作は単純にPINGコマンドを使うだけなので、どのバージョンのRedisに対しても動作します。
固有レイテンシ(Intrinsic Latency)
一見すると、このモード名からサーバーの固有レイテンシを測っているように思えるかもしれません。しかし実際は違います。GitHub上のredis-cliソースコードを見ると、サーバーと通信さえしていないことが分かります。
start = ustime();
compute_something_fast();
end = ustime();
latency = end-start;固有レイテンシモードに関するソース内のコメントには、次のように書かれています。
システムコールに起因しない、実行中プロセスの最大レイテンシを測定する。要するに、このソフトウェアはカーネルがプロセスに実行機会を与えない時間がどれほどあるかの手掛かりを提供するものである。
つまり、これはクライアント側ホストの固有レイテンシをテストしているのです。問題がサーバーではなくクライアント側にあるのかどうかを判断するのに役立ちます。
有用ではありますが、レイテンシ確認の最初のステップに置くべきではないでしょう。追記: Salvatore氏に確認したところ、このコマンドはサーバー上で実行することが意図されているとのことでした。つまりRedisサーバーへのシェルアクセスがあれば有用ですが、そうでなければ(Redisサービスプロバイダー利用時のように)役に立ちません。
Commissarの利用
Commissarは、Redisのレイテンシと全体的なパフォーマンスを追跡・テストするために筆者が開発中の小規模なツール群です。注意: 開発初期段階であり、今後大きく変更される可能性があります。そのため、本番品質ではないソフトウェアの使用に抵抗がない場合のみ使用してください。CommissarはGitHubのCommissarリポジトリで公開されています。
本記事では特に、latencyツール/ディレクトリに注目します。
このツールは環境変数で設定を行い、指定されたRedisインスタンスに接続し、redis-cliと同じ「PINGコマンドの時間計測」メカニズムを実行します。これはテスト条件の公平性を保つためです。redis-cliと異なるのは、より多くの情報を出力でき、(現時点では)MongoDBに結果を保存できる点です。今後は他のストアにも対応予定です。
latencyの実行結果は次のようになります(記事執筆時点のもので、出力形式は変更されている可能性があります):
./latency
Connected to <host:ip>
100000 iterations over 53698us, average 536us/operation
Percentile breakout:
====================
99.00%: 3,876.99us
95.00%: 640.00us
90.00%: 514.00us
75.00%: 452.00us
50.00%: 414.00us
Min: 243us
Max: 44,686us
Mean: 536.98us
Jitter: 764.37us注目すべきは、この実行での時間単位が「us」(マイクロ秒)である点です。また、パーセンタイル別の内訳も表示されることが分かります。単純なmin/max/avgの組み合わせよりも、レイテンシの分布をより正確に把握できます。ここでの「Jitter」はサンプルの標準偏差を意味します。
この出力から、全体としては良好な状態だと言えます。この例はプライベートネットワーク経由のものです。ピーク値は平均よりかなり高くなっていますが、反復の95%は640マイクロ秒以下に収まっています。これは何を示唆するのでしょうか?
散発的なネットワーク障害、散発的なサーバー側の遅延、あるいはテストクライアントのガベージコレクションなどが結果に影響している可能性もあります。だからこそリクエストの分布が提供されているのです。「高い」結果がどの程度の頻度で発生するのかを確認できます。
問題の所在を特定するには、まずサーバー上でコマンドの実行にどれだけの時間がかかっているかを確認しましょう。それにより、サーバーがボトルネックになっているかどうかが分かります。
例えばこのケースでは、redis infoの出力を確認し、特にCommandstatsセクションを見るとよいでしょう:
redis-cli info commandstats
# Commandstats
cmdstat_ping:calls=32497193,usec=22213723,usec_per_call=0.68ここから、サーバー上でPINGを実行する平均時間は0.68マイクロ秒だと分かります。明らかにpingコマンド自体が原因である可能性は低いと言えます。ただし、テスト中に他のコマンドが実行され、Redisプロセスが詰まって遅延が発生していた可能性はあります。
latencyツールへの最近の追加機能として、並行レイテンシテストの実行があります。環境変数LATENCY_CLIENTCOUNTを設定することで、Redisサーバーへの複数接続を確立し、同時実行数がレイテンシ結果にどう影響するかを確認できます。例えば、10クライアントと100クライアント、さらには1000の同時クライアントで、単純なRedis PINGコマンドにどのような違いが現れるかを見られます。開発/ステージング環境と本番環境との差異を把握するのに役立つでしょう。
コンテナからのテスト
Dockerコンテナからテストを実行したい方には朗報です。golatencyツールだけを含むビルド済みDockerコンテナを公開Dockerレジストリにプッシュしています。docker pull therealbill/golatencyを実行すればイメージを取得でき、数秒で実行準備が整います(現在のイメージサイズは4MB未満です)。
ReadMeの指示に従って環境変数を指定してdocker runを呼び出すだけで、stdoutから、またはデーモンとして実行した場合はdocker logsから出力を取得できます。何かをビルドする必要はありません。ツールに重要な変更を加えるたびに、Dockerリポジトリは新しいイメージで更新されます。あるいは、リポジトリにはDockerfileも含まれているので、自由にカスタマイズすることも可能です。
まとめ
Redisのパフォーマンス分析は一筋縄ではいかないこともあります。しかし、レイテンシとスループット、そしてそれらがアプリケーションに与える影響を理解していれば、Redisそのものではなく、アプリケーションのRedisの使い方の分析に集中できるようになります。「Redisの禅」にある言葉、「パフォーマンスの鍵はRedisを遅くしないこと」を心に留めながら、ネットワーク問題の切り分けやデータ構造の代替案の検討を通じて、より賢く効率的なアプリケーションを作り上げ、結果として優れたパフォーマンスを実現しましょう。
-
サーバーレスデータベース徹底比較:DynamoDB vs Firestore vs MongoDB vs Cassandra vs Redis vs FaunaDB
はじめに 本記事は、2021年4月に公開したブログ記事の続編です。 私たちは、一般的なWebユースケースとサーバーレス関数を用いて、主要なサーバーレスデータベースのパフォーマンスを比較するサンプルアプリケーションを構築しました。比較対象は、DynamoDB、MongoDB(Atlas)、Firestore、Cassandra(Datastax Astra)、FaunaDB、Redis(Upstash)の6つです。 アプリケーションおよびソースコードは公開しているので、ぜひご確認ください。 測定内容と方法 今回比較したのは、各データベースで上位10件のニュース記事を取得する際のレイテンシです。
-
エッジキャッシングで実現する、世界どこでも5ミリ秒のRedisレイテンシ
Redisでは、データベースとクライアントが同じリージョン内にあれば、1ミリ秒のレイテンシは容易に実現できます。しかし、クライアントが世界中に分散している場合、レイテンシは100ミリ秒を超えてしまいます。この課題を解決するために開発されたのが「Edge Caching(エッジキャッシング)」です。 エッジキャッシングとは エッジキャッシングでは、CDNと同じようにREST APIのレスポンスが世界各地のエッジロケーションにキャッシュされます。エッジキャッシングを有効にすると、平均5ミリ秒というグローバルレイテンシを実現できます。実際に、10の異なるリージョンに配置したクライアントからレイテンシ