OpenResty から Redis への大量アクセス:接続数を抑え、P99 レイテンシを下げる
トラフィックのピーク時には、次のような厄介な状況がよく起こります。普段は大量のトラフィックでも安定して処理できていて、Redis インスタンスの CPU やメモリにも十分な余裕がある。それなのに、タイムセール開始直後や突発的なアクセス集中といった肝心なときに、ゲートウェイから Redis への接続数が数十倍から数百倍に急増し、一瞬で接続数のクォータを使い切り、ひいてはリクエスト経路全体の連鎖障害を招いてしまう。あるいは、バックエンドの注文サービスにはまだ処理能力が残っているのに、ゲートウェイ側のセッションのクエリが遅くなったせいで、ユーザーの画面がいつまでも表示されない。認証、高頻度のレート制限、リアルタイムの状態チェックに Redis を使っている業務では、こうした 2 種類のボトルネックがそのままシステムの安定性リスク、クラウドのリソースコスト、ユーザー体験の問題につながります。
技術チームはしばしば、次のような判断を迫られます。Redis インスタンスを安易にスケールアップすることなく、突発的なトラフィックによる「接続ストーム」を根本から解消し、同時にピーク時でもより多くのユーザーが滞りなく操作を完了できるようにできないか。 この問題を解くには、トラフィック急増時にクライアントが接続数をどう制御するかと、大量アクセス時のクエリのスループットとテールレイテンシ(P99)の両方を見る必要があります。
そこで OpenResty は、単一インスタンス構成とクラスタ構成のそれぞれに向けて、2 つの高性能な Redis プライベートライブラリを提供しています。
| 構成 | クライアント | 主な価値 |
|---|---|---|
| 単一インスタンス Redis | lua-resty-redis-fast | 接続数が業務の同時リクエスト数に応じて増えず、突発的な接続急増やクォータ枯渇を防止。読み取り性能も大幅に向上 |
| Redis Cluster | lua-resty-redis-cluster-fast | GET スループットはオープンソースクライアントの 7.14 倍、P99 レイテンシは 1 ミリ秒未満 |
普段は安定、肝心なときに連鎖障害:接続数の急増とクォータ不足を断つ
まずは、肝心なときに最も問題になりやすい接続数から見ていきます。
多くのチームが、次のような経験をしています。日常のアクセス量はすでに多く、ゲートウェイと Redis の連携もスムーズに回っている。ところが、フラッシュセールや突発的なトラフィック、あるいはわずかなネットワークの揺らぎに見舞われた途端、サービス全体がほんの数秒で停止してしまう。
その根本原因は、従来のクライアントが「1 リクエストが 1 接続を占有し、使い終わったら接続プールに返す」というモデルを採用していることにあります。平常時はリクエストがすぐに完了するため、数十本の持続的接続を使い回すだけで非常に高い QPS をさばけます。しかし肝心なときに、同時リクエスト数が急に膨らんだり、応答がわずかに遅れたりすると、処理中のリクエストが接続をプールに返す前に後続のリクエストが押し寄せ、平常時の数十倍から数百倍にのぼる「新規接続ストーム」が一気に発生します。その結果、次のような連鎖障害が起こります。
- ローカルポートが枯渇し、サーバーに接続できなくなる:瞬間的に大量発生した新規接続が、ゲートウェイマシンで使用可能なエフェメラルポート(Ephemeral Ports)を急速に使い果たし、後続のリクエストはエラーとなって Redis に接続できなくなります。
- サーバーが接続の受け付けに追われ、全体の応答が遅くなる:Redis サーバーに新規接続要求が一気に殺到し、接続受け付けのオーバーヘッドが急増するため、通常の読み書きコマンドの応答まで遅くなります。
- 持続的接続を再利用できず、1 回ごとのリクエストが遅くなる:既存の持続的接続を再利用する場合と比べ、新規接続では TCP ハンドシェイクと認証の手順をすべて踏む必要があり、Redis リクエスト 1 回あたりの所要時間が大きく増えます。
- タイムアウトとリトライが重なり、最終的に全面障害に至る:クライアントのリクエストに時間内に応答できないため、上流の呼び出し元やユーザー側がタイムアウトして接続を切り、すぐにリトライします。リトライのトラフィックが同時リクエスト数と新規接続数をさらに押し上げる悪循環となり、最終的にはサービスが完全に停止してしまいます。
こうした制御不能な接続数の急増は、単一箇所の障害を引き起こすだけではありません。複数のサービスで Redis を共用している構成では、深刻なクォータとコストの悩みも生みます。ピーク時にゲートウェイが接続数を一気に使い果たし、同じインスタンスを使う中核となる取引サービスにまで影響が及ぶのを防ぐため、チームは部門間で接続数のクォータを調整するのに苦労するか、大型セールの前に費用をかけて Redis インスタンスをスケールアップするしかありません。たとえ Redis の CPU やメモリにはまだ十分な余裕があり、ボトルネックがピーク時の接続数だけだったとしても、こうした対応を迫られます。
認証、レート制限、セッション検証といった一般的な読み書きの場面では、lua-resty-redis-fast を使うことで、この連鎖障害の流れを根本から断ち切れます。占有する接続数が、業務の同時リクエスト数の増加に応じて増えないからです。 ゲートウェイ自体のデプロイ規模(マシン数と Worker 数)が変わらない限り、同時リクエスト数が突然 2 倍になっても接続数は安定しており、新規接続の大量発生を引き起こすことはありません。
つまり、突発的なトラフィックの急増に直面しても、ゲートウェイが新規接続を乱発してローカルポートを使い果たしたり、Redis の応答を悪化させたりすることはなく、肝心なときに接続数のクォータを超過することもありません。既存の Redis インスタンスの CPU とメモリにまだ余裕があれば、単一インスタンス版のプライベートライブラリに切り替えることで、現在の接続数クォータの範囲内でピークトラフィックを安定して受け止められる見込みがあり、「接続数の上限を買う」ためだけのインスタンスのスケールアップ費用を削減できます。(注:ここでは「業務の同時リクエスト数の増加」と「ゲートウェイのスケールアウト」を区別する必要があります。後からゲートウェイのノード数や Worker 数を増やした場合は、新しい規模に合わせて必要な総接続数を改めて見積もってください。)
また、lua-resty-redis-fast はオープンソースの lua-resty-redis で一般的に使われる Lua インターフェースを踏襲しているため、既存のサービスでも評価と移行をスムーズに進められます。具体的な対応範囲は、単一インスタンス版の導入ドキュメントを参照してください。
前段のクエリが遅いと、ユーザーはページと操作結果を待たされる
接続数の規模を抑えることで、肝心なときの接続ストームによる連鎖障害とクォータ超過を防げます。一方、日常のピーク時には、1 回 1 回のクエリが「瞬時に完了するかどうか」が、ユーザーの待ち時間を直接左右します。これは単一インスタンス構成でもクラスタ構成でも同じく重要です。
ゲートウェイ層でのログイン状態やトークンの検証を例に考えます。ユーザーが注文ページを開いたり操作を送信したりすると、ゲートウェイはまず Redis からセッションやクォータの状態を読み取り、検証に通ってはじめてリクエストをバックエンドサービスに転送できます。バックエンドの注文サービスがどれだけ空いていても、ゲートウェイのこの段階で詰まってしまえば、リクエストはただ待つしかありません。
ユーザーには内部の呼び出し経路の詳細は見えません。目に入るのは、ページの読み込みが終わらない、送信ボタンを押しても反応がない、という状況だけです。前段の Redis クエリに時間がかかりすぎて経路全体のタイムアウト予算を食いつぶすと、リクエストはそのままタイムアウトで失敗し、ユーザーは何度も再読み込みや再試行を強いられます。したがって、ゲートウェイ側の Redis クエリを最適化する目的は、単一の API で見栄えのよいスコアを出すことだけではなく、中核となる業務フローの完了率を確保することにあります。
ここでは、高スループットと**低テールレイテンシ(P99)**が、2 つの実際のビジネス効果に直結します。
- スループットの向上は「入口を通れる」ことにつながる:ゲートウェイのクエリ処理がボトルネックになっていて、バックエンドサービスにはまだ余力がある場合、1 秒あたりに処理できるクエリを増やせば入口の渋滞が解消され、ピーク時でもより多くの有効なリクエストがバックエンドへスムーズに流れます。
- P99 レイテンシの低下は「タイムアウトしない」ことにつながる:遅いクエリの所要時間を短縮すれば、その後の注文処理など中核ロジックに使える時間に余裕が生まれ、前段の検証が遅いせいでリクエスト全体が失敗するリスクを減らせます。ユーザーが長く待たされたり、何度もやり直したりすることも少なくなります。
2 つの GET ベンチマーク:スループットが大幅に向上し、P99 はいずれも 1 ミリ秒未満
セッションや状態のデータをキーバリュー形式で保存している場合、ゲートウェイの最も中心的な操作は高頻度の GET です。ここでは、同時実行の GET ベンチマークで 2 つのプライベートライブラリの読み取り性能を確認します(リクエスト全体の所要時間にはネットワークや後続の業務ロジックも含まれるため、実際の経路に即して評価する必要があります)。
2 つのプライベートライブラリを、それぞれ対応するオープンソースクライアントと同じ条件で比較しました。以下の表は、各テスト結果の中央値です。
単一インスタンス版:GET スループットはオープンソースクライアントの 3.47 倍、P99 レイテンシは半分以下に。(比較対象はオープンソースの lua-resty-redis v0.34)
| 指標 | lua-resty-redis-fast | オープンソースの lua-resty-redis |
|---|---|---|
| GET スループット | 214,314 commands/s | 61,778 commands/s |
| GET P99 レイテンシ | 0.785 ms | 1.793 ms |
クラスタ版:GET スループットはオープンソースクライアントの 7.14 倍、P99 レイテンシは 6.8 ms から 1 ms 未満に。(比較対象はオープンソースの lua-resty-redis-cluster。Lua の同時実行数は同一)
| 指標 | lua-resty-redis-cluster-fast | オープンソースの lua-resty-redis-cluster |
|---|---|---|
| GET スループット | 192,848 commands/s | 27,019 commands/s |
| GET P99 レイテンシ | 0.972 ms | 6.821 ms |
2 組の結果から、プライベートライブラリは GET のスループットを大幅に引き上げると同時に、テールレイテンシを大きく抑えていることがわかります。これは前述の 2 つのビジネス目標、つまりピーク時のトラフィックのために入口を広げることと、バックエンドの処理に十分な時間を残すことにそのまま対応しています。
テストについて:上記のデータは GET のみのベンチマークに基づくもので、クライアント自体の性能差を示すことを目的としており、接続数の削減率は直接測定していません。実際の業務で得られる効果は、使用する Redis コマンド、ネットワーク環境、読み取り戦略、ゲートウェイ以外の経路上のボトルネックによっても変わります。
クラスタ版では、業務に求められるデータの一貫性に応じて読み取り戦略を選択することもできます。具体的な設定方法は、クラスタ版の導入ドキュメントを参照してください。
接続数のクォータが底をつきかけて Redis のスケールアップを検討しているチームや、ピーク時に前段のクエリが遅くなることで生じる待ち時間やタイムアウトを改善したいチームは、ぜひお問い合わせのうえ、トライアルをお申し込みください。実際の業務トラフィックのもとで、どれだけのリソースコストを削減し、どれだけ応答性を高められるかを評価いただけます。
さらに詳しく:同じリクエスト経路上のほかのコスト
Redis クエリは、ゲートウェイがリクエストを処理する工程の一部にすぎません。Redis クエリはすでに十分に速いのに、API 全体の応答時間やサーバーの負荷がまだ思わしくない場合は、同じ経路のほかの工程で時間や CPU が消費されていないかを確認してみてください。OpenResty プライベートライブラリの概要では、Redis とあわせて最適化されることの多い領域をほかにもいくつか紹介しています。
- セッションデータや API のペイロードで JSON を高頻度に解析する場合:JSON 形式のセッションや設定データを Redis から取り出した後、ゲートウェイは通常すぐにデコードする必要があります。フレームグラフで JSON のエンコード・デコードが CPU を大きく占めているなら、OpenResty サービスにおける「見えないボトルネック」としての JSON もあわせてお読みください。解析を高速化することで、ゲートウェイインスタンスが業務トラフィックの処理に使える CPU リソースを増やせます。
- ゲートウェイから Kafka へログや業務イベントを非同期で送信する場合:ゲートウェイがリクエストの転送と並行して、不正検知イベントやアクセスログの収集・送信も担っているなら、送信処理の揺らぎがメインの経路を遅くしないようにする必要があります。lua-resty-kafka-fast は OpenResty から Kafka への書き込みに向けて徹底的に最適化されており、高スループットのデータ収集を維持しながら、ユーザーへの応答に与える影響を厳密に抑えます。
- 突発的なトラフィックがゲートウェイ自体の CPU の限界に迫っている場合:内部のクエリや解析は十分に最適化したものの、外部からの急激なトラフィックが現在のマシンの処理能力を超えてしまう場合は、lua-resty-limit-traffic-dynamic に注目してください。CPU 使用率の目標値に応じて HTTP のレート制限のしきい値を動的に調整し、トラフィックの急増時にもシステムの余力を守り、すでに受け付けたリクエストを確実に完了させます。
これらのプライベートライブラリは、それぞれシリアライズ処理、メッセージ送信、動的なトラフィック制御を対象としており、チームは自社の性能ボトルネックに合わせて必要なものを選べます。全コンポーネントの一覧と導入ガイドは、プライベートライブラリのドキュメントをご覧ください。
著者について
章亦春(Zhang Yichun)は、オープンソースの OpenResty® プロジェクトの創始者であり、OpenResty Inc. の CEO および創業者です。
章亦春(GitHub ID: agentzh)は中国江蘇省生まれで、現在は米国ベイエリアに在住しています。彼は中国における初期のオープンソース技術と文化の提唱者およびリーダーの一人であり、Cloudflare、Yahoo!、Alibaba など、国際的に有名なハイテク企業に勤務した経験があります。「エッジコンピューティング」「動的トレーシング」「機械プログラミング」の先駆者であり、22 年以上のプログラミング経験と 16 年以上のオープンソース経験を持っています。世界中で 4000 万以上のドメイン名を持つユーザーを抱えるオープンソースプロジェクトのリーダーとして、彼は OpenResty® オープンソースプロジェクトをベースに、米国シリコンバレーの中心部にハイテク企業 OpenResty Inc. を設立しました。その主製品である OpenResty XRay(動的トレーシング技術を利用した非侵入型のプロファイリングおよびトラブルシューティング製品)および OpenResty Edge(分散トラフィック管理およびプライベート CDN 向けの強力なソフトウェア)は、世界中の多くの上場企業および大企業から高い評価を得ています。OpenResty 以外にも、章亦春は Linux カーネル、Nginx、LuaJIT、GDB、SystemTap、LLVM、Perl など、複数のオープンソースプロジェクトに累計 100 万行以上のコードを寄与し、60 以上のオープンソースソフトウェアライブラリを執筆しています。
翻訳
英語版の原文と日本語訳版(本文)をご用意しております。読者の皆様による他の言語への翻訳版も歓迎いたします。全文翻訳で省略がなければ、採用を検討させていただきます。心より感謝申し上げます!














