Apache Kafkaとは、大量のメッセージ(イベント)を順番どおりにディスクへ記録し、複数のアプリが好きなタイミングで読み出せる「分散ログ」型のメッセージ基盤です。 送る側(プロデューサー)と受け取る側(コンシューマー)を切り離せるので、注文・在庫・通知のようにシステムをまたいでデータを流す仕組みに使われます。

Kafkaは4.0でZooKeeperが取り除かれ、KRaft(Kafka自身でメタデータを管理する方式)だけになりました。この記事では、2026年10月時点の最新版 Kafka 4.3.1 を前提に、フォーマット → 起動 → トピック作成 → 送信 → 受信 → グループ確認の最短手順を公式Quickstartに沿って紹介します。あわせて、用語の図解、Pythonのコピペ用コード、パーティション数・acks・retentionの決め方表、配信保証の比較、RabbitMQなどとの使い分けまで、入門者が最初につまずく所をまとめました。

検証について:この記事の作成環境ではKafka本体(Apache公式のダウンロード、Dockerイメージ)を入手できなかったため、Kafkaのコマンドは公式ドキュメントに沿って記載し、未実行です。Pythonコードは confluent-kafka 2.15.1(Python 3.11)で構文・importを確認し、ブローカーがない状態で実行したときの実際のログを載せています。

Kafka入門の早見表

やりたいこと コマンド・設定(Kafka 4.x)
クラスターIDを作る KAFKA_CLUSTER_ID="$(bin/kafka-storage.sh random-uuid)"
ストレージを初期化 bin/kafka-storage.sh format --standalone -t $KAFKA_CLUSTER_ID -c config/server.properties
ブローカーを起動 bin/kafka-server-start.sh config/server.properties
トピックを作る bin/kafka-topics.sh --create --topic orders --partitions 3 --replication-factor 1 --bootstrap-server localhost:9092
トピックの一覧・詳細 kafka-topics.sh --list / --describe --topic orders(どちらも --bootstrap-server 付き)
手で送信 bin/kafka-console-producer.sh --topic orders --bootstrap-server localhost:9092
先頭から受信 bin/kafka-console-consumer.sh --topic orders --from-beginning --bootstrap-server localhost:9092
グループで受信 上の受信コマンドに --group order-service
グループの遅れ(LAG)を見る bin/kafka-consumer-groups.sh --describe --group order-service --bootstrap-server localhost:9092
オフセットを巻き戻す kafka-consumer-groups.sh --reset-offsets --to-earliest --group order-service --topic orders --execute
パーティションを増やす kafka-topics.sh --alter --topic orders --partitions 6(減らすことはできない)
保持期間を変える kafka-configs.sh --alter --entity-type topics --entity-name orders --add-config retention.ms=259200000
Dockerで試す docker run -p 9092:9092 apache/kafka:4.3.1
必要なJava ブローカーは Java 17以上

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「Kafka入門|KRaftでトピック作成から消費まで最短手順」

Kafkaの用語を図で理解する

Kafkaは「トピック(名前のついたログ)」を「パーティション(分割された追記専用のファイル)」に分けて、複数のブローカー(サーバー)に置きます。 プロデューサーが末尾に追記し、コンシューマーは「オフセット(何番目まで読んだか)」を記録しながら読み進めます。

flowchart LR
    P1[プロデューサー<br/>注文サービス] -->|key=A001| T0
    P1 -->|key=A002| T1
    subgraph TP["トピック orders"]
        T0[パーティション0<br/>offset 0,1,2...]
        T1[パーティション1<br/>offset 0,1,2...]
        T2[パーティション2<br/>offset 0,1,2...]
    end
    subgraph G1["コンシューマーグループ order-service"]
        C1[コンシューマー1]
        C2[コンシューマー2]
    end
    T0 --> C1
    T1 --> C1
    T2 --> C2
    subgraph G2["別のグループ mail-service"]
        C3[コンシューマー3]
    end
    T0 -. 同じデータを独立して読む .-> C3
    T1 -.-> C3
    T2 -.-> C3
用語 ひとことで 入門で押さえる点
ブローカー Kafkaのサーバー1台 複数台でクラスターを組む。4.xではコントローラー役も兼ねられる
コントローラー クラスターのメタデータ(トピック・リーダーなど)を管理する役 KRaftではKafka自身が担当(以前のZooKeeperの役目)
トピック メッセージの分類名(orders など) データベースのテーブルに近いイメージ
パーティション トピックを分割した追記専用ログ 並列度の単位。順序が保証されるのはパーティションの中だけ
オフセット パーティション内の通し番号 コンシューマーは「どこまで読んだか」をオフセットで記録(コミット)
レコード 1件のメッセージ キー・値・タイムスタンプ・ヘッダーを持つ
キー パーティションを決める値 同じキーは同じパーティションに入るので、キー単位で順序が保たれる
プロデューサー 書き込む側のアプリ acks で「どこまで書けたら成功とするか」を決める
コンシューマー 読み出す側のアプリ 読んでもデータは消えない。保持期間が過ぎると消える
コンシューマーグループ 同じ group.id のコンシューマーの集まり グループ内でパーティションを分担。グループが違えば同じデータを別々に読める
レプリカ パーティションのコピー リーダー1つ+フォロワー。replication.factor で数を決める
ISR リーダーに追いついているレプリカの集合 acks=all はISR全員への書き込みを待つ

「読んでも消えない」「グループごとに独立して読める」がキュー型の仕組みとの一番の違いです。同じ注文イベントを、在庫サービスとメールサービスがそれぞれ自分のペースで読めます。

Kafka 4.xで変わったこと

版 主な変更(公式リリース告知より)
3.3 KRaftが本番利用可能に
4.0 ZooKeeperを削除しKRaftのみに。新しいコンシューマーリバランスプロトコル(KIP-848)が一般提供。ブローカーはJava 17以上
4.2 Queues for Kafka(共有グループ、KIP-932)が一般提供。1つのパーティションを複数のコンシューマーで分担して読める
4.3.1 2026年10月時点の最新版(公式Quickstart記載)

古い記事にある --zookeeper localhost:2181 オプションや zookeeper-server-start.sh は4.xでは使いません。 すべてのコマンドは --bootstrap-server でブローカーに直接つなぎます。

KRaftで動かす最短手順(公式Quickstartに沿って)

手順は「ダウンロード → クラスターIDを作る → フォーマット → 起動 → トピック作成 → 送受信」の6ステップです。ここではブローカーとコントローラーを1台で兼ねる、学習用の構成で動かします(未実行。公式Quickstartのコマンドに沿って記載)。

1. ダウンロードして展開する

公式サイトのダウンロードページから kafka_2.13-4.3.1.tgz を取得します(2.13 は内部で使うScalaの版で、利用者は気にしなくて大丈夫です)。

java -version          # 17以上であることを確認
tar -xzf kafka_2.13-4.3.1.tgz
cd kafka_2.13-4.3.1

2. クラスターIDを作ってストレージをフォーマットする

KAFKA_CLUSTER_ID="$(bin/kafka-storage.sh random-uuid)"
bin/kafka-storage.sh format --standalone -t $KAFKA_CLUSTER_ID -c config/server.properties

KRaftでは、起動の前にログディレクトリをフォーマットする必要があります。 --standalone は「コントローラー1台だけのクォーラム(合議の単位)を作る」という指定です。複数台のコントローラーで組む場合は --initial-controllers で参加者を列挙します。

config/server.properties の主な項目は次のとおりです(KRaftの1台構成)。

process.roles=broker,controller
node.id=1
controller.quorum.bootstrap.servers=localhost:9093
listeners=PLAINTEXT://:9092,CONTROLLER://:9093
advertised.listeners=PLAINTEXT://localhost:9092,CONTROLLER://localhost:9093
controller.listener.names=CONTROLLER
log.dirs=/tmp/kraft-combined-logs
num.partitions=1
項目 意味 変えるとき
process.roles このノードの役割 本番では broker と controller を別ノードに分けることが多い
node.id ノード番号 クラスター内で重複させない
listeners 待ち受けるアドレス ポートを変えるとき
advertised.listeners クライアントに教える接続先 別マシンやDockerから接続するときは、そこから届くホスト名にする
log.dirs データの保存先 /tmp は再起動で消えることがあるので、常設なら別のディレクトリへ

3. ブローカーを起動する

bin/kafka-server-start.sh config/server.properties

このターミナルは起動したままにして、以降は別のターミナルで操作します。

4. トピックを作る

bin/kafka-topics.sh --create --topic orders \
  --partitions 3 --replication-factor 1 \
  --bootstrap-server localhost:9092

bin/kafka-topics.sh --describe --topic orders --bootstrap-server localhost:9092

--describe では、パーティションごとに Leader(リーダーのノード番号)、Replicas(レプリカの置き場所)、Isr(追いついているレプリカ)が表示されます。1台構成では --replication-factor は1までです。

5. メッセージを送る(console-producer)

bin/kafka-console-producer.sh --topic orders --bootstrap-server localhost:9092
>注文A001を受け付けました
>注文A002を受け付けました

1行が1レコードになります。Ctrl-C で終了します。キーを付けて送りたいときは次のようにします。

bin/kafka-console-producer.sh --topic orders --bootstrap-server localhost:9092 \
  --property parse.key=true --property key.separator=:
>A001:ノート2冊
>A002:ペン5本

6. メッセージを受け取る(console-consumer)

bin/kafka-console-consumer.sh --topic orders --from-beginning \
  --bootstrap-server localhost:9092 \
  --property print.key=true --property print.partition=true

--from-beginning を付けないと「今から届くもの」だけが表示されます。何度実行しても同じデータが読めるのは、読んでもデータが消えないためです。

(コマンドラインの --property は新しい版で --reader-property/--formatter-property などへ名前の整理が進んでいます。手元の版の --help で確認してください。)

7. コンシューマーグループを確認する

# グループ名を付けて受信(別ターミナルで2つ起動すると、パーティションを分担する)
bin/kafka-console-consumer.sh --topic orders --group order-service \
  --bootstrap-server localhost:9092

# グループの一覧と状態
bin/kafka-consumer-groups.sh --list --bootstrap-server localhost:9092
bin/kafka-consumer-groups.sh --describe --group order-service --bootstrap-server localhost:9092

--describe の主な列は次のとおりです。

列 意味
PARTITION パーティション番号
CURRENT-OFFSET グループがコミットした「次に読む位置」
LOG-END-OFFSET パーティションの末尾
LAG 未処理の件数(末尾 − 現在位置)。増え続けるなら処理が追いついていない
CONSUMER-ID / HOST どのコンシューマーが担当しているか

オフセットの巻き戻しは、グループのコンシューマーをすべて止めてから行います。--dry-run で確認してから --execute にすると安心です。

bin/kafka-consumer-groups.sh --reset-offsets --to-earliest \
  --group order-service --topic orders --dry-run --bootstrap-server localhost:9092

Dockerで試す場合

docker run -p 9092:9092 apache/kafka:4.3.1

公式イメージは既定でKRaftの1台構成が起動します。コマンドはコンテナの中の /opt/kafka/bin/ にあります(例:docker exec -it <コンテナ名> /opt/kafka/bin/kafka-topics.sh ...)。

Pythonでプロデューサーとコンシューマーを作る(confluent-kafka)

PythonからはConfluentが提供する confluent-kafka(C言語のlibrdkafkaを使う公式系クライアント)がよく使われます。pip install confluent-kafka だけで入り、ライブラリのビルドは不要です。

ライブラリ 特徴
confluent-kafka librdkafkaベースで高速。設定名がKafka本体と同じ(acks、enable.idempotence など)
kafka-python 純Python。軽く試すとき向け
aiokafka asyncio対応

プロデューサー(producer.py)

# pip install confluent-kafka   (確認:confluent-kafka 2.15.1 / Python 3.11)
import json
from confluent_kafka import Producer

conf = {
    "bootstrap.servers": "localhost:9092",
    "acks": "all",                 # 全ISRへの書き込みを待つ
    "enable.idempotence": True,    # 再送しても重複しない
    "linger.ms": 5,                # 少し待ってまとめて送る
}
producer = Producer(conf)

def on_delivery(err, msg):
    if err is not None:
        print(f"送信失敗: {err}")
    else:
        print(f"送信OK: topic={msg.topic()} partition={msg.partition()} offset={msg.offset()} key={msg.key().decode()}")

orders = [
    {"order_id": "A001", "item": "ノート", "qty": 2},
    {"order_id": "A002", "item": "ペン", "qty": 5},
    {"order_id": "A001", "item": "ノート", "qty": 1},
]
for o in orders:
    producer.produce(
        "orders",
        key=o["order_id"],                       # 同じキーは同じパーティションへ
        value=json.dumps(o, ensure_ascii=False),
        on_delivery=on_delivery,
    )
    producer.poll(0)                             # コールバックを処理

remaining = producer.flush(10)                   # 最大10秒、送信完了を待つ
print("未送信:", remaining)

produce() は送信を予約するだけで、実際の送信はバックグラウンドで行われます。 終了前に flush() を呼ばないと、送信待ちのメッセージが残ったままプログラムが終わります。

ブローカーを起動していない状態で実行したときの実際の出力です(Kafkaに届かない場合の動きの確認)。

%3|1790860397.125|FAIL|rdkafka#producer-1| [thrd:localhost:9092/bootstrap]: localhost:9092/bootstrap: Connect to ipv4#127.0.0.1:9092 failed: Connection refused (after 0ms in state CONNECT)
%3|1790860397.177|FAIL|rdkafka#producer-1| [thrd:localhost:9092/bootstrap]: localhost:9092/bootstrap: Connect to ipv4#127.0.0.1:9092 failed: Connection refused (after 0ms in state CONNECT, 1 identical error(s) suppressed)
未送信: 3

接続できなくても produce() 自体はエラーにならず、flush() の戻り値(未送信件数)に表れます。 送信の成否は on_delivery のコールバックか flush() の戻り値で確認します。ブローカーが動いていれば、コールバックで 送信OK: topic=orders partition=... offset=... が表示されます(この行はブローカーなしでは確認できていません)。

コンシューマー(consumer.py)

# pip install confluent-kafka
import json
from confluent_kafka import Consumer, KafkaError, KafkaException

conf = {
    "bootstrap.servers": "localhost:9092",
    "group.id": "order-service",       # 同じgroup.idのコンシューマーでパーティションを分担
    "auto.offset.reset": "earliest",   # コミット済みオフセットがなければ先頭から
    "enable.auto.commit": False,       # 処理が終わってから手動でコミット
}
consumer = Consumer(conf)
consumer.subscribe(["orders"])

try:
    while True:
        msg = consumer.poll(1.0)
        if msg is None:
            continue
        if msg.error():
            if msg.error().code() == KafkaError._PARTITION_EOF:
                continue
            raise KafkaException(msg.error())
        order = json.loads(msg.value())
        print(f"受信: partition={msg.partition()} offset={msg.offset()} {order}")
        # ここで注文を処理する
        consumer.commit(message=msg, asynchronous=False)
except KeyboardInterrupt:
    pass
finally:
    consumer.close()   # グループから抜けて再割り当てを早める

「処理してからコミット」にすると、途中で止まっても未処理のメッセージを読み直せます(at-least-once)。 そのかわり同じメッセージを2回処理することがあるので、処理側は「同じ注文IDなら1回だけ反映する」ように作っておきます。

設定 既定 入門での指針
auto.offset.reset latest 初回に過去分も読みたいなら earliest
enable.auto.commit true 取りこぼしを避けたいなら false にして処理後に commit()
max.poll.interval.ms 300000(5分) 1件の処理がこれを超えるとグループから外され、再割り当てが起きる
session.timeout.ms 45000 心拍が途絶えたと判断するまでの時間

設定の決め方:パーティション数・acks・retention・レプリカ数

項目 既定値 決め方の目安
パーティション数 num.partitions=1 同時に動かしたいコンシューマー数以上にする。グループ内で1パーティションを読めるのは1台なので、3パーティションなら最大3台で並列処理。あとから増やせるが、増やすとキーの振り分け先が変わり、キー単位の順序が途切れるので最初に余裕をもたせる
レプリカ数 default.replication.factor=1 本番は 3 が一般的(ブローカー3台以上)。学習用の1台構成は1
min.insync.replicas 1 レプリカ3なら 2。acks=all と組み合わせて「2台以上に書けたら成功」にする
acks all(3.0以降の既定) 下の表を参照。迷ったら all のまま
enable.idempotence true(Javaクライアント3.0以降の既定。confluent-kafkaは false) 再送による重複を防ぐ。Pythonでは明示的に True にする
retention.ms 604800000(7日) 読み直したい期間+余裕。容量で制限するなら retention.bytes
cleanup.policy delete キーごとに最新値だけ残したいなら compact
max.message.bytes 約1MB 大きなファイルは別の保存先に置き、Kafkaには場所だけ流す

acks の比較

acks 成功とみなすタイミング 速さ データの残りやすさ
0 送った時点(応答を待たない) 最も速い ブローカー障害時に失われることがある
1 リーダーが書いた時点 速い リーダーが落ちる直前の分は失われることがある
all(-1) ISR全員が書いた時点 やや遅い 最も残りやすい。min.insync.replicas と組み合わせる

配信保証の比較

保証 意味 Kafkaでの実現方法 向いている処理
at-most-once 最大1回(失われることがある) 読んだらすぐコミット → 処理 一部が欠けてもよいログ集計
at-least-once 最低1回(重複することがある) 処理 → コミット。acks=all 多くの用途の基本。処理側で重複を吸収する
exactly-once ちょうど1回 冪等プロデューサー+トランザクション(transactional.id、コンシューマーは isolation.level=read_committed) Kafkaから読んでKafkaへ書く変換処理

exactly-onceはKafkaの中で完結する処理(読んで加工して別トピックへ書く)が対象です。外部のデータベースへ書く場合は、注文IDで重複を判定するなど処理側の工夫と組み合わせます。

RabbitMQなどとの使い分け

観点 Apache Kafka RabbitMQ クラウドのキュー(SQS など)
モデル 分散ログ(読んでも残る) メッセージブローカー(読んだら消える) マネージドなキュー
同じデータを複数のシステムで読む 得意(グループごとに独立) Exchangeで複製して配る トピック型サービスと組み合わせる
過去のデータの読み直し 得意(オフセットを戻す) 基本はしない 基本はしない
大量データの流し込み 得意 中程度 サービスの上限内
1件ずつの細かいルーティング・優先度 得意ではない 得意 機能による
運用の手間 多め(クラスター・容量設計) 中程度 少ない
向いている例 注文・在庫などのイベント配信、ログ集約、変更データの連携 仕事の振り分け、リクエスト/リプライ 小〜中規模の非同期処理

「同じイベントを複数のシステムが使う」「あとから読み直したい」ならKafka、「タスクを1回ずつ確実に誰かへ渡したい」ならRabbitMQやクラウドのキューが選びやすいです。Kafka 4.2以降は共有グループ(Queues for Kafka)で、キューに近い使い方もできるようになりました。

よくあるエラーと対処

Kafka本体は未実行のため、下表のメッセージは公式ドキュメント・クライアントの例外名に基づきます(1行目のみ、この記事の環境で実際に出力を確認)。

症状・メッセージ 原因 対処
Connect to ipv4#127.0.0.1:9092 failed: Connection refused(librdkafka、実行確認済み) ブローカーが起動していない/ポート違い kafka-server-start.sh の起動ログを確認、bootstrap.servers を見直す
起動時に meta.properties が見つからない旨のエラー ストレージ未フォーマット kafka-storage.sh format を実行してから起動
フォーマット時にクラスターIDの不一致 以前のデータが log.dirs に残っている 学習用なら log.dirs を消してフォーマットし直す
InvalidReplicationFactorException(Replication factor larger than available brokers) ブローカー台数よりレプリカ数が多い 1台構成なら --replication-factor 1
UNKNOWN_TOPIC_OR_PARTITION トピックが存在しない kafka-topics.sh --create で作る。本番では自動作成(auto.create.topics.enable)に頼らない
NOT_ENOUGH_REPLICAS ISR数が min.insync.replicas 未満で acks=all ブローカーの状態を確認、レプリカ数と min.insync.replicas を見直す
RecordTooLargeException メッセージが上限(約1MB)を超えた データを分割するか、外部に置いて参照だけ送る
別マシンやDockerの外から接続すると、つながった直後に失敗する advertised.listeners がクライアントから届かないアドレス クライアントから見えるホスト名・ポートにする
LAGが減らない、リバランスが繰り返される 処理が max.poll.interval.ms を超えている 1回の取得件数(max.poll.records)を減らす、処理を速くする
--zookeeper オプションが使えない 4.xではZooKeeperが削除済み --bootstrap-server localhost:9092 を使う

よくある質問

Q. ZooKeeperはもう不要ですか? A. はい。Kafka 4.0以降はKRaftのみで、ZooKeeperは使いません。 3.x以前のZooKeeper構成から上げる場合は、3.x系の途中で「ZooKeeperからKRaftへの移行」を済ませてから4.xへ上げる流れが公式に案内されています。

Q. パーティション数はいくつにすればよいですか? A. 同時に処理したいコンシューマーの数以上が目安です。増やすことはできても減らせないこと、増やすとキーの割り当て先が変わることから、将来の台数を見込んで少し多めにします。学習用なら3で十分です。

Q. メッセージの順序は保証されますか? A. 同じパーティションの中だけ保証されます。 注文ごとに順序が必要なら、注文IDをキーにして同じパーティションに入れます。トピック全体で厳密な順序が必要なら、パーティションを1つにする方法もありますが、並列処理はできなくなります。

Q. 読んだメッセージはいつ消えますか? A. 読んだかどうかとは関係なく、retention.ms(既定7日)や retention.bytes を超えた古いものから消えます。 コンシューマーが何を読んだかはオフセットで管理されます。

まとめ

  • Kafkaは「読んでも消えない分散ログ」。グループごとに同じデータを独立して読める
  • 4.0以降はKRaftのみ。kafka-storage.sh format → kafka-server-start.sh で起動し、すべて --bootstrap-server で操作
  • パーティションは並列度と順序の単位。同じキーは同じパーティションに入り、順序が保たれる
  • Pythonは confluent-kafka。produce() 後の flush()、処理後の commit() が基本
  • 迷ったら acks=all・レプリカ3・min.insync.replicas=2、配信保証はat-least-onceと重複に強い処理の組み合わせ
  • 複数システムへの配信や読み直しならKafka、タスクの振り分けならRabbitMQやクラウドのキュー

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「Kafka入門|KRaftでトピック作成から消費まで最短手順」

株式会社RJCでは、Kafkaをはじめとするメッセージ基盤の仕組みを仲間と学び合っています。こうした知識を共有しながら、日々技術を磨いています。

株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。

WE ARE HIRING

RJCで一緒に開発しながら、
成長を楽しみませんか?

RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!

  • 127日年間休日
  • 12時間平均残業時間
  • 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!

ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。

ABOUT RJC RJCがどんな会社か知る 考え方、研修、働き方、福利厚生、社員の前職まで。RJCのことが丸わかり! RJC丸わかりページへ JOB DESCRIPTION 仕事内容・待遇を見てみる 仕事内容、給与・待遇、選考の流れ。経験者も未経験も!応募前に知りたいこと、まとめました! 募集要項を見る ENTRY エントリーする エントリーは1〜2分・履歴書不要です。まずは話を聞いてみたい、という方でも歓迎です! エントリーフォームへ

RJCで一緒に開発しながら、 成長を楽しみませんか?