はじめに
本記事では、メッセージングシステムとして代表的な Apache Pulsar と Apache Kafka を比較しながら、以下の点に着目して解説します。
- 両者における サブスクリプションモデルの違い
- Producer 側の ルーティング方式
- 順序保証(Ordering)の考え方
- Pulsar のサブスクリプションタイプを使った 具体的なユースケース例
Pulsar は「サブスクリプションタイプ」を複数用意しており、1つのトピックに対して異なるタイプのコンシューマを同時に動かすことが可能です。一方 Kafka では、1つの「Consumer Group」で「パーティション割り当て」中心のモデルが確立されており、並列度の確保と順序保証はパーティション単位で管理するのが基本となります。
1. サブスクリプションモデルの違い
1-1. Kafka の場合
- Consumer Group に属する複数の Consumer は、Kafka ブローカーから パーティションごと に割り当てを受けます。
- 1パーティション = 1Consumer の関係が基本で、パーティション内のメッセージは常に同じ Consumer が読むことになります。
- 並列度を上げたい場合は、パーティション数を増やし、Consumer をスケールアウトさせる設計が必要です。
- パーティション内部でさらに並列化したい場合は、アプリケーション側で工夫(スレッドプールなど)して順序を崩さないよう制御する必要があります。
1-2. Pulsar の場合
Pulsar には 4種類のサブスクリプションタイプ が存在し、Consumer がトピックを購読するときに指定できます。1つのトピックに対して複数のサブスクリプションを張ることも可能で、それぞれ異なるタイプを選べます。
Exclusive
- 1つのサブスクリプションに対し 1つの Consumer だけがアクティブにメッセージを受け取る。
- 完全にシリアルな読み出しが可能。
Failover
- 複数の Consumer が同じサブスクリプションを購読できるが、同時にアクティブなのは 1つだけ。
- アクティブな Consumer が落ちたときに フェイルオーバー で別の Consumer が引き継ぐ。
- Exclusive と同様にシリアルな読み出しを行いつつ、高可用性を確保できる。
Shared
- 1つのサブスクリプションに 複数の Consumer が同時に参加し、メッセージを ラウンドロビン などで振り分ける。
- パーティション内の順序保証は崩れる 代わりに、高いスループットを得られる。
Key_Shared
- Shared と似ているが、Message Key (Producer 側で設定) ごとに 同じ Consumer に割り当てる。
- 同じ Key のメッセージ は必ず同じ Consumer が受け取り、パーティション内でキー単位の順序が保たれる。
- 異なる Key は別の Consumer が同時に処理するため、キーごとのシリアル処理を維持しつつ並列化が可能。
2. ルーティング方式の違い (Producer 側)
2-1. Kafka
- Producer でメッセージを送る際、Key を指定すると、その Key のハッシュ値をもとに 特定パーティション へ常にルーティングされます。
- Key を指定しない場合はラウンドロビンなどでパーティションが割り当てられることが多いです。
- 同じ Key のメッセージを同じパーティションに集約 できるのが特徴。
2-2. Pulsar
- Pulsar の Producer も似たように、メッセージごとに
messageKey
をセットし、パーティションルーティングを KeyHash に切り替える ことで、同じ Key が同じパーティションへ送られます。 - 何も指定しなければデフォルトはラウンドロビンなど、設定次第で柔軟に振り分けることができます。
- Key_Shared サブスクリプションと組み合わせると、「同じ Key → 同じパーティション → 同じ Consumer」 のフローを構築可能です。
3. 順序保証の考え方
3-1. パーティション内の順序
- Kafka / Pulsar ともに、単一パーティション ではメッセージが受信された順に append-only なログとしてブローカーに保存されます。
- Consumer はそのログをオフセット順に読み出すため、パーティション内のメッセージ順序は保証 されます。
- 複数 Producer が同じパーティションに書き込む場合、ブローカーが受信した順序 で確定し、Producer の送信時刻順とは必ずしも一致しない点は共通です。
3-2. パーティションをまたぐグローバル順序
- いずれのシステムも、パーティションをまたぐグローバルな順序保証は行いません。
- パーティション間で到着時刻が前後するのは一般的で、完全な時系列を保つにはアプリケーション側の追加ロジックが必要です。
- 「すべてのメッセージで厳密な順序が必要」な場合は パーティション数を1つ にするか、キーを工夫して常に同じパーティションへルーティングする必要があります。
3-3. Pulsar におけるサブスクリプションタイプと順序の関係
- Exclusive / Failover
- 1つの Consumer (またはアクティブ1台) がすべてのメッセージを読み取るため、パーティション内の完全な順序が保たれる。
- Shared
- パーティション内のメッセージが複数 Consumer に分散するため、グローバルな順序は崩れる。
- Key_Shared
- 同じ Key のメッセージ は順序が保証される一方、Key が異なるもの同士 では順序は保証されない。
- これは Kafka でも同じパーティションにキーを集めれば保持できる考え方と同様だが、Pulsar はキー単位で Consumer を自動振り分けする仕組みが標準機能として提供されている点が特徴的。
4. サブスクリプションタイプを活かしたユースケース実例
Pulsar では、1つのトピック に複数のサブスクリプションを張り、それぞれ 異なるサブスクリプションタイプ を同時に利用できます。
ここでは具体例を 3つ示します。
4-1. 監査ログ + リアルタイム分析
シナリオ
- トピック
audit-logs
にユーザ操作ログなどを集積している。 - 監査 向けには「時系列どおり全メッセージを1台で処理」したい (順序重視)。
- リアルタイム分析 向けには「並列分散」して高スループットで処理したい (スピード重視)。
実装イメージ
監査向けサブスクリプション
- サブスクリプション名:
audit-subscription
- タイプ: Exclusive (もしくは Failover)
- 1台(またはフェイルオーバー構成)でログをすべて取得し、厳密な時系列で保存・検証する。
- サブスクリプション名:
分析向けサブスクリプション
- サブスクリプション名:
analysis-subscription
- タイプ: Shared
- 複数インスタンスで並列に取り込み、リアルタイム集計・ダッシュボード更新などを行う。
- サブスクリプション名:
4-2. ユーザIDごとのワークフロー制御 + バッチ処理
シナリオ
- ECサイトのイベント
user-events
。 - リアルタイムには 「ユーザID単位の順序」を守りたい (注文→決済→配送リクエスト などのステートマシン処理)。
- 別途 バッチ処理 で全メッセージを定期的に取得し、大規模分析したい。
実装イメージ
ワークフロー制御用サブスクリプション
- サブスクリプション名:
workflow-subscription
- タイプ: Key_Shared
userId
をキーとして、同じユーザIDのイベントは必ず同じ Consumer が順序通りに処理する。
- サブスクリプション名:
バッチ用サブスクリプション
- サブスクリプション名:
batch-subscription
- タイプ: Exclusive / Failover / Shared のいずれか
- 定期的に全メッセージを取得し、Hadoop/Spark などでまとめて分析。
- サブスクリプション名:
4-3. 高信頼レプリケーション + 即時アラート
シナリオ
- IoT センサーからのデータ
sensor-data
が大量に流れてくる。 - すべてのデータを バックアップ (外部ストレージなど) し、高い耐久性を確保したい。
- 一方で リアルタイムアラート (閾値超過検知など) にも活用したい。
実装イメージ
レプリケーション/バックアップ用サブスクリプション
- サブスクリプション名:
backup-subscription
- タイプ: Exclusive (または Failover)
- 1台がすべてのメッセージを漏れなく取り込み、外部に連携する。
- 障害時は Failover で別 Consumer がすぐに引き継ぐ。
- サブスクリプション名:
リアルタイムアラート用サブスクリプション
- サブスクリプション名:
alert-subscription
- タイプ: Shared
- センサーイベントを並列に処理し、閾値超過時に即アラートを発行。
- スケールアウトしやすく、高速応答が期待できる。
- サブスクリプション名:
5. まとめ
- 順序保証(Ordering) の観点では、Kafka も Pulsar も 「パーティション単位で到着順を保証し、パーティション間のグローバル順序は保証しない」 という点では共通しています。
- 違い は、Pulsar が標準で持つ 多様なサブスクリプションタイプ による Consumer モデルの柔軟性 にあります。
- Kafka では「Consumer Group → パーティション割り当て」で順序制御するのが主流。1パーティションを複数 Consumer で並行処理したい場合はアプリケーション側の管理が必要。
- Pulsar では Shared / Key_Shared が用意されており、パーティション内でも並列かつ Key 単位で順序を維持 するような運用が容易です。
- 同じトピックを複数の目的で読みたい場合、Kafka では通常トピックを複製するか Consumer Group を別々に作成しますが、Pulsar では「サブスクリプションごとに異なるタイプ」を併用 できるため、1つのデータストリームをより多角的に活用できるのが特徴です。
以上のように、Pulsar vs Kafka の比較ポイントとして、
- サブスクリプション(コンシューマモデル)
- Producer からのルーティング
- 順序保証の範囲(パーティション内 vs グローバル)
- ユースケース別の活用方法
を理解しておくと、要件に合ったメッセージング設計を行いやすくなります。