APIを10倍のリクエスト/秒を処理できるように最適化した。スループットのグラフは素晴らしく見えた。そしてユーザーからアプリが鈍いというクレームが来始めた。
どうやってシステムを速くしながら遅くできるのか?スループットとレイテンシを混同することで。
レイテンシは1つのリクエストにかかる時間。ユーザーがクリックし、待ち、結果を見る。ミリ秒で測定。
スループットは1秒あたりのリクエスト数。システム容量であり、ユーザー体験ではない。RPSで測定。
罠:これらはしばしば逆方向に動く。
1人のシェフがいるレストランを想像しろ。各料理に10分かかる。レイテンシは10分、スループットは1時間に6皿。
今、キューシステムを追加する。客が事前注文し、シェフが似た料理をバッチで調理—5つのステーキを1つずつではなく一度に焼く。スループットは1時間に20皿にジャンプ。
でも君のステーキ?調理が始まる前にキューで25分待った。レイテンシは10分から35分になった。
単品注文のビフォーでは、注文してすぐ調理10分で提供。レイテンシ10分、スループット1時間6皿。バッチ処理のアフターでは、注文してキュー25分、調理10分で提供。レイテンシ35分に悪化、でもスループットは1時間20皿に改善。高スループット、悪いレイテンシ、同じキッチン。
**バッチ処理(Kafka、SQS)**は高スループットだが、各メッセージはバッチが満たされるのを待つ。
コネクションプーリングは総リクエストをより多く処理するが、個々のリクエストは利用可能なコネクションを待つ。
リージョナルロードバランシングはより良いグローバル分散をもたらすが、一部のリクエストは遠いサーバーにルーティングされる。
ライトコアレッシングはディスク操作が少ないが、各書き込みはバッファがフラッシュされるのを待つ。
スループット改善を祝いながらユーザーが静かに離れるチームを見てきた。
ダッシュボードは良く見える—平均レイテンシ(p50)は150msで問題なし、リクエスト/秒は10,000で問題なし、エラー率は0.1%で問題なし。でも一部のユーザーの現実はp99レイテンシが8秒だ。
なぜ?負荷時のキューイング。p50ユーザーは問題ない。p99ユーザーはキューで7.8秒待った。ほとんどのユーザーは平均を感じない。最悪ケースを感じる。1回の悪い体験で離れる。
Redisはレイテンシに最適化している。シンプル操作、インメモリ、シングルスレッド(ロック遅延なし)。サブミリ秒レスポンス。
Kafkaはスループットに最適化している。メッセージをバッチし、シーケンシャルディスク書き込みで、レイテンシをボリュームとトレード。100msのバッチ待ちは普通。
決済システムは正確性に最適化している。スループットもレイテンシも優先ではない—二重請求しないことが優先。安全のために遅さを受け入れる。
最適化する前に問え:ユーザーは何を感じる?
チェックアウトページでは、ユーザーがクレジットカードを手に待っている。1秒ごとにコンバージョンが減る。最適化対象はレイテンシで、目標はp99が500ms未満。
バックグラウンドジョブ処理では、ユーザーがファイルをアップロードしてランチに行った。スピナーを見ていない。最適化対象はスループットで、目標は1時間10Kファイル処理。
アナリティクスダッシュボードでは、誰かが画面を見て数字を待っている。最適化対象はレイテンシで、目標はp99が2秒未満。
ログ取り込みでは、待っているユーザーなし。最適化対象はスループットで、目標は毎秒100万イベント。
答えは絶対に「両方均等に最適化」ではない。1つを選び、もう1つのトレードオフを受け入れる。
嘘をつくメトリクスに注意しろ。「平均レイテンシは150ms」は8秒のp99を隠す。「10K RPSを処理」はどのレイテンシかを言わない。「システムは速い」は誰にとって速いかを言わない。
重要なメトリクスは明確だ。p50が150ms、p99が800ms、p99.9が2秒。p99が500ms未満で10K RPS。チェックアウトレイテンシのp99がSLA以下。
常に両方を測定しろ。両方を報告しろ。君のユーザーにとって重要な方を最適化しろ。
マシンにとって速いとユーザーにとって速いは異なる問題だ。
— blanho
ロギング、認証、リトライ、レート制限 — 最初に設計しないが、後で全員が苦しむもの。
どのアーキテクチャも1つの問題を解決し、3つの新しい問題を生む。コミットする前に誰も教えてくれないことがここにある。
NetflixはKafka、Cassandra、3つのキャッシュレイヤーを引き剥がした。すべてのキャッシュは嘘だから。