みなさんこんにちは!本ブログではApache Kafkaの強力なコア概念である「コンシューマーグループ(Consumer Group)」を取り上げていきます。今回はPythonとtmux(4分割ターミナル)を使い、トピックへ100件のイベントを送信した際の挙動と、裏側の分散ロジックについて検証した記録をまとめました。
1. コンシューマーグループ(Consumer Group)とは
Kafkaは、データを受け取る受信アプリを「グループ」という単位で管理します。このグループの組み方によって、1つのトピックに対して2つの異なる挙動を同時に実現できます。
- 異なるグループ間 ➔ パブサブ型(イベントの複製): 別のグループ同士には、まったく同じデータがそれぞれ全件コピー(複製)されて配信されます。
- 同じグループ内 ➔ キュー型(負荷分散): 同一グループ内のサーバー同士では、データを重複することなく綺麗に分担して配信されます。
2. 検証デモの実行手順と環境構成
パーティション数を「3」に設定したトピック five を作成し、ターミナルをtmuxで4分割して以下の手順で検証を行いました。
- 【左上・左下ペイン】 Group-X(2台起動): 負荷分散を検証するコンシューマー(Consumer-X1 / X2)
- 【右上ペイン】 Group-Y(1台起動): イベントの複製(全件受信)を検証するコンシューマー(Consumer-Y1)
- 【右下ペイン】 Producer: 送信側から
userA50件、userB50件(計100件)を連続送信
3. 使用したPythonスクリプト
検証に使用した主要なソースコードです。(事前に pip install confluent-kafka の実行が必要です)
■ 受信側:consumer_flexible.py
from confluent_kafka import Consumer
import sys
group_id = sys.argv[1]
consumer_id = sys.argv[2]
conf = {
'bootstrap.servers': 'localhost:9092',
'group.id': group_id,
'auto.offset-reset': 'earliest'
}
consumer = Consumer(conf)
consumer.subscribe(['five'])
print(f"--- 【{consumer_id}】 グループ【{group_id}】としてデータ待ち中... ---")
try:
count = 0
while True:
msg = consumer.poll(1.0)
if msg is None: continue
if msg.error(): continue
count += 1
print(f"[{count}件目] Key: {msg.key().decode('utf-8')}, Value: {msg.value().decode('utf-8')}")
except KeyboardInterrupt:
pass
finally:
consumer.close()
■ 送信側:key_producer.py
from confluent_kafka import Producer
import time
p = Producer({'bootstrap.servers': 'localhost:9092'})
print("データの送信を開始します(100件)...")
for i in range(50):
p.produce('five', key='userA', value=f'data-A-{i}')
p.produce('five', key='userB', value=f'data-B-{i}')
p.flush()
time.sleep(0.05)
print("送信完了")
4. デモの実行結果と受信件数
▼ デモ実行画面(プロデューサーからイベント送信中の様子)

イベント送信完了後、各ペインに立ち上げたコンシューマーの受信ログおよび最終的な合計件数は以下の通りになりました。
| グループ名 | サーバーID | 最終受信件数 | ログから見えた決定的な特徴 |
|---|---|---|---|
| Group-X (2台構成) | Consumer-X1 | 50件 | userB のイベントのみを100%固定受信(負荷分散) |
| Consumer-X2 | 50件 | userA のイベントのみを100%固定受信(負荷分散) | |
| Group-Y (1台構成) | Consumer-Y1 | 100件 | 全件(userA userB)を漏れなく受信(イベントの複製) |
なぜ自動的に綺麗に分かれたのか?裏側の仕様
ソースコード側には割り当ての設定を1行も記述していません。それなのにこの結果になったのは、Kafkaのデフォルトの仕様によるものです。
- Keyによる「固定配置」: 送信時にユーザー名をKeyに指定したため、Kafkaが自動的にハッシュ値を計算し、
userAはパーティション2、userBはパーティション1へと固定配置しました。 - 重複なき「自動割り当て」: 3つのパーティションに対して同じグループに2台のサーバーがいたため、Kafkaは裏側で自動的に仕事を割り振りました(X1がパーティション1、X2がパーティション2を担当)。
この2つの標準仕様が合体した結果、「負荷を完全に分散させつつ、同じユーザーのデータは必ず同じサーバーに届く(順序性の保証)」という挙動が完全自動で実現しています。
5. まとめ
今回の実証デモを通して、コンシューマーグループを分けることで「イベントの複製(並列処理)」、グループ内では「負荷分散・順序保証」が完璧に行えることが確認できました。
データ量が増えても、プログラムを1行も変えずにコンシューマーの台数を増やすだけで処理能力を水平スケールできる、Kafkaの洗練された設計の美しさを体感できる検証となりました。


