ブログ一覧へ戻るシステムアーキテクチャ

分散システムにおけるRedis Streams

分散システムにおけるRedis Streams

イベント駆動アーキテクチャ(Event-Driven Architecture)や現代の分散システムでは、サービス(マイクロサービス)間の非同期通信や、バックグラウンドワーカーへのタスク調整が中核的な課題となります。

長年、Redis Pub/Subや**Redis List(LPUSH / RPOP)**は、インメモリの極めて高い速度と低い導入コストにより、馴染みのある手段でした。しかし、システムの規模が拡大すると、信頼性や負荷分散に関するこれらの方式固有の限界が現れ始めます。

Redis Streamsの登場により、分散ログ(Distributed Log)モデルがRedisエコシステムに取り込まれました。本記事では、Redis Streamsのアーキテクチャ上の考え方を分析し、Redis Pub/Subとの長所・短所を詳しく比較したうえで、実務でどちらを選ぶべきかを明らかにします。


1. 中核となる考え方: 不変の追記専用ログ(Append-Only Log)

本質的に、Redis Streamsはメモリ上に保存される**追記専用ログ(Append-Only Log)**型のデータ構造です。

  • ストリームへ投入された各メッセージには、時間とともに単調増加する一意のMessage ID(timestamp-sequence形式)が割り当てられます。
  • 一度ストリームへ書き込まれたデータはRAM上に永続的に保存され、ディスクへの同期(AOF/RDB)も設定可能です。読み取られた後に自動で消えることはありません。
  • 消費側サービス(consumers)は、リアルタイムに順次読み取ることも、過去の任意の時点から履歴を読み直すこともできます。
                    REDIS STREAM (Append-Only Log)
 ┌─────────────┐   ┌─────────────┐   ┌─────────────┐   ┌─────────────┐
 │ Msg: 1001-0 │──►│ Msg: 1002-0 │──►│ Msg: 1003-0 │──►│ Msg: 1004-0 │──► [追記が続く...]
 └─────────────┘   └─────────────┘   └─────────────┘   └─────────────┘
  (処理済み)         (処理中)          (読み取り待ち)      (新規到着)

2. アーキテクチャ比較: Redis Streams vs. Redis Pub/Sub

違いを明確にするため、配信方式とデータ保証の観点から、この2つの仕組みを並べて比較します。

[REDIS PUB/SUB: 発射して忘れる(Fire-and-Forget)]
Producer ────► [Channel] ────► Consumer 1 (Online)   ── メッセージを受信
                         ────► Consumer 2 (Offline)  ── 永久に失われる!

[REDIS STREAMS: ログの軌跡とConsumer Groups]
Producer ────► [Stream Log] ──(メモリ上に永続保存)
                     │
                     ├─── Worker 1 (Consumer Group) ── Msg 1 を処理(ACK済み)
                     └─── Worker 2 (Consumer Group) ── Msg 2 を処理(ACK待ち)
                     └─── Worker 3 (オフラインから復帰)── Msg 3 から読み続ける
評価項目Redis Pub/SubRedis Streams
配信モデルブロードキャスト(Broadcast / Fan-out)<br>接続中のすべてのsubscriberへ送信します。分散ログ(Log + Consumer Groups)<br>ブロードキャストと作業分担の両方に対応します。
永続性(Persistence)保存しない(In-memory transient)<br>聞き手がいない場合、メッセージは直ちに破棄されます。永続保存あり(Persistent)<br>メッセージは能動的に切り詰められるまでStream内に残ります。
配信保証At-most-once(最大1回)<br>ネットワーク遅延やconsumerのクラッシュで容易に失われます。At-least-once(少なくとも1回)<br>確認(ACK)と障害時の再試行の仕組みがあります。
負荷分散(Load Balancing)非対応<br>すべてのsubscriberが同一の複製を受け取ります。Consumer Groupsにより強力に対応<br>ワーカー群へタスクを均等に分担します。
履歴の再読込(Replayability)不可<br>consumerはsubscribe以降に送られたメッセージのみ受信します。完全に可能<br>任意の位置または時点から履歴を読み直せます。
メモリ負荷メッセージ保存のためのRAM消費はありません。ストリーム長に応じてRAMを消費します(上限設定が必要です)。

3. Redis Streamsが分散システムに適する3つの柱

1. コンシューマグループの仕組み(Consumer Groups)

高負荷な処理(例:文書OCR、画像圧縮、大規模データ処理)では、単一のワーカーでは追いつきません。複数のワーカーが作業量を分担するグループが必要です。

Redis Streamsは、Apache Kafkaと同様のConsumer Groupsの概念を提供します。

  • 同一グループ内のワーカーは異なるメッセージを分担して読み取り、同じメッセージを2つのワーカーが重複処理しないことを保証します。
  • スケールアウトのために新しいワーカーを追加すると、複雑な設定変更なしにシステムが自動で負荷を再配分します。
flowchart LR
    Stream[(Redis Stream)]
    
    subgraph Group["Consumer Group: OCR_Workers"]
        W1[Worker 1]
        W2[Worker 2]
        W3[Worker 3]
    end
    
    Stream -->|タスクAを割り当て| W1
    Stream -->|タスクBを割り当て| W2
    Stream -->|タスクCを割り当て| W3

2. データ損失の防止(ACK & Pending Entries List)

Pub/Subでは、ワーカーがメッセージを受け取った後に停電やクラッシュが起きると、その作業は誰にも知られずに永久に失われます。

Redis Streamsは、**Pending Entries List(PEL)**によってこのリスクを徹底的に解消します。

  • ワーカーがメッセージを受け取ると、そのメッセージは「処理待ち」(Pending)状態へ移ります。
  • ワーカーが処理を完了し、**成功確認(ACK)**を送って初めて、メッセージは完了とマークされます。
  • 途中でワーカーが停止しても、メッセージはPELに残ります。他のワーカーは許容時間を超えて滞留しているタスクを確認し、**処理権を再取得(Claiming/Auto-claim)**できるため、タスクが脱落することはありません。

3. スマートなメモリ制御(Stream Trimming)

Streamはデータを永続保存するため、制御戦略がなければRedisのRAMはすぐに満杯になります。

Redis Streamsでは、**最大長の上限(Capped Streams)**を設定できます。

  • メッセージ数が許容閾値を超えると(例:直近10,000件のみ保持)、システムは最も古いメッセージを自動的に削除します。
  • 近似トリミング(Approximate Trimming)にも対応しており、Redis ServerのCPU性能を低下させずに、バックグラウンドでメモリを解放できます。

4. 実務での選定基準

アーキテクチャの本質を理解することで、リソースを無駄にせず、正確な技術判断ができます。

[あなたの課題は何か?]
      │
      ├── 超高速な伝達が必要で、数件の損失は許容できるか?
      │   (リアルタイムチャット、Notification、GPS座標の更新)
      │   └──► 選択: Redis Pub/Sub
      │
      ├── 信頼できるキュー処理、ワーカー負荷分散、リトライ機構が必要か?
      │   (文書OCRキュー、レポート出力、社内トランザクション処理)
      │   └──► 選択: Redis Streams
      │
      └── 数か月にわたる数十億件のイベント保存と、エンタープライズ級の複雑なルーティングが必要か?
          (全社Event Sourcing、Big Data分析)
          └──► 選択: Apache Kafka / RabbitMQ

Redis Pub/Subを選ぶべき場合

  • リアルタイム通知(Real-time Push): プッシュ通知(Push Notifications)の配信や、WebSocket経由のUI状態更新。
  • 即時計測データ(Metrics / Heartbeat): サービス監視のハートビートやリアルタイムチャートデータなど、最新情報が最も重要で、古い情報が落ちても再読込が不要な場面。

Redis Streamsを選ぶべき場合

  • 分散バックグラウンド処理(Task Queue): 文書の電子化、OCR、検索インデックス生成など、重い作業を複数ワーカーで並列に調整する場合。
  • サービス間の非同期データ同期: 受信側サービスが一時的にオフラインでも中断したくない場合に、あるサービスが他サービスへ状態を通知しつつ、データの完全性を確保します。
  • Kafka/RabbitMQの軽量な代替: すでにRedisがあり、メッセージ伝達の需要が中〜大規模であれば、Redis Streamsを活用することで、重いKafkaクラスタを構築する場合に比べ、運用コストとインフラの複雑さを大幅に削減できます。

おわりに

Redis Streamsは、Redis Pub/Subを完全に置き換えるために生まれたのではなく、Redisエコシステムにおける耐久性、耐障害性、負荷分散の仕組みという欠けていた環を補うためのものです。

不変ログのアーキテクチャと柔軟なコンシューマグループの仕組みを組み合わせることで、Redis Streamsは分散メッセージングの課題に対して「十分に強く、極めて軽い」解決策をもたらし、企業が最も最適化された運用コストで信頼性の高いタスク処理システムを構築できるよう支援します。


BK Hightechのエンジニアチームによる記事です。

Phan Van Tai

執筆 Phan Van Tai

ソフトウェアエンジニア、BK Hightech

一緒に、優れたプロダクトを作りませんか?

プロジェクトについてお聞かせください。1営業日以内にご連絡いたします。

お問い合わせ