<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>奥井 一暁 (Kazuaki Okui) &#8211; SRA OSS Tech Blog</title>
	<atom:link href="https://www.sraoss.co.jp/tech-blog/author/okui/feed/index.xml" rel="self" type="application/rss+xml" />
	<link>https://www.sraoss.co.jp/tech-blog/</link>
	<description>OSS専門の技術ブログ。PostgreSQL、Zabbixを中心に10種類以上のOSSの解説、アップデート情報、運用ヒントを提供。</description>
	<lastBuildDate>Wed, 04 Nov 2026 06:56:48 +0000</lastBuildDate>
	<language>ja</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.1.3</generator>

<image>
	<url>https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2018/07/blog-icon-150x150.png</url>
	<title>奥井 一暁 (Kazuaki Okui) &#8211; SRA OSS Tech Blog</title>
	<link>https://www.sraoss.co.jp/tech-blog/</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Apache Kafka のトランザクションについて</title>
		<link>https://www.sraoss.co.jp/tech-blog/kafka/kafka-transaction/</link>
		
		<dc:creator><![CDATA[奥井 一暁 (Kazuaki Okui)]]></dc:creator>
		<pubDate>Tue, 17 Mar 2026 01:00:37 +0000</pubDate>
				<category><![CDATA[Kafka]]></category>
		<category><![CDATA[Apache Kafka]]></category>
		<category><![CDATA[OSS]]></category>
		<guid isPermaLink="false">https://www.sraoss.co.jp/tech-blog/?p=19910</guid>

					<description><![CDATA[Apache Kafka（以下 Kafka）ではメッセージ送信をトランザクションにまとめてアトミックに行うことができます。 さらに Kafka から取り出したメッセージに何らかの処理を行い再度 Kafka に書き込む、と ...]]></description>
										<content:encoded><![CDATA[<p class="code-line" dir="auto" data-line="2">Apache Kafka（以下 Kafka）ではメッセージ送信をトランザクションにまとめてアトミックに行うことができます。</p>
<p class="code-line" dir="auto" data-line="2">さらに Kafka から取り出したメッセージに何らかの処理を行い再度 Kafka に書き込む、という処理を行うにあたっては Offset Commit もトランザクションに含めることができます。</p>
<p class="code-line" dir="auto" data-line="2">この記事ではトランザクションを用いて送信したメッセージが後段で読まれるまでの流れを説明し、さらに Offset Commit をトランザクション内で行う際の流れについても説明します。</p>
<p dir="auto" data-line="2"><span id="more-19910"></span></p>
<p class="code-line" dir="auto" data-line="4">Kafka バージョンは 4.1.0 を用います。</p>
<h2 id="%E3%83%88%E3%83%A9%E3%83%B3%E3%82%B6%E3%82%AF%E3%82%B7%E3%83%A7%E3%83%B3%E3%81%A7%E3%83%A1%E3%83%83%E3%82%BB%E3%83%BC%E3%82%B8%E3%82%92%E9%80%81%E3%82%8B%E6%B5%81%E3%82%8C" class="code-line" dir="auto" data-line="6">トランザクションでメッセージを送る流れ</h2>
<p>メッセージ送信だけでなく Offset Commit も一つのトランザクションにまとめられるのが Kafka のトランザクションの特徴ですが、まずトランザクションを用いて単純にメッセージを送る流れから説明します。</p>
<p class="code-line" dir="auto" data-line="10">トランザクションを使用してメッセージを送信する際の大まかな流れは以下の通りです (すべて正常に送信できた場合)。</p>
<p dir="auto" data-line="10"><img fetchpriority="high" decoding="async" class="alignnone wp-image-20030 size-large" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction0-2-1024x363.png" alt="" width="1024" height="363" srcset="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction0-2-1024x363.png 1024w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction0-2-300x106.png 300w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction0-2-768x272.png 768w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction0-2-1536x545.png 1536w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction0-2-2048x726.png 2048w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction0-2-304x108.png 304w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction0-2-282x100.png 282w" sizes="(max-width: 1024px) 100vw, 1024px" /></p>
<ol class="code-line" dir="auto" data-line="14">
<li class="code-line" dir="auto" data-line="14">トランザクションを初期化</li>
<li class="code-line" dir="auto" data-line="15">トランザクションを開始</li>
<li class="code-line" dir="auto" data-line="16">メッセージを送信 (ここでは送信先は Topic A)</li>
<li class="code-line" dir="auto" data-line="17">トランザクションを Commit</li>
</ol>
<p class="code-line" dir="auto" data-line="21">このように大まかな流れはデータベースのトランザクションと同様です。そして各ステップでそれぞれ以下のメソッドが対応します。</p>
<ol class="code-line" dir="auto" data-line="23">
<li class="code-line" dir="auto" data-line="23">トランザクションを初期化 (initTransactions メソッド)</li>
<li class="code-line" dir="auto" data-line="24">トランザクションを開始 (beginTransaction メソッド)</li>
<li class="code-line" dir="auto" data-line="25">メッセージを送信 (send メソッド)</li>
<li class="code-line" dir="auto" data-line="26">トランザクションを Commit (commitTransaction メソッド)</li>
</ol>
<p class="code-line" dir="auto" data-line="28">また送信中に例外が起きた場合などは abortTransaction メソッドによりトランザクションを Abort します。これらはすべて Producer のメソッドです。</p>
<h2 id="%E3%83%88%E3%83%A9%E3%83%B3%E3%82%B6%E3%82%AF%E3%82%B7%E3%83%A7%E3%83%B3%E3%81%AE%E6%8C%99%E5%8B%95" class="code-line" dir="auto" data-line="30">トランザクションの挙動</h2>
<p class="code-line code-active-line" dir="auto" data-line="30">ここからは各メソッドがどのように動作するかを説明します。</p>
<h3 id="1-%E3%83%88%E3%83%A9%E3%83%B3%E3%82%B6%E3%82%AF%E3%82%B7%E3%83%A7%E3%83%B3%E3%81%AE%E5%88%9D%E6%9C%9F%E5%8C%96-inittransactions" class="code-line" dir="auto" data-line="34">1. トランザクションの初期化 (initTransactions)</h3>
<p class="code-line" dir="auto" data-line="36">まずトランザクションを利用する前に initTransactions を呼び出します。このメソッドでは Transaction Coordinator に InitProducerId リクエストを送信してトランザクション初期化の処理を行います。InitProducerId リクエストには TransactionalID が含まれています。これは Producer のパラメータで、トランザクションを識別できるようにクラスタ内で一意になるよう設定します。初期化処理ではこの ID をもとに Transaction Coordinator から Producer ID を取得します。initTransactions は Producer 起動時に 1 回実行する必要があります。</p>
<p dir="auto" data-line="36"><img decoding="async" class="alignnone size-large wp-image-20035" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction3-2-1024x317.png" alt="" width="1024" height="317" srcset="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction3-2-1024x317.png 1024w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction3-2-300x93.png 300w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction3-2-768x238.png 768w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction3-2-1536x476.png 1536w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction3-2-304x94.png 304w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction3-2-282x87.png 282w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction3-2.png 1743w" sizes="(max-width: 1024px) 100vw, 1024px" /></p>
<h3 id="2-%E3%83%88%E3%83%A9%E3%83%B3%E3%82%B6%E3%82%AF%E3%82%B7%E3%83%A7%E3%83%B3%E3%81%AE%E9%96%8B%E5%A7%8B-begintransaction" class="code-line" dir="auto" data-line="40">2. トランザクションの開始 (beginTransaction)</h3>
<p class="code-line" dir="auto" data-line="42">次に beginTransaction メソッドによってトランザクションを開始します。このメソッドでは Transaction Coordinator にリクエストを送るわけではなく Producer 内部の状態を変更することでトランザクションを開始します。</p>
<p dir="auto" data-line="42"><img decoding="async" class="alignnone size-large wp-image-20037" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction4-1-1024x317.png" alt="" width="1024" height="317" srcset="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction4-1-1024x317.png 1024w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction4-1-300x93.png 300w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction4-1-768x238.png 768w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction4-1-1536x476.png 1536w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction4-1-304x94.png 304w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction4-1-282x87.png 282w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction4-1.png 1743w" sizes="(max-width: 1024px) 100vw, 1024px" /></p>
<h3 id="3-%E3%83%A1%E3%83%83%E3%82%BB%E3%83%BC%E3%82%B8%E3%82%92%E9%80%81%E4%BF%A1-send" class="code-line" dir="auto" data-line="46">3. メッセージを送信 (send)</h3>
<p class="code-line" dir="auto" data-line="48">メッセージの送信は通常の送信と同様 send メソッドを用います。基本的には通常の送信と同じ挙動なのですが、Broker はトランザクション中の Produce リクエストを受け取るとメッセージの書き込みの前に (未実施であれば) AddPartitionsToTxn というリクエストを Transaction Coordinator に送ります。このリクエストでは書き込み先の Topic と Partition を Transaction Coordinator に知らせ、__transaction_state というトランザクション管理用内部 Topic に記録します。これによってどの Partition がトランザクション中なのか記録することができます。</p>
<p dir="auto" data-line="48"><img loading="lazy" decoding="async" class="alignnone size-large wp-image-20039" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction5-1-1024x371.png" alt="" width="1024" height="371" srcset="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction5-1-1024x371.png 1024w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction5-1-300x109.png 300w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction5-1-768x278.png 768w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction5-1-1536x556.png 1536w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction5-1-2048x742.png 2048w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction5-1-304x110.png 304w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction5-1-282x102.png 282w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></p>
<h3 id="4-%E3%83%88%E3%83%A9%E3%83%B3%E3%82%B6%E3%82%AF%E3%82%B7%E3%83%A7%E3%83%B3%E3%82%92-commitabort-committransactionaborttransaction" class="code-line code-active-line" dir="auto" data-line="52">4. トランザクションを Commit/Abort (commitTransaction/abortTransaction)</h3>
<p class="code-line" dir="auto" data-line="54">必要なメッセージ送信が完了したら commitTransaction によってトランザクションを確定させます。commitTransaction ではトランザクションを Commit する旨を添えて EndTxn リクエストを Transaction coordinator に送ります。Transaction coordinator がリクエストを受け取るとまず __transaction_state に Commit する旨を記録します。さらに AddPartitionsToTxn によって記録されている Partition に対して Commit したことを示すメッセージを送ります。このメッセージは Control Batch と呼ばれる、トランザクションの終了を示す特別なメッセージです。Control Batch の送信は commitTransaction とは非同期で行われます。</p>
<p dir="auto" data-line="54"><img loading="lazy" decoding="async" class="alignnone size-large wp-image-20042" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction6-1-1024x288.png" alt="" width="1024" height="288" srcset="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction6-1-1024x288.png 1024w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction6-1-300x84.png 300w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction6-1-768x216.png 768w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction6-1-1536x432.png 1536w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction6-1-304x86.png 304w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction6-1-282x79.png 282w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction6-1.png 2037w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></p>
<p class="code-line" dir="auto" data-line="58">トランザクションを Abort するには abortTransaction を用います。abortTransaction ではトランザクションを Abort する旨を添えて EndTxn リクエストを送り、関連する Partition に Abort したことを示す Control Batch を送ります。</p>
<p class="code-line" dir="auto" data-line="60">Commit / Abort がされた状態の Partition は下図のようになっています。Control Batch も通常のメッセージと同じように記録されます。</p>
<p dir="auto" data-line="60"><img loading="lazy" decoding="async" class="alignnone wp-image-20043" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction7-1-1024x350.png" alt="" width="412" height="141" srcset="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction7-1-1024x350.png 1024w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction7-1-300x103.png 300w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction7-1-768x263.png 768w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction7-1-304x104.png 304w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction7-1-282x97.png 282w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction7-1.png 1236w" sizes="auto, (max-width: 412px) 100vw, 412px" /></p>
<h2 id="%E3%83%88%E3%83%A9%E3%83%B3%E3%82%B6%E3%82%AF%E3%82%B7%E3%83%A7%E3%83%B3%E3%81%A7%E9%80%81%E4%BF%A1%E3%81%97%E3%81%9F%E3%83%A1%E3%83%83%E3%82%BB%E3%83%BC%E3%82%B8%E3%81%AE%E8%AA%AD%E3%81%BF%E5%87%BA%E3%81%97" class="code-line" dir="auto" data-line="66">トランザクションで送信したメッセージの読み出し</h2>
<p class="code-line" dir="auto" data-line="68">次にメッセージを読み出す際にトランザクション中のメッセージや Abort したメッセージをどのように扱うかについて説明します。</p>
<p class="code-line" dir="auto" data-line="70">すでに述べたように、トランザクションの Commit / Abort は Control Batch によって行うのでトランザクション中のメッセージも Partition 内には記録されています。また Abort したメッセージも Partition 内には残っています。これらのメッセージをどのように扱うかは Consumer の設定である isolation.level によって決まります。</p>
<p class="code-line" dir="auto" data-line="70">isolation.level には read_uncommitted (デフォルト値) あるいは read_committed を設定することができます。read_uncommitted の場合、poll メソッドはトランザクション中かどうかや Abort されているかに関わらずすべてのメッセージを取得することができます。</p>
<p class="code-line code-active-line" dir="auto" data-line="72">次に read_committed の場合ですが、この説明のためには Last Stable Offset (LSO) について説明する必要があります。LSO はトランザクションが未確定の Offset のうち一番小さい Offset のこと (下図では Offset 6) です。これより前の Offset はすべて確定していることになり、Stable Offsets といいます。逆にこれより後の Offset の領域では確定と未確定が混在していることになります。混在しうるのは同じ Partition に複数の Producer がトランザクションでメッセージを送信する場合です。read_committed の場合、poll メソッドは Stable Offsets のメッセージのみ取得することができます。さらに Abort されたメッセージを取り除いた上でユーザーに返します。</p>
<p dir="auto" data-line="72"><img loading="lazy" decoding="async" class="alignnone size-large wp-image-20047" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction8-2-1024x407.png" alt="" width="1024" height="407" srcset="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction8-2-1024x407.png 1024w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction8-2-300x119.png 300w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction8-2-768x305.png 768w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction8-2-1536x610.png 1536w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction8-2-2048x813.png 2048w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction8-2-304x121.png 304w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction8-2-282x112.png 282w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></p>
<p class="code-line" dir="auto" data-line="78">このように、トランザクションを使って送信したメッセージを読み出す際は isolation.level を read_committed にすることで Commit 済みのメッセージのみ読むことができます。</p>
<h2 id="%E3%83%88%E3%83%A9%E3%83%B3%E3%82%B6%E3%82%AF%E3%82%B7%E3%83%A7%E3%83%B3%E3%81%A8-offset-commit" class="code-line" dir="auto" data-line="80">トランザクションと Offset Commit</h2>
<p class="code-line" dir="auto" data-line="82">冒頭で述べたように、Offset Commit をトランザクションに含められる点が Kafka のトランザクションの特徴です。この仕組みは、Kafka から取得したメッセージに何らかの処理を行い、再度 Kafka に書き込むような処理で利用されます。</p>
<p dir="auto" data-line="82"><img loading="lazy" decoding="async" class="alignnone size-large wp-image-20049" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction1-3-1024x403.png" alt="" width="1024" height="403" srcset="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction1-3-1024x403.png 1024w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction1-3-300x118.png 300w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction1-3-768x302.png 768w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction1-3-304x120.png 304w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction1-3-282x111.png 282w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction1-3.png 1533w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></p>
<p class="code-line" dir="auto" data-line="82">この例では以下の流れで処理が進みます。</p>
<ol class="code-line" dir="auto" data-line="84">
<li class="code-line" dir="auto" data-line="83">クライアント AP が Topic A からメッセージを取得</li>
<li class="code-line" dir="auto" data-line="84">取得したメッセージを AP で処理し、その結果を Topic A&#8217; に送信</li>
<li class="code-line code-active-line" dir="auto" data-line="85">すべての処理結果送信が完了したら Topic A の Offset Commit</li>
</ol>
<p class="code-line" dir="auto" data-line="91">ここで Offset Commit がトランザクションに入らない場合を考えてみましょう。処理結果の送信がアトミックにできたとしても Offset Commit に失敗した場合メッセージの取得からやり直すことになり、処理結果が二重に記録されてしまいます。Offset Commit がトランザクションに入れば、Offset Commit に失敗した時に Abort することができます。</p>
<p dir="auto" data-line="91">このような利点があるため、Kafka から取得したメッセージに何らかの処理を行い、再度 Kafka に書き込むという処理では Offset Commit をトランザクション内で行います。</p>
<h2 id="offset-commit-%E3%82%92%E3%83%88%E3%83%A9%E3%83%B3%E3%82%B6%E3%82%AF%E3%82%B7%E3%83%A7%E3%83%B3%E5%86%85%E3%81%A7%E8%A1%8C%E3%81%86%E9%9A%9B%E3%81%AE%E6%8C%99%E5%8B%95" class="code-line" dir="auto" data-line="105">Offset Commit をトランザクション内で行う際の挙動</h2>
<p class="code-line" dir="auto" data-line="93">Kafka ではトランザクション内で Offset Commit をするために Producer 側で sendOffsetsToTransaction というメソッドが用意されています。全体の流れで見るとトランザクションを Commit する前に sendOffsetsToTransaction をすることになります。</p>
<p dir="auto" data-line="93"><img loading="lazy" decoding="async" class="alignnone size-large wp-image-20051" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction2-1-1024x425.png" alt="" width="1024" height="425" srcset="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction2-1-1024x425.png 1024w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction2-1-300x124.png 300w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction2-1-768x319.png 768w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction2-1-1536x637.png 1536w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction2-1-304x126.png 304w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction2-1-282x117.png 282w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction2-1.png 1743w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></p>
<ol class="code-line" dir="auto" data-line="97">
<li class="code-line" dir="auto" data-line="97">トランザクションを初期化 (initTransactions メソッド)</li>
<li class="code-line" dir="auto" data-line="98">Topic A からメッセージを取り出す (Consumer が poll メソッドで取得)</li>
<li class="code-line" dir="auto" data-line="99">トランザクションを開始 (beginTransaction メソッド)</li>
<li class="code-line" dir="auto" data-line="100">処理結果のメッセージを Topic A&#8217; に送信 (send メソッド)</li>
<li class="code-line" dir="auto" data-line="101">Topic A について Offset Commit (sendOffsetsToTransaction メソッド)</li>
<li class="code-line" dir="auto" data-line="102">トランザクションを Commit (commitTransaction メソッド)</li>
</ol>
<p class="code-line code-active-line" dir="auto" data-line="107">sendOffsetsToTransaction では TxnOffsetCommit リクエストを Consumer Group Coordinator に送ります。Offset Commit のやり方自体は通常の Consumer から行うものと同じで、__consumer_offsets という内部 Topic へ Offset Commit の情報が記録されます。異なるのは内部 Topic への記録の前に (未実施であれば) AddPartitionsToTxn リクエストが送信される点です。send と同様に、この操作によってトランザクションに含まれる Partition の情報が __transaction_state に記録されます。</p>
<p dir="auto" data-line="107"><img loading="lazy" decoding="async" class="alignnone size-large wp-image-20052" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction9-1-1024x347.png" alt="" width="1024" height="347" srcset="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction9-1-1024x347.png 1024w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction9-1-300x102.png 300w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction9-1-768x260.png 768w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction9-1-1536x521.png 1536w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction9-1-2048x694.png 2048w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction9-1-304x103.png 304w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2026/02/kafka-transaction9-1-282x96.png 282w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></p>
<p class="code-line" dir="auto" data-line="111">Offset Commit 情報の Commit (あるいは Abort) も、__consumer_offsets の対応する Partition に Control Batch を送ることによって記録されます。</p>
<h2 id="%E7%B5%82%E3%82%8F%E3%82%8A%E3%81%AB" class="code-line" dir="auto" data-line="113">終わりに</h2>
<p class="code-line" dir="auto" data-line="114">Kafka でトランザクションを用いてメッセージを送信し確定させるまでの挙動と、トランザクションで送信したメッセージを読み出す際の挙動について解説しました。さらに Offset Commit をトランザクション内で行う際の挙動についても解説しました。</p>
<p class="code-line" dir="auto" data-line="116">Kafka のトランザクションで Offset Commit を行う場合、本来 Consumer から行うものを Producer から行うため混乱しますが、単にメッセージを送るのみであれば使う流れはデータベースのトランザクションと同じようなものです。メッセージを送るのみの流れ、Offset Commit もする場合の流れと段階的に理解するのがよいでしょう。</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Apache Kafka の Idempotent Producer について</title>
		<link>https://www.sraoss.co.jp/tech-blog/kafka/idempotent-producer/</link>
		
		<dc:creator><![CDATA[奥井 一暁 (Kazuaki Okui)]]></dc:creator>
		<pubDate>Fri, 19 Dec 2025 01:56:31 +0000</pubDate>
				<category><![CDATA[Kafka]]></category>
		<category><![CDATA[Apache Kafka]]></category>
		<category><![CDATA[OSS]]></category>
		<guid isPermaLink="false">https://www.sraoss.co.jp/tech-blog/?p=19112</guid>

					<description><![CDATA[はじめに この記事は SRA Advent Calendar 2025 の20日目の記事です。 Apache Kafka（以下 Kafka）には送達保証のための機能がいくつかあります。 この記事ではその中でも送達が重複す ...]]></description>
										<content:encoded><![CDATA[<h2 id="%E3%81%AF%E3%81%98%E3%82%81%E3%81%AB" class="code-line" dir="auto" data-line="13">はじめに</h2>
<p>この記事は <a href="https://qiita.com/advent-calendar/2025/sra" data-href="https://qiita.com/advent-calendar/2025/sra" target="_blank" rel="noopener">SRA Advent Calendar 2025</a> の20日目の記事です。</p>
<p class="code-line" dir="auto" data-line="16">Apache Kafka（以下 Kafka）には送達保証のための機能がいくつかあります。 この記事ではその中でも送達が重複するのを防止するための機能である Idempotent Producer について解説します。</p>
<p class="code-line" dir="auto" data-line="19">Idempotent Producer は Kafka のバージョン 0.11.0.0 からある機能です。この記事ではバージョン 4.1.0 を元に解説します。</p>
<p><span id="more-19112"></span></p>
<h2 id="kafka-%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6" class="code-line" dir="auto" data-line="23">Kafka について</h2>
<p class="code-line" dir="auto" data-line="25">Kafka はストリーミング処理を実現するための OSS です。</p>
<p class="code-line" dir="auto" data-line="27">Kafka では Producer と呼ばれるクライアントが Broker と呼ばれるサーバにデータを送信します。Broker は複数台で Kafka クラスタを構成します。Kafka ではやり取りする一つ一つのデータを Message と呼びます。 そして Consumer と呼ばれるクライアントが Broker からデータを読み出し処理、活用します。</p>
<p dir="auto" data-line="29"><img loading="lazy" decoding="async" class="alignnone size-large wp-image-19114" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/12/image-5-1024x334.png" alt="" width="1024" height="334" srcset="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/12/image-5-1024x334.png 1024w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/12/image-5-300x98.png 300w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/12/image-5-768x250.png 768w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/12/image-5-1536x500.png 1536w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/12/image-5-304x99.png 304w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/12/image-5-282x92.png 282w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/12/image-5.png 1817w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></p>
<p class="code-line" dir="auto" data-line="34">今回紹介する Idempotent Producer は Broker に重複した Message が送られてきた時にそれを排除する機能です。 ではどのように重複は発生し、またそれはどのように排除されるのでしょうか。</p>
<h2 id="producer-%E3%81%AE%E8%87%AA%E5%8B%95%E3%83%AA%E3%83%88%E3%83%A9%E3%82%A4%E6%A9%9F%E8%83%BD" class="code-line" dir="auto" data-line="37">Producer の自動リトライ機能</h2>
<p class="code-line" dir="auto" data-line="38">Producer から Broker に送られる Message に重複が発生するのは Producer の自動リトライ機能によるものです。まずこちらについて説明します。</p>
<p class="code-line" dir="auto" data-line="40">Producer は Message を送ったあと Broker 側から送信が成功したかについての応答として Ack を受け取ります。この Ack をもとに Producer 側で判断して自動で Message 送信をリトライするのが自動リトライ機能です。 以下の図では送信の失敗を正しく検知し再送しています。このように自動リトライ機能は Message を確実に送るために重要な機能です。</p>
<p dir="auto" data-line="40"><img loading="lazy" decoding="async" class="alignnone size-large wp-image-19182" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/12/455e3fed786f9ded22c1a722e47f89d8-1024x567.png" alt="" width="1024" height="567" srcset="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/12/455e3fed786f9ded22c1a722e47f89d8-1024x567.png 1024w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/12/455e3fed786f9ded22c1a722e47f89d8-300x166.png 300w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/12/455e3fed786f9ded22c1a722e47f89d8-768x425.png 768w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/12/455e3fed786f9ded22c1a722e47f89d8-304x168.png 304w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/12/455e3fed786f9ded22c1a722e47f89d8-282x156.png 282w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/12/455e3fed786f9ded22c1a722e47f89d8.png 1129w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></p>
<p class="code-line" dir="auto" data-line="45">自動リトライ機能は Producer の <code>retries</code> という設定値によって制御できます。 送信失敗時、Producer はこの値の回数だけ再送を試みます（0に設定すると自動再送を行いません）。ただし致命的なエラーが起こった時や <code>delivery.timeout.ms</code> というタイムアウト超過時などはそれ以上再送しません。 その場合はユーザー処理で再送することになりますが、そのような再送は Producer による自動リトライではないので区別されます。</p>
<p class="code-line" dir="auto" data-line="50">さて、以上が自動リトライ機能の概要ですが、この仕組みでは以下の図のように送信には成功したのに Ack が受け取れず再送してしまう可能性があります。重複はこのようにして発生します。</p>
<p dir="auto" data-line="50"><img loading="lazy" decoding="async" class="alignnone size-large wp-image-19184" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/12/c5efb5e6da52e2b6594a22b9361befb3-1024x551.png" alt="" width="1024" height="551" srcset="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/12/c5efb5e6da52e2b6594a22b9361befb3-1024x551.png 1024w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/12/c5efb5e6da52e2b6594a22b9361befb3-300x161.png 300w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/12/c5efb5e6da52e2b6594a22b9361befb3-768x413.png 768w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/12/c5efb5e6da52e2b6594a22b9361befb3-304x164.png 304w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/12/c5efb5e6da52e2b6594a22b9361befb3-282x152.png 282w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/12/c5efb5e6da52e2b6594a22b9361befb3.png 1136w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></p>
<h2 id="idempotent-producer" class="code-line" dir="auto" data-line="54">Idempotent Producer（重複排除機能付きの Producer）</h2>
<p class="code-line" dir="auto" data-line="55">自動リトライによって Message が重複して記録されてしまうのを防ぐのが Idempotent Producer の機能です。次はこちらについて説明します。</p>
<p class="code-line" dir="auto" data-line="57">この機能では Producer は各 Message に1ずつ増加するシーケンス番号を自動で割り当て、Producer ID とともに送信します。 こうすることで Broker 側では、同じ Producer から同じ Message が来たことを検知します。 以下の図のように、Broker はそれを検知した場合重複している Message を Broker 側に記録しません。 さらに、これだけでは Producer は送信が成功したか分からず再送し続けてしまうため、Broker 側は送信成功の Ack を返します。こうすることで Broker 側では Message は重複しませんし、Producer 側で再送し続けることもありません。</p>
<p dir="auto" data-line="57"><img loading="lazy" decoding="async" class="alignnone size-large wp-image-19185" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/12/d2a5f071bfe2248e9134ae198e3b86d6-1024x542.png" alt="" width="1024" height="542" srcset="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/12/d2a5f071bfe2248e9134ae198e3b86d6-1024x542.png 1024w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/12/d2a5f071bfe2248e9134ae198e3b86d6-300x159.png 300w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/12/d2a5f071bfe2248e9134ae198e3b86d6-768x407.png 768w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/12/d2a5f071bfe2248e9134ae198e3b86d6-304x161.png 304w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/12/d2a5f071bfe2248e9134ae198e3b86d6-282x149.png 282w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/12/d2a5f071bfe2248e9134ae198e3b86d6.png 1126w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></p>
<p class="code-line" dir="auto" data-line="67">Idempotent Producer の重複排除で注意すべきは、検知できるのは自動リトライによる問題という点です。例えば「Producer に障害があって再起動した」という場合は元の Producer とは別の Producer として Broker は認識するので重複があっても気付けません。 また、「自動リトライでは送りきれなかったのでユーザー処理で再送する」という場合も元の Message とは別の Message として Broker は認識するので重複に気付けません。</p>
<div>
<div>またシーケンス番号がついていることによって、重複だけでなく Message を記録する順番も Broker は確認することができます。Producer では送信リクエストを同時に複数送ることができるため、ネットワークの問題などで送信リクエストが届く順番が変わってしまうというのが順番が入れかわる典型的なケースです。 Broker では上記の重複確認を行った上で、送られてきた Message のシーケンス番号が順番通りか（直前に記録したシーケンス番号+1と等しいか）確認します。順番通りでない場合は OUT_OF_ORDER_SEQUENCE_NUMBER というエラーによって Producer 側に通知します。この場合、他の送信リクエストを追い抜いてしまっただけという可能性があるので Producer は自動で Message を再送します。追い抜いてしまったのではなく一部の Message が送信失敗してシーケンス番号が飛んでしまったという場合も考えられますが、その場合は Producer、Broker 双方でシーケンス番号をリセットして再送します。</div>
</div>
<div></div>
<div></div>
<p class="code-line" dir="auto" data-line="70">また Idempotent Producer を有効にするには設定値が以下の条件を満たしている必要があります。デフォルトの設定ではこれらは満たされているので、Idempotent Producer はデフォルトで有効です。</p>
<table class="code-line" dir="auto" data-line="70">
<thead class="code-line" dir="auto" data-line="70">
<tr class="code-line" dir="auto" data-line="70">
<th>パラメータ</th>
<th>条件</th>
<th>説明</th>
</tr>
</thead>
<tbody class="code-line" dir="auto" data-line="72">
<tr class="code-line" dir="auto" data-line="72">
<td>enable.idempotence</td>
<td>true</td>
<td>Idempotent Producer の有効化設定です。</td>
</tr>
<tr class="code-line" dir="auto" data-line="73">
<td>max.in.flight.requests.per.connection</td>
<td>5以下</td>
<td>Producer では Message の送信リクエストを<br />
同時に複数送ることができます。<br />
同時送信数を決めるのがこのパラメータです。<br />
Idempotent Producer では<br />
実装上5までしか対応していません。</td>
</tr>
<tr class="code-line" dir="auto" data-line="74">
<td>retries</td>
<td>1以上</td>
<td>0だと再送をしないので1以上にします。</td>
</tr>
<tr class="code-line code-active-line" dir="auto" data-line="75">
<td>acks</td>
<td>all</td>
<td>Broker でデータの複製が適切にされた状態を<br />
保証することで重複検知を正しく行います。</td>
</tr>
</tbody>
</table>
<h2 id="%E9%87%8D%E8%A4%87%E6%8E%92%E9%99%A4%E3%81%AE%E3%82%BD%E3%83%BC%E3%82%B9%E3%82%B3%E3%83%BC%E3%83%89" class="code-line" dir="auto" data-line="81">重複排除のソースコード</h2>
<p class="code-line" dir="auto" data-line="84">最後に、Message の重複を検知し排除している部分を Kafka 4.1.0 のソースコードで見てみましょう。 重複の確認は <a href="https://github.com/apache/kafka/blob/4.1.0/storage/src/main/java/org/apache/kafka/storage/internals/log/UnifiedLog.java#L1081" data-href="https://github.com/apache/kafka/blob/4.1.0/storage/src/main/java/org/apache/kafka/storage/internals/log/UnifiedLog.java#L1081" target="_blank" rel="noopener">UnifiedLog の append() メソッド</a>内で行っています。このメソッドは送られてきた Message の記録をし、 記録の結果（メソッド内では appendInfo という名前）を返すメソッドです。以下はそこからの抜粋です。</p>
<pre><code class="code-line" dir="auto" data-line="83">// now that we have valid records, offsets assigned, and timestamps updated, we need to
// validate the idempotent/transactional state of the producers and collect some metadata
AnalyzeAndValidateProducerStateResult result = analyzeAndValidateProducerState(
        logOffsetMetadata, validRecords, origin, verificationGuard);

if (result.maybeDuplicate.isPresent()) {
    BatchMetadata duplicate = result.maybeDuplicate.get();
    appendInfo.setFirstOffset(duplicate.firstOffset());
    appendInfo.setLastOffset(duplicate.lastOffset);
    appendInfo.setLogAppendTime(duplicate.timestamp);
    appendInfo.setLogStartOffset(logStartOffset);
} else {
    // Append the records, and increment the local log end offset immediately after the append because a
</code></pre>
<p class="code-line" dir="auto" data-line="103">analyzeAndValidateProducerState() メソッド内で重複の確認をしており、その結果を result として受け取っています。その結果で result.maybeDuplicate.isPresent() が True だと重複があることが分かります。続く if 文では重複があるか判定していますが、重複がない場合は else 節に存在する Message 記録の処理が行われ、appendInfo に値がセットされます。 重複がある場合は else 節に入らないため Message の記録は行いません。これによって重複は排除されます。また、記録はしませんが appendInfo に値をセットし正常に Message の記録が行われたときと同じ状態にします。このようにすることで Producer には正常に Message が記録されていることが伝わります。</p>
<h2 id="%E3%81%8A%E3%82%8F%E3%82%8A%E3%81%AB" class="code-line" dir="auto" data-line="107">おわりに</h2>
<p class="code-line" dir="auto" data-line="109">Idempotent Producer の仕組みについて解説しました。 重複を排除するというありがたい機能なので、仕組みを理解し適切に活用しましょう。</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Ansible を用いた Kafka クラスターの構築</title>
		<link>https://www.sraoss.co.jp/tech-blog/kafka/ansible-kafka-cluster/</link>
		
		<dc:creator><![CDATA[奥井 一暁 (Kazuaki Okui)]]></dc:creator>
		<pubDate>Thu, 18 Sep 2025 00:00:14 +0000</pubDate>
				<category><![CDATA[Kafka]]></category>
		<category><![CDATA[Ansible]]></category>
		<category><![CDATA[Apache Kafka]]></category>
		<category><![CDATA[OSS]]></category>
		<guid isPermaLink="false">https://www.sraoss.co.jp/tech-blog/?p=18515</guid>

					<description><![CDATA[はじめに 本記事では複数台のマシンを用いて Kafka クラスターを構築し、簡単な動作確認を行います。構築には Ansible を用いて、動作に必要な最低限の設定を行います。使用するバージョンは以下の通りです。 名前 バ ...]]></description>
										<content:encoded><![CDATA[
<h2 class="wp-block-heading">はじめに</h2>



<p class="wp-block-paragraph">本記事では複数台のマシンを用いて Kafka クラスターを構築し、簡単な動作確認を行います。構築には Ansible を用いて、動作に必要な最低限の設定を行います。使用するバージョンは以下の通りです。</p>
<p><span id="more-18515"></span></p>
<table class="code-line" dir="auto" data-line="21">
<thead class="code-line" dir="auto" data-line="22">
<tr class="code-line" dir="auto" data-line="22">
<th>名前</th>
<th>バージョン</th>
</tr>
</thead>
<tbody class="code-line" dir="auto" data-line="24">
<tr class="code-line" dir="auto" data-line="24">
<td>Rocky Linux</td>
<td>9.5</td>
</tr>
<tr class="code-line" dir="auto" data-line="25">
<td>Apache Kafka</td>
<td>4.0.0</td>
</tr>
<tr class="code-line" dir="auto" data-line="26">
<td>Ansible</td>
<td>2.15.13</td>
</tr>
</tbody>
</table>



<h2 class="wp-block-heading">Kafka について</h2>



<p class="wp-block-paragraph">Apache Kafka はストリーミング処理を実現するための OSS です。複数台のマシンで並列分散処理を行わせることができ、高いスケーラビリティ、障害耐性、低いレイテンシといった特徴があります。複数台のマシンでクラスターを構成するため、Ansible を使ってクラスター全体を構築すると楽です。</p>



<p class="wp-block-paragraph">簡単な動作確認ができる Docker 環境も用意されているのですが、ここでは各マシンに Kafka のバイナリを配置することから始めてクラスターを構築します。Docker 環境で Kafka の動作を試す方法については<a href="https://www.sraoss.co.jp/tech-blog/kafka/apache-kafka-entry/">こちら</a>の記事をご覧ください。</p>



<h2 class="wp-block-heading">Ansible について</h2>



<p class="wp-block-paragraph">Ansible はサーバ構築を自動化するための OSS です。サーバ構築をコード化できるので同時に構築するサーバ数を増やしたりインストールするパッケージを変更したりするのも容易です。コードを見ればサーバの仕様が分かるようにもなります。</p>



<p class="wp-block-paragraph">サーバ構築のコードを書く際、実行のたびにサーバーの状態が変わってしまうコードになることがあります。そのため何回実行してもサーバの状態が同じになる（このような性質を冪等性と言います）ように気を付ける必要があります。本記事でも冪等性を適宜確認しながら進めます。</p>



<h2 class="wp-block-heading">今回構築するクラスターの概要</h2>



<p class="wp-block-paragraph"><img loading="lazy" decoding="async" class="alignnone wp-image-18630" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/08/46f9da528f2535d7bef6a93902e07846-300x200.png" alt="" width="550" height="367" srcset="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/08/46f9da528f2535d7bef6a93902e07846-300x200.png 300w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/08/46f9da528f2535d7bef6a93902e07846-768x513.png 768w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/08/46f9da528f2535d7bef6a93902e07846-304x203.png 304w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/08/46f9da528f2535d7bef6a93902e07846-282x188.png 282w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/08/46f9da528f2535d7bef6a93902e07846.png 1000w" sizes="auto, (max-width: 550px) 100vw, 550px" /></p>



<p class="wp-block-paragraph">本記事では Broker プロセスが合計5つ、Controller プロセスが合計3つのクラスターを構築します。これらを５台のマシン（Broker とController のプロセスを動かす kafka1~3＋Broker のみの kafka4, 5）で稼働させます。 加えてAnsible のコントロールマシンを立てて Kafka クラスター5台の操作を行います。</p>
<p>Ansible のコントロールマシンと Kafka クラスター5台は ssh で通信できるように設定しておきます。 また dnf によるパッケージインストール時など、root 権限を取得することがあるので構築対象サーバで Ansible を実行するユーザーには sudo 権限を与えておきます。</p>



<h2 class="wp-block-heading">Ansible ディレクトリ構造</h2>



<pre><code class="code-line code-active-line" dir="auto" data-line="57">$ tree
.
├── README
├── group_vars
│   └── kafka_cluster.yaml
├── host_vars
│   ├── kafka1.yaml
│   ├── kafka2.yaml
│   ├── kafka3.yaml
│   ├── kafka4.yaml
│   └── kafka5.yaml
├── inventory.ini
├── roles
│   ├── common
│   │   └── templates
│   │       └── kafka_service_template.j2
│   ├── java
│   │   └── tasks
│   │       └── main.yaml
│   ├── kafka_broker
│   │   ├── tasks
│   │   │   └── main.yaml
│   │   └── vars
│   │       └── main.yaml
│   ├── kafka_cluster
│   │   ├── files
│   │   │   └── kafka_2.13-4.0.0.tgz
│   │   └── tasks
│   │       └── main.yaml
│   ├── kafka_controller
│   │   ├── tasks
│   │   │   └── main.yaml
│   │   └── vars
│   │       └── main.yaml
│   ├── terminate_kafka_broker
│   │   └── tasks
│   │       └── main.yaml
│   └── terminate_kafka_controller
│       └── tasks
│           └── main.yaml
├── setup_servers.yaml
└── terminate_servers.yaml

20 directories, 20 files</code></pre>





<p class="wp-block-paragraph">今回、Kafka の環境準備から設定ファイルの編集、起動 までを行う Playbook（setup_servers.yaml）と Kafka の終了を行う Playbook（terminate_servers.yaml）を作成しました。</p>



<h2 class="wp-block-heading">playbook 全体の流れ</h2>



<p class="wp-block-paragraph">setup_servers.yaml を以下に示します。</p>



<pre><code class="code-line" dir="auto" data-line="109">- name: Setup kafka_broker_controller
  hosts: kafka_broker_controller 
  roles:
    - java
    - kafka_cluster
    - kafka_controller
    - kafka_broker

- name: Setup kafka_broker
  hosts: kafka_broker
  roles: 
    - java
    - kafka_cluster
    - kafka_broker</code></pre>





<p class="wp-block-paragraph">terminate_servers.yaml を以下に示します。</p>



<pre><code class="code-line" dir="auto" data-line="127">- name: Terminate kafka_broker
  hosts: kafka_broker
  roles: 
    - terminate_kafka_broker

- name: Terminate kafka_broker_controller
  hosts: kafka_broker_controller
  roles:  
    - terminate_kafka_broker
    - terminate_kafka_controller</code></pre>
<p class="code-line" dir="auto" data-line="139">各タスクは以下の通りです。</p>
<table class="code-line" dir="auto" data-line="141">
<thead class="code-line" dir="auto" data-line="141">
<tr class="code-line" dir="auto" data-line="141">
<th>name</th>
<th>説明</th>
</tr>
</thead>
<tbody class="code-line" dir="auto" data-line="143">
<tr class="code-line" dir="auto" data-line="143">
<td>Setup kafka_broker_controller</td>
<td>kafka1、kafka2、kafka3 で Broker と Controller のプロセスを起動</td>
</tr>
<tr class="code-line" dir="auto" data-line="144">
<td>Setup kafka_broker</td>
<td>kafka4、kafka5 で Broker プロセスを起動</td>
</tr>
<tr class="code-line" dir="auto" data-line="145">
<td>Terminate kafka_broker</td>
<td>kafka4、kafka5 の Broker プロセスを終了</td>
</tr>
<tr class="code-line" dir="auto" data-line="146">
<td>Terminate kafka_broker_controller</td>
<td>kafka1、kafka2、kafka3 の Broker と Controller のプロセスを終了</td>
</tr>
</tbody>
</table>
<p class="code-line code-active-line" dir="auto" data-line="149">各role は以下の通りです。</p>
<table class="code-line" dir="auto" data-line="151">
<thead class="code-line" dir="auto" data-line="151">
<tr class="code-line" dir="auto" data-line="151">
<th>role</th>
<th>説明</th>
</tr>
</thead>
<tbody class="code-line" dir="auto" data-line="153">
<tr class="code-line" dir="auto" data-line="153">
<td>java</td>
<td>Java のインストール</td>
</tr>
<tr class="code-line" dir="auto" data-line="154">
<td>kafka_cluster</td>
<td>Kafka クラスタ共通のタスク（Kafka バイナリの配布）</td>
</tr>
<tr class="code-line" dir="auto" data-line="155">
<td>kafka_controller</td>
<td>Controller の設定＋起動</td>
</tr>
<tr class="code-line" dir="auto" data-line="156">
<td>kafka_broker</td>
<td>Broker の設定＋起動</td>
</tr>
<tr class="code-line" dir="auto" data-line="157">
<td>terminate_kafka_broker</td>
<td>Broker の停止</td>
</tr>
<tr class="code-line" dir="auto" data-line="158">
<td>terminate_kafka_controller</td>
<td>Controller の停止</td>
</tr>
</tbody>
</table>
<p class="code-line" dir="auto" data-line="160">Controller プロセスは Broker プロセスより先に起動するようにしてあります。Broker プロセスの動作のためにはController が必要だからです。プロセスの終了では逆に Broker プロセスを先に終了させています。</p>
<p>&nbsp;</p>
<h2 class="wp-block-heading">Java のインストール</h2>



<p class="wp-block-paragraph">roles/java/task/main.yaml に Java のインストールを行うタスクを記載しています。</p>
<p>

</p>
<pre class="wp-block-code"><code>- name: Ensure openjdk21 present
  ansible.builtin.dnf:
    name: java-21-openjdk
    state: present
  become: true</code></pre>
<p>

</p>
<p class="wp-block-paragraph">ansible.builtin.dnf では name にパッケージ名、state に実行後どんな状態であるべきかを指定することでパッケージのインストール、アンインストールを行うことができます。state に指定できる状態は以下の通りです。</p>
<table class="code-line" dir="auto" data-line="163">
<thead class="code-line" dir="auto" data-line="163">
<tr class="code-line" dir="auto" data-line="163">
<th>設定値</th>
<th>説明</th>
</tr>
</thead>
<tbody class="code-line" dir="auto" data-line="165">
<tr class="code-line" dir="auto" data-line="165">
<td>present</td>
<td>パッケージがインストールされた状態にします。すでにインストールされている場合は何もしません。installed と同じです。</td>
</tr>
<tr class="code-line" dir="auto" data-line="166">
<td>latest</td>
<td>パッケージが最新版にアップデートされた状態にします。未インストールの場合はインストールします。</td>
</tr>
<tr class="code-line" dir="auto" data-line="167">
<td>absent</td>
<td>パッケージがアンインストールされた状態にします。removed と同じです。</td>
</tr>
</tbody>
</table>
<p>2回目以降の実行でバージョンが変わらないようにここでは present を使っています。</p>
<p>

</p>
<h2 class="wp-block-heading">Kafka バイナリの配置</h2>
<p>

</p>
<p class="wp-block-paragraph">roles/kafka_cluster/task/main.yaml に Kafka バイナリの配置を行うタスクを記載しています。</p>
<pre><code class="code-line" dir="auto" data-line="174">- name: Unarchive kafka file
  ansible.builtin.unarchive:
    src: ./roles/kafka_cluster/files/{{kafka_dir}}.tgz
    dest: '{{install_dir}}'
    creates: '{{install_dir}}/{{kafka_dir}}'</code></pre>
<p>

</p>
<p class="wp-block-paragraph">ansible.builtin.unarchive では src に Ansible 環境上のアーカイブファイル、dest に構築対象サーバの展開先ディレクトリを指定することでアーカイブファイルの展開ができます。このように設定するとアーカイブファイルを構築対象サーバに送信した後展開処理は構築対象サーバ上で行うという挙動になります。ここではあらかじめ ./roles/kafka_cluster/files/ に置いておいた kafka_2.13-4.0.0.tgz を各サーバで展開しています（変数 kafka_dir と install_dir は group_vars/kafka_cluster.yaml で定義しています）。</p>
<p>

</p>
<p class="wp-block-paragraph">構築対象サーバでアーカイブファイルのダウンロード、展開をさせるという方法も考えられます。どのような方法を採用するかは各環境によるでしょう。</p>
<p>

</p>
<p class="wp-block-paragraph">また creates に展開後ディレクトリのパスを指定すると、そのディレクトリがすでに存在する場合タスクをスキップさせることができます。<br />creates がない場合、2回目以降の実行で ansible.builtin.unarchive は展開後のファイルが変更されていないか確認し、変更があれば元の状態に戻すという動きをします。その動きで時間がかからないようにここでは creates を使っていますが、再展開させる必要がある場合は creates を削除するとよいでしょう。</p>
<p>

</p>
<h2 class="wp-block-heading">設定</h2>
<p>

</p>
<h3 class="wp-block-heading">Broker の設定</h3>
<p>

</p>
<p class="wp-block-paragraph">

</p>
<p class="wp-block-paragraph">roles/kafka_broker/task/main.yaml に Broker の設定を行うタスクを記載しています。</p>
<pre><code class="code-line" dir="auto" data-line="194">- name: Set node.id
  ansible.builtin.lineinfile:
    path: '{{path_to_properties}}'
    state: present
    regexp: '^node.id='
    line: node.id={{node_id_broker}}

- name: Unset controller.quorum.bootstrap.servers
  ansible.builtin.lineinfile:
    path: '{{path_to_properties}}'
    state: present
    regexp: '^controller.quorum.bootstrap.servers='
    line:  '# controller.quorum.bootstrap.servers='

- name: Set controller.quorum.voters 
  ansible.builtin.lineinfile:
    path: '{{path_to_properties}}'
    state: present
    regexp: '^#controller.quorum.voters='
    line:  'controller.quorum.voters=201@{{ hostvars["kafka1"].ansible_host }}:9093,202@{{ hostvars["kafka2"].ansible_host }}:9093,203@{{ hostvars["kafka3"].ansible_host }}:9093'

- name: Set listeners
  ansible.builtin.lineinfile:
    path: '{{path_to_properties}}'
    state: present
    regexp: '^listeners='
    line: listeners=PLAINTEXT://{{ansible_host}}:9092

- name: Unset advertised.listeners
  ansible.builtin.lineinfile:
    path: '{{path_to_properties}}'
    state: present
    regexp: '^advertised.listeners='
    line: '# advertised.listeners='</code></pre>
<p>

</p>
<p class="wp-block-paragraph">ansible.builtin.lineinfile では行の置き換えや挿入、削除ができます。ここでは path に指定したファイル内の regexp にマッチした行を line で指定した文字列で置き換えています。</p>
<p>

</p>
<p class="wp-block-paragraph">path に指定している path_to_properties ですが、roles/kafka_broker/vars/main.yaml にて kafka_2.13-4.0.0/configs/broker.properties になるように指定しています。つまり kafka_2.13-4.0.0.tgz に同梱されている Broker 用の設定ファイルから設定に必要な行を書き換えています。</p>
<p>

</p>
<p class="wp-block-paragraph">regexp にマッチする行がなかった場合は、line に指定した文字列と同じ内容の行があれば何もしない、なければファイル末尾に line の行を挿入するという挙動になります。そのため複数回実行しても同じ内容が挿入され続けることはなく、冪等性が保たれています。</p>
<p>

</p>
<p class="wp-block-paragraph">変更している設定値は以下の通りです。ここで Quorum について、静的 Quorum または動的 Quorum が使用できますが今回は静的 Quorum を採用しています。</p>
<p>&nbsp;</p>
<table class="code-line" dir="auto" data-line="239">
<thead class="code-line" dir="auto" data-line="239">
<tr class="code-line" dir="auto" data-line="239">
<th>設定値</th>
<th>説明</th>
</tr>
</thead>
<tbody class="code-line" dir="auto" data-line="241">
<tr class="code-line" dir="auto" data-line="241">
<td>node.id</td>
<td>各 Broker または Controller固有の ID で、被りがあってはいけません。変数 node_id_broker はホストごとに指定しています。</td>
</tr>
<tr class="code-line" dir="auto" data-line="242">
<td>controller.quorum.bootstrap.servers</td>
<td>動的 Quorum を採用する場合は、こちらの設定にすべての Controller を {host}:{port} の形でカンマ区切りで指定します。今回静的 Quorum なのでコメントアウトしています。</td>
</tr>
<tr class="code-line" dir="auto" data-line="243">
<td>controller.quorum.voters</td>
<td>静的 Quorum を採用する場合、こちらの設定にすべての Controller を {node.id}@{host}:{port} の形でカンマ区切りで指定します。</td>
</tr>
<tr class="code-line" dir="auto" data-line="244">
<td>listeners</td>
<td>接続を受け付けるリスナーを {リスナー名}://{host}:{port} で指定します。リスナー名ごとにセキュリティプロトコルが listener.security.protocol.map で指定でき、ここでは PLAINTEXT は認証や暗号化のないリスナーを表しています。</td>
</tr>
<tr class="code-line" dir="auto" data-line="245">
<td>advertised.listeners</td>
<td>Kafka クライアントからの接続に使うリスナーを指定します。これが設定されていなければ listeners の設定値が使われます。今回は同じで良いのでコメントアウトしています。</td>
</tr>
</tbody>
</table>
<p>

</p>
<p class="wp-block-paragraph">

</p>
<h3 class="wp-block-heading">Controller の設定</h3>
<p>

</p>
<p class="wp-block-paragraph">

</p>
<p class="wp-block-paragraph">roles/kafka_controller/task/main.yaml に Controller の設定を行うタスクを記載しています。</p>
<pre><code class="code-line" dir="auto" data-line="250">- name: Set node.id
  ansible.builtin.lineinfile:
    path: '{{path_to_properties}}'
    state: present
    regexp: '^node.id='
    line: node.id={{node_id_controller}}

- name: Unset controller.quorum.bootstrap.servers
  ansible.builtin.lineinfile:
    path: '{{path_to_properties}}'
    state: present
    regexp: '^controller.quorum.bootstrap.servers='
    line: '# controller.quorum.bootstrap.servers='

- name: Set controller.quorum.voters 
  ansible.builtin.lineinfile:
    path: '{{path_to_properties}}'
    state: present
    regexp: '^#controller.quorum.voters='
    line:  'controller.quorum.voters=201@{{ hostvars["kafka1"].ansible_host }}:9093,202@{{ hostvars["kafka2"].ansible_host }}:9093,203@{{ hostvars["kafka3"].ansible_host }}:9093'

- name: Set listeners
  ansible.builtin.lineinfile:
    path: '{{path_to_properties}}'
    state: present
    regexp: '^listeners='
    line: listeners=CONTROLLER://{{ansible_host}}:9093

- name: Unset advertised.listeners
  ansible.builtin.lineinfile:
    path: '{{path_to_properties}}'
    state: present
    regexp: '^advertised.listeners='
    line: '# advertised.listeners='</code></pre>
<p>

</p>
<p class="wp-block-paragraph">Controller 側の設定もほとんど同じですが、node_id は Controller 用、listeners はリスナー名が CONTROLLER、ポート番号が 9093 になっています。CONTROLLER も認証や暗号化のないリスナーを表しています。</p>
<p>

</p>
<h2 class="wp-block-heading">起動</h2>
<p>

</p>
<p>

</p>
<h3 class="wp-block-heading">ログディレクトリのフォーマット</h3>
<p>

</p>
<p class="wp-block-paragraph">

</p>
<p class="wp-block-paragraph">

</p>
<p class="wp-block-paragraph">roles/kafka_broker/task/main.yaml と roles/kafka_controller/task/main.yaml にログディレクトリのフォーマットを行うタスクを記載しています。内容は同じです。</p>
<pre><code class="code-line" dir="auto" data-line="293">- name: Format Log Directory
  ansible.builtin.shell:
    cmd: bin/kafka-storage.sh format -t {{kafka_cluster_id}} -c {{path_to_properties}} --ignore-formatted
    chdir: '{{install_dir}}/{{kafka_dir}}/'</code></pre>
<p>

</p>
<p class="wp-block-paragraph">ansible.builtin.shell は cmd に指定したコマンドを chdir で指定したディレクトリ上で実行します。コマンドをただ実行するだけのモジュールのため、冪等性の確保等は行いません。Kafka 起動前には Broker と Controller それぞれでログディレクトリのフォーマットが必要ですが、それは kafka_2.13-4.0.0.tgz の bin ディレクトリにある kafka-storage.sh を使って実行します。shell モジュールは冪等性の観点では避けるべきモジュールですが、kafka-storage.sh を使うために今回は使用しています。</p>
<p>

</p>
<p class="wp-block-paragraph">kafka-storage.sh format とすればフォーマットを行います。オプションは以下の通りです。</p>
<table class="code-line" dir="auto" data-line="305">
<thead class="code-line" dir="auto" data-line="305">
<tr class="code-line" dir="auto" data-line="305">
<th>オプション</th>
<th>説明</th>
</tr>
</thead>
<tbody class="code-line" dir="auto" data-line="307">
<tr class="code-line" dir="auto" data-line="307">
<td>-t {クラスターID}</td>
<td>クラスター全体で共通な ID を指定します。変数 kafka_cluster_id は group_vars/kafka_cluster.yaml でクラスター共通な変数として定義しています。</td>
</tr>
<tr class="code-line" dir="auto" data-line="308">
<td>-c {設定ファイル}</td>
<td>サーバの設定ファイルを指定します。</td>
</tr>
<tr class="code-line" dir="auto" data-line="309">
<td>&#8211;ignore-formatted</td>
<td>すでにフォーマットが済んでいた場合エラーにせず正常終了させます。このオプションがあることで冪等性を保つことができます。</td>
</tr>
</tbody>
</table>
<p>

</p>
<p class="wp-block-paragraph">

</p>
<p class="wp-block-paragraph">

</p>
<h3 class="wp-block-heading">サービスファイルの作成</h3>
<p>

</p>
<p class="wp-block-paragraph">roles/kafka_broker/task/main.yaml と roles/kafka_controller/task/main.yaml にサービスファイルを作成するタスクを記載しています。内容は同じです。</p>
<pre><code class="code-line" dir="auto" data-line="326">- name: Copy template of kafka broker service file
  ansible.builtin.template:
    src: ./roles/common/templates/kafka_service_template.j2
    dest: /etc/systemd/system/kafka-broker.service
  become: true</code></pre>
<p>ansible.builtin.template は構築対象サーバにテンプレートファイルをコピーします。その際テンプレートファイル内の変数を変数の値に置き換えた上でコピーします。ここでは src に指定した Ansible サーバ上のテンプレートファイルを dest で指定した構築対象サーバ上のファイルにコピーします。<br />テンプレートファイルは以下の通りです。</p>
<p>

</p>
<p class="wp-block-paragraph">roles/common/templates/kafka_service_template.j2</p>
<pre><code class="code-line" dir="auto" data-line="337">[Unit]
Description=Kafka server ({{process_role}})
Documentation=https://kafka.apache.org/documentation/

[Service]
Type=simple
Environment="LOG_DIR=/var/log/kafka/{{process_role}}"
ExecStart={{install_dir}}/{{kafka_dir}}/bin/kafka-server-start.sh {{path_to_properties}}
ExecStop={{install_dir}}/{{kafka_dir}}/bin/kafka-server-stop.sh --process-role={{process_role}}

[Install]
WantedBy=multi-user.target</code></pre>
<p>このようなサービスファイルを用いて systemctl で Kafka の起動が行えるようにすることで起動状態の管理を楽にしています。</p>
<p>

</p>
<p class="wp-block-paragraph">変数 process_role と path_to_properties は、Broker 用と Controller 用で変わるようになっていて、Broker か Controller かによってサービスファイルの内容が変わるようになっています。</p>
<p>

</p>
<p class="wp-block-paragraph">Environment として LOG_DIR を設定していますが、これによってログ出力先（Kafka でやり取りされるメッセージという意味のログではなく、サーバのエラー等を出力するログのこと）を指定できます。</p>
<p>

</p>
<p class="wp-block-paragraph">ExecStart では起動コマンドを指定しますが、kafka_2.13-4.0.0.tgz の bin ディレクトリにある kafka-server-start.sh を使用します。kafka-server-start.sh {設定ファイルのパス} と実行することで起動しますが、設定ファイルが Broker のものなら Brokerが、Controller のものなら Controller が起動します。</p>
<p>

</p>
<p class="wp-block-paragraph">ExecStop では終了コマンドを指定しますが、kafka_2.13-4.0.0.tgz の bin ディレクトリにある kafka-server-stop.sh を使用します。kafka-server-stop.sh は引数なしだとそのマシン上のすべての Kafka プロセスを終了させてしまうため、<code>--process-role</code> を指定することで指定したプロセスのみを終了させています。</p>
<p>

</p>
<p class="wp-block-paragraph">このように Kafka の起動、終了にもスクリプトを使うのですが、systemctl を使うようにすることで ansible.builtin.systemd_service モジュールを使用できるので shell モジュールを避けることができます。</p>
<p>

</p>
<h3 class="wp-block-heading">起動</h3>
<p>

</p>
<p class="wp-block-paragraph">

</p>
<p class="wp-block-paragraph">roles/kafka_broker/task/main.yaml に Broker プロセスを起動するタスクを記載しています。</p>
<pre><code class="code-line" dir="auto" data-line="368">- name: Start Kafka broker
  ansible.builtin.systemd_service:
    name: kafka-broker.service
    state: started
    daemon_reload: true
  become: true</code></pre>
<p>ansible.builtin.systemd_service は name で指定したサービスを state で指定した状態にします。今回は起動した状態にしたいので started としています。</p>
<p>

</p>
<p class="wp-block-paragraph">daemon_reload:true としているのは起動前に systemctl daemon-reload を実行し直前でコピーしたサービスファイルを読み込ませるためです。</p>
<p>

</p>
<p class="wp-block-paragraph">roles/kafka_controller/tasks/main.yaml に Controller プロセスを起動するタスクを記載しています。</p>
<pre><code class="code-line" dir="auto" data-line="382">- name: Start Kafka controller
  ansible.builtin.systemd_service:
    name: kafka-controller.service
    state: started
    daemon_reload: true
  become: true</code></pre>
<p>起動させるのが Controller であること以外は Broker の場合と同じです。</p>
<p>

</p>
<h2 class="wp-block-heading">終了</h2>
<p>

</p>
<p class="wp-block-paragraph">

</p>
<p class="wp-block-paragraph">roles/terminate_kafka_broker/tasks/main.yaml に Broker プロセスを終了するタスクを記載しています。</p>
<pre><code class="code-line" dir="auto" data-line="407">- name: Stop kafka broker
  ansible.builtin.systemd_service:
    name: kafka-broker.service
    state: stopped
  become: true</code></pre>
<p>ansible.builtin.systemd_service で state を stopped にすることで Broker プロセスを終了させています。</p>
<p>

</p>
<p class="wp-block-paragraph">roles/terminate_kafka_controller/tasks/main.yaml に Controller プロセスを終了するタスクを記載しています。</p>
<pre><code class="code-line" dir="auto" data-line="417">- name: Stop kafka controller
  ansible.builtin.systemd_service:
    name: kafka-controller.service
    state: stopped
  become: true</code></pre>
<p>

</p>
<p class="wp-block-paragraph">対象が Controller になっている点以外は Broker の場合と同じです。</p>
<h2 id="playbook-%E5%AE%9F%E8%A1%8C" class="code-line" dir="auto" data-line="396">Playbook 実行</h2>
<p class="code-line" dir="auto" data-line="397">実行コマンドは以下の通りです。</p>
<pre><code class="code-line" dir="auto" data-line="398">$ ansible-playbook -i inventory.ini setup_servers.yaml --ask-become-pass -v
</code></pre>
<pre><code class="code-line" dir="auto" data-line="401">$ ansible-playbook -i inventory.ini terminate_servers.yaml --ask-become-pass -v</code></pre>
<p>

</p>
<p class="wp-block-paragraph">

</p>
<h2 class="wp-block-heading">動作確認</h2>
<p class="wp-block-paragraph">Kafka クラスターの動作確認としてトピック作成、Produce、Consume を行います。ここでは kafka_2.13-4.0.0.tgz の bin ディレクトリにある kafka-topics.sh、kafka-console-producer.sh、kafka-console-consumer.sh を用います。</p>
<p>

</p>
<ul>
<li>トピックの作成は以下のように行います。</li>
</ul>
<pre><code class="code-line" dir="auto" data-line="398">$ ./bin/kafka-topics.sh --bootstrap-server kafka_controller1.example.com:9092 --create --topic test --partitions 5 --replication-factor 5
Created topic test.</code></pre>
<p class="wp-block-paragraph">kafka-topics.sh でトピックを作成できます。<br /><code class="code-line" dir="auto" data-line="398">--bootstrap-server kafka_controller1.example.com:9092</code><br />で接続先の Broker を指定するので環境によって変えます。成功すれば Created topic test. と出力されます。</p>
<ul>
<li>メッセージの Produce、Consume は以下のように行います。</li>
</ul>
<p>ターミナルを2つ開いておきます。</p>
<p>Producer 側のターミナルではkafka-console-producer.sh を用います。</p>
<pre><code class="code-line" dir="auto" data-line="404">$ ./bin/kafka-console-producer.sh --bootstrap-server kafka_controller1.example.com:9092 --topic test
&gt;hoge #プロンプトが表示されたら入力</code></pre>
<p>Consumer 側のターミナルでは kafka-console-consumer.sh を用います。</p>
<pre><code class="code-line" dir="auto" data-line="411">$ ./bin/kafka-console-consumer.sh --bootstrap-server kafka_controller1.example.com:9092 --topic test --from-beginning
hoge #Producer 側で入力すると表示される</code><code class="code-line" dir="auto" data-line="404"></code></pre>
<p>Producer 側で入力した内容が Consumer 側で表示されれば成功です。メッセージの送受信ができることが確認できました。</p>
<h2 class="wp-block-heading">おわりに</h2>
<p>

</p>
<p class="wp-block-paragraph">今回は Kafka クラスターの動作に必要な最低限の設定方法をご紹介しました。<br />同じように Kafka クラスターを構築する方の助けとなれば幸いです。</p>
<p>

</p>
<p class="wp-block-paragraph"></p>]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
