システムの性能について話していると、よく出てくる言葉があります。

  • Latency
  • Throughput

どちらも「速さ」に関係する言葉なので、最初は少し混同しやすいです。

ただ、実際には見ているものが違います。

かなりざっくり言うと、

Latency = 1回の処理にどれくらい時間がかかるか

Throughput = 一定時間にどれくらい処理できるか

です。

この2つを分けて考えられるようになると、性能改善の話もかなり整理しやすくなります。

Latencyとは

Latencyは、ある処理を開始してから結果が返ってくるまでに、どれくらい時間がかかるかを表します。

たとえばAPIなら、次の流れがあります。

Request -> Server -> Response

このRequestを送ってからResponseが返ってくるまでの時間がLatencyです。

たとえば、

GET /users/1

Latency: 100ms

だった場合、そのAPIはだいたい100msでレスポンスを返している、ということになります。

なのでLatencyは、

1回の処理でどれくらい待つか

と考えるとわかりやすいです。

Webアプリであれば、ユーザーがボタンを押してから画面に結果が出るまでの時間にも関係してきます。

Latencyが大きいと、それだけ「なんか遅いな」と感じやすくなります。

Throughputとは

一方でThroughputは、

一定時間にどれくらいの処理を完了できるか

を見る指標です。

たとえばAPIサーバーが1秒間に1,000リクエスト処理できるのであれば、

Throughput: 1,000 requests/sec

というイメージです。

API以外でも同じです。

メッセージ処理なら、

50,000 messages/sec

画像処理なら、

500 images/sec

のように表せます。

つまりThroughputは、

システム全体としてどれくらいの量を捌けるか

を見るものです。

LatencyとThroughputの違い

整理すると、違いはかなりシンプルです。

指標見ているもの
Latency1つの処理にかかる時間
Throughput一定時間に処理できる量

たとえば、あるAPIサーバーが、

Latency: 100ms

Throughput: 1,000 req/s

だったとします。

これは、

  • 1回のリクエストはだいたい100msで返る
  • システム全体では1秒間に約1,000件処理できる

という意味です。

どちらも性能の話ではありますが、見ている方向が違います。

Latencyが低ければThroughputも高いのか

ここは少しややこしいところです。

感覚的には、

1回の処理が速いなら、たくさん処理できるんじゃないの?

と思います。

もちろん、そうなることもあります。

ただし、

Latencyが低い = Throughputが高い

とは限りません。

たとえば、1リクエストを100msで処理できるサーバーがあるとします。

でも、同時に1リクエストしか処理できないなら、単純計算では1秒間に10件くらいしか処理できません。

Latency: 100ms

Concurrency: 1

Throughput: 約10 req/s

一方で、同じ100msの処理でも、100件を同時に処理できるなら話が変わります。

Latency: 100ms

Concurrency: 100

Throughput: 約1,000 req/s

ということもありえます。

つまり、Latencyが同じでもConcurrencyによってThroughputは変わります。

ざっくり言うと、

  • Latency: 1件にどれくらい時間がかかるか
  • Concurrency: 同時に何件処理できるか
  • Throughput: 結果として一定時間に何件処理できるか

という感じです。

なので、Latencyだけを見て「このシステムは大量のリクエストにも強い」と判断することはできません。

Web APIではLatencyが気になりやすい

たとえば、ECサイトの商品ページを開くケースを考えてみます。

Browser -> GET /products/123 -> API -> Response

このAPIが100msで返るのと3秒かかるのでは、かなり体感が違います。

ユーザーが直接待つような処理では、Latencyが重要になりやすいです。

もちろん、大量アクセスがあるサービスならThroughputも必要です。

ただ、

Throughput: 10,000 req/s

p95 Latency: 5秒

だったら、かなり使いづらい可能性があります。

大量に処理できることと、1人ひとりのユーザーが快適に使えることは別の話です。

バッチ処理ではThroughputが重要になることもある

逆に、ユーザーがその場で結果を待っていない処理では、Throughputの方が重要になることがあります。

たとえば、

100万枚の画像を変換する

という処理を考えます。

1枚あたりの処理時間が、

100ms -> 90ms

になったとしても、全体として同時に少ししか処理できないなら、そこまで大きな改善にならないかもしれません。

それよりも、

100 images/sec -> 1,000 images/sec

のように、単位時間あたりに処理できる量を増やした方が効果が大きいことがあります。

たとえばWorkerを増やして、

Job Queue -> Worker A

Job Queue -> Worker B

Job Queue -> Worker C

Job Queue -> Worker D

のように並列処理するイメージです。

1件あたりのLatencyはほとんど変わっていなくても、全体のThroughputは上げられます。

IoTでも処理によって変わる

IoTでも同じです。

たとえば大量のデバイスからテレメトリを受け取る仕組みを考えます。

Device -> MQTT Broker -> Consumer -> Database

数万台のデバイスから定期的にデータが送られてくるなら、

1メッセージが20msで処理されるか30msで処理されるか

よりも、

1秒間に何万メッセージ処理できるか

の方が重要になることがあります。

この場合はThroughputです。

一方で、たとえばドローンやロボットに緊急停止コマンドを送る処理ならどうでしょう。

Server -> Command -> Device

この場合、

1秒間に何万件の緊急停止命令を処理できるか

より、

コマンドを送ってからどれくらいで届くか

の方が気になります。

こちらではLatencyが重要です。

つまり、同じシステムの中でも、

  • テレメトリ受信はThroughput
  • リアルタイム制御はLatency

のように、処理によって重要な指標が変わります。

「このシステムはLatency重視」「このシステムはThroughput重視」と大きく分けるより、処理ごとに考えた方が自然なこともあります。

Throughputの限界に近づくとLatencyが悪化する

LatencyとThroughputは別の指標ですが、完全に無関係ではありません。

たとえば、あるサーバーが最大で1,000 req/sくらい処理できるとします。

そこに500 req/sしか来ていないなら、かなり余裕があります。

Incoming: 500 req/s

Capacity: 1,000 req/s

この状態なら、リクエストが来てもすぐに処理できるので、Latencyも安定しやすいです。

でも負荷が増えて、

900 req/s

950 req/s

990 req/s

のように限界へ近づいてくると、処理待ちが発生するようになります。

Requests -> Queue -> Server

という状態です。

サーバーが実際に処理している時間は同じでも、Queueで待たされる時間が増えれば、ユーザーから見たLatencyは悪化します。

さらに、

Incoming: 1,200 req/s

Capacity: 1,000 req/s

になったとします。

毎秒1,200件来るのに、毎秒1,000件しか処理できません。

すると、毎秒200件ずつ処理待ちが増えていきます。

こうなると、

  • Throughputは1,000 req/s付近で頭打ち
  • Queueは伸び続ける
  • Latencyだけどんどん悪化する

という状態になります。

なので負荷試験でも、

最大で何req/s出せるか

だけを見るのではなく、

負荷を増やしたときにLatencyがどう変化するか

も一緒に見た方がいいです。

平均Latencyだけを見るのも危ない

Latencyを見るときは、平均値だけを見るのも少し注意が必要です。

たとえば、

Average Latency: 100ms

だけを見ると、かなり速そうに見えます。

でも実際には、

p50: 50ms

p95: 300ms

p99: 2,000ms

かもしれません。

この場合、大半のリクエストは速いですが、一部のリクエストは2秒以上かかっています。

平均値だけだと、この遅いリクエストが見えづらくなります。

なのでAPIのLatencyを見るときは、

  • p50
  • p95
  • p99

のようなPercentileを見ることがあります。

たとえば、

p95 = 300ms

なら、

リクエストの95%は300ms以内に終わった

という意味です。

単純に平均だけを見るより、遅いリクエストがどれくらい存在しているかもわかります。

結局どちらを最適化すればいいのか

これは結局、システムや処理によります。

傾向としては、

処理重視されやすい指標
Web APILatency
バッチ処理Throughput
大量のメッセージ処理Throughput
IoTテレメトリThroughput
リアルタイム制御Latency

くらいには分けられます。

ただ、

WebだからLatency

バッチだからThroughput

と単純に決められるわけでもありません。

Web APIでも大量アクセスを受けるならThroughputが必要ですし、バッチ処理でも完了時間に厳しい要件があるかもしれません。

なので、最初から、

LatencyとThroughputのどちらを改善するべきか

と考えるより、

この処理では何が遅いと困るのか

どれくらいの量を処理できないと困るのか

から考えた方がいいと思います。

たとえば、

p95 Latency < 300ms

Throughput > 5,000 req/s

のように、両方に要件があることも普通です。

必要なLatencyを満たしながら、必要なThroughputも確保する。

実際にはそういう考え方になることが多いです。

「性能が良い」だけだと少し曖昧

「このシステムは速い」という表現は、よく考えるとかなり曖昧です。

Latencyが低いことを言っているのかもしれません。

Throughputが高いことを言っているのかもしれません。

たとえば、

1件の処理はかなり速いけど、大量アクセスには弱い

というシステムもあります。

逆に、

大量のデータは処理できるけど、1件あたりの処理には時間がかかる

というシステムもあります。

なので性能について話すときは、

何が速いのか

を分けて考える必要があります。

その基本になるのがLatencyとThroughputです。

ざっくり覚えるなら、

Latency = 1回の処理でどれくらい待つか

Throughput = 一定時間でどれくらい捌けるか

くらいで考えておけば、まずは十分だと思います。