<?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>Kafka &#8211; SRA OSS Tech Blog</title>
	<atom:link href="https://www.sraoss.co.jp/tech-blog/category/kafka/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>Fri, 23 Oct 2026 06:56:32 +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>Kafka &#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>Current New Orleans 2025 参加レポート</title>
		<link>https://www.sraoss.co.jp/tech-blog/event_reports/current-new-orleans-2025/</link>
		
		<dc:creator><![CDATA[赤松 俊弘 (Toshihiro Akamatsu )]]></dc:creator>
		<pubDate>Wed, 19 Nov 2025 23:09:36 +0000</pubDate>
				<category><![CDATA[Kafka]]></category>
		<category><![CDATA[イベントレポート]]></category>
		<category><![CDATA[Current]]></category>
		<category><![CDATA[Current 2025]]></category>
		<category><![CDATA[イベント]]></category>
		<category><![CDATA[参加レポート]]></category>
		<guid isPermaLink="false">https://www.sraoss.co.jp/tech-blog/?p=18874</guid>

					<description><![CDATA[本記事では 2025 年 10 月 29 日から 30 日にかけて開催されたデータストリーミングのコミュニティイベント Current New Orleans 2025 の現地の様子をレポートします。 はじめに Curr ...]]></description>
										<content:encoded><![CDATA[<p>本記事では 2025 年 10 月 29 日から 30 日にかけて開催されたデータストリーミングのコミュニティイベント <a href="https://current.confluent.io/new-orleans" target="_blank">Current New Orleans 2025</a> の現地の様子をレポートします。</p>
<p><span id="more-18874"></span></p>
<h2>はじめに</h2>
<p><a href="https://current.confluent.io/" target="_blank" rel="noopener">Current</a> はデータストリーミング分野の第一人者が一堂に会するコミュニティイベントです。イベントでは主に <a href="https://kafka.apache.org/" target="_blank">Apache Kafka</a>® (以下 Kafka) や <a href="https://flink.apache.org/" target="_blank">Apache Flink</a>® (以下 Flink) などのストリーミング処理ソフトウェアに関する講演が行われ、世界中の人々が集まり交流、学び、そして情報共有する場です。</p>
<p>今年 2025 年は 3 月 19 日にインドのベンガルール、5 月 20 日にイギリスのロンドン、そして 10 月 29 日にアメリカのニューオーリンズで開催されました。今回はその中のニューオーリンズで開催されたイベントに参加してきましたので、私が聴講したセッションを中心にその様子をお伝えしたいと思います。</p>
<h2>開催地、ニューオーリンズ</h2>
<p>開催地であるニューオーリンズはアメリカのルイジアナ州南部にあるメキシコ湾に面した港湾都市です。ジャズの発祥地として有名で、フレンチクォータと呼ばれる地域ではフランス・スペイン植民地時代の街並みが残り、クレオール、ケイジャン料理などの美食も味わえる全米でも有数の観光都市でもあります。</p>
<p><img decoding="async" class="size-medium wp-image-18875 alignnone" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-new-orleans-1-300x225.jpg" alt="" width="240" srcset="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-new-orleans-1-300x225.jpg 300w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-new-orleans-1-1024x768.jpg 1024w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-new-orleans-1-768x576.jpg 768w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-new-orleans-1-1536x1152.jpg 1536w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-new-orleans-1-2048x1536.jpg 2048w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-new-orleans-1-285x214.jpg 285w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-new-orleans-1-282x212.jpg 282w" sizes="(max-width: 300px) 100vw, 300px" /><img decoding="async" class="size-medium wp-image-18877 alignnone" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-new-orleans-2-300x225.jpg" alt="" width="240" srcset="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-new-orleans-2-300x225.jpg 300w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-new-orleans-2-1024x768.jpg 1024w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-new-orleans-2-768x576.jpg 768w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-new-orleans-2-1536x1152.jpg 1536w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-new-orleans-2-2048x1536.jpg 2048w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-new-orleans-2-285x214.jpg 285w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-new-orleans-2-282x212.jpg 282w" sizes="(max-width: 300px) 100vw, 300px" /><img decoding="async" class="size-medium wp-image-18875 alignnone" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-new-orleans-3-300x225.jpg" alt="" width="240" /></p>
<h2>イベント会場の様子</h2>
<p>Current New Orleans 2025 はニューオーリンズの中心部、ミシシッピ川沿岸の Ernest N. Morial Convention Center (アーネスト N. モリアル コンベンションセンター) の一角で開催され、60 以上のセッションに 3,500 人以上が参加する非常に大規模なイベントとなりました。イベントホール内では 50 近いスポンサーブースが立ち並び、各社が提供するデータストリーミングに関する様々なソリューションの紹介や参加者同士の交流の場となっていました。</p>
<p><img decoding="async" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-venue-1-300x225.jpg" alt="" width="360" class="alignnone size-medium wp-image-18909" srcset="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-venue-1-300x225.jpg 300w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-venue-1-1024x768.jpg 1024w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-venue-1-768x576.jpg 768w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-venue-1-1536x1152.jpg 1536w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-venue-1-2048x1536.jpg 2048w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-venue-1-285x214.jpg 285w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-venue-1-282x212.jpg 282w" sizes="(max-width: 300px) 100vw, 300px" /><img decoding="async" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-venue-2-300x225.jpg" alt="" width="360" class="alignnone size-medium wp-image-18910" srcset="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-venue-2-300x225.jpg 300w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-venue-2-1024x768.jpg 1024w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-venue-2-768x576.jpg 768w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-venue-2-1536x1152.jpg 1536w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-venue-2-2048x1536.jpg 2048w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-venue-2-285x214.jpg 285w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-venue-2-282x212.jpg 282w" sizes="(max-width: 300px) 100vw, 300px" /></p>
<p><img decoding="async" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-hall-1-300x225.jpg" alt="" width="360" class="alignnone size-medium wp-image-18894" srcset="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-hall-1-300x225.jpg 300w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-hall-1-1024x768.jpg 1024w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-hall-1-768x576.jpg 768w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-hall-1-1536x1152.jpg 1536w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-hall-1-2048x1536.jpg 2048w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-hall-1-285x214.jpg 285w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-hall-1-282x212.jpg 282w" sizes="(max-width: 300px) 100vw, 300px" /><img decoding="async" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-hall-2-300x225.jpg" alt="" width="360" class="alignnone size-medium wp-image-18895" srcset="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-hall-2-300x225.jpg 300w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-hall-2-1024x768.jpg 1024w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-hall-2-768x576.jpg 768w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-hall-2-1536x1152.jpg 1536w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-hall-2-2048x1536.jpg 2048w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-hall-2-285x214.jpg 285w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-hall-2-282x212.jpg 282w" sizes="(max-width: 300px) 100vw, 300px" /></p>
<p>それ以外にもイベントホール内ではハッカソンが開催されていたり、VR の体験、ストリーミング処理ともかかわりの深い AI に関するアートの展示など、様々なイベントが開催され、大いに盛り上がっていました。</p>
<p><img decoding="async" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-hackathon-300x225.jpg" alt="" width="360" class="alignnone size-medium wp-image-18898" srcset="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-hackathon-300x225.jpg 300w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-hackathon-1024x768.jpg 1024w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-hackathon-768x576.jpg 768w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-hackathon-1536x1152.jpg 1536w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-hackathon-2048x1536.jpg 2048w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-hackathon-285x214.jpg 285w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-hackathon-282x212.jpg 282w" sizes="(max-width: 300px) 100vw, 300px" /><img decoding="async" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-ai-gallary-1-300x225.jpg" alt="" width="360" class="alignnone size-medium wp-image-18899" srcset="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-ai-gallary-1-300x225.jpg 300w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-ai-gallary-1-1024x768.jpg 1024w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-ai-gallary-1-768x576.jpg 768w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-ai-gallary-1-1536x1152.jpg 1536w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-ai-gallary-1-2048x1536.jpg 2048w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-ai-gallary-1-285x214.jpg 285w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-ai-gallary-1-282x212.jpg 282w" sizes="(max-width: 300px) 100vw, 300px" /></p>
<p>イベントで提供されるセッションは非常に多く複数のセッションが同時に行われていたため、そのすべてをレポートすることはできませんが、その中から私が聴講したものをいくつか紹介したいと思います。</p>
<h2>一日目</h2>
<h3>Keynote (一日目): Building Intelligent Systems on Real-time Data</h3>
<p>一日目の Keynoteでは Confluent 社の CEO 兼共同設立者、Jay Kreps 氏がプレゼンターとして壇上に立ちました。Confluent 社はカリフォルニアに本社を置き、Kafka を基盤とした企業向けのリアルタイムデータストリーミングプラットフォームやフルマネージドクラウドサービスを提供する会社で、日本法人として Confluent Japan もあります。また本イベント Current を主催する会社でもあります。</p>
<p><img loading="lazy" decoding="async" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-keynote1-1-1024x768.jpg" alt="" width="1024" height="768" class="aligncenter size-large wp-image-18900" srcset="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-keynote1-1-1024x768.jpg 1024w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-keynote1-1-300x225.jpg 300w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-keynote1-1-768x576.jpg 768w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-keynote1-1-1536x1152.jpg 1536w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-keynote1-1-2048x1536.jpg 2048w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-keynote1-1-285x214.jpg 285w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-keynote1-1-282x212.jpg 282w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></p>
<p>Keynote の主題は昨今の AI の台頭に対して、それを使ったシステムをどう構築し、組織内のソフトウェアそしてリアルタイムのデータとどう結び付けていくかについてです。効果的に AI を活用していくには AI が利用するデータをどのようにアップデートしていくかが重要です。例えばデータの更新をバッチ処理で行うとすればその分最新の状況との差異が生まれます。そこでリアルタイムデータを逐次的に処理できるストリーミングデータパイプラインを構築すれば、常にデータを最新に保ち続けることができます。そのシステムの構築に有効なのが Kafka や Flink といったストリーミング処理のソフトウェアです。企業にとっても日々生まれ続けるデータをリアルタイムに活用するためにはストリーム処理が必要不可欠なのだと感じました。</p>
<p>また <a href="https://www.confluent.io/product/confluent-intelligence/" target="_blank">Confluent Intelligence</a> と名付けられた新しいサービスもこのセッションの中で発表されました。これはビルトインの機械学習関数、リアルタイムコンテキストエンジン、ストリーミングエージェントの 3 つの製品から構成されるサービスで、AI システムが過去のデータから継続的に学習し、リアルタイムで行動することを可能にするためのものとのことです。AI エージェントや RAG (検索強化生成)、AI 向け機械学習パイプラインの構築、または Kafka および Flink によるコンテキスト提供に活用が期待されるサービスです。</p>
<p><img decoding="async" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-keynote1-2-300x225.jpg" alt="" width="360" class="alignnone size-medium wp-image-18904" srcset="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-keynote1-2-300x225.jpg 300w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-keynote1-2-1024x768.jpg 1024w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-keynote1-2-768x576.jpg 768w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-keynote1-2-1536x1152.jpg 1536w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-keynote1-2-2048x1536.jpg 2048w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-keynote1-2-285x214.jpg 285w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-keynote1-2-282x212.jpg 282w" sizes="(max-width: 300px) 100vw, 300px" /><img decoding="async" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-keynote1-3-300x225.jpg" alt="" width="360" class="alignnone size-medium wp-image-18905" srcset="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-keynote1-3-300x225.jpg 300w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-keynote1-3-1024x768.jpg 1024w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-keynote1-3-768x576.jpg 768w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-keynote1-3-1536x1152.jpg 1536w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-keynote1-3-2048x1536.jpg 2048w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-keynote1-3-285x214.jpg 285w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-keynote1-3-282x212.jpg 282w" sizes="(max-width: 300px) 100vw, 300px" /></p>
<p>さらには、<a href="https://www.confluent.io/blog/introducing-confluent-private-cloud/" target="_blank">Confluent Private Cloud</a> の発表も併せて行われました。これは Confluent Platform を基盤としており、自社インフラにクラウドサービスの効率性を備えたプライベートデータストリーミング環境を実現できるサービスとなるようです。</p>
<p>続いて一日目の個別セッションの内容をご紹介します。</p>
<h3>Introduction to Apache Flink: Key Concepts and Architecture</h3>
<p>ストリーム処理とバッチ処理の両方をサポートする分散処理フレームワークである Flink について解説する、初心者向けのワークショップセッションです。ストリーム処理とバッチ処理の概念や Flink による分散処理のコンセプトとアーキテクチャを基礎から丁寧に解説されており、ストリーム処理を一から学びたいという人にも最適なセッションだと感じました。</p>
<p><img loading="lazy" decoding="async" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-session1-1-1024x771.jpg" alt="" width="1024" height="771" class="aligncenter size-large wp-image-18908" srcset="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-session1-1-1024x771.jpg 1024w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-session1-1-300x226.jpg 300w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-session1-1-768x578.jpg 768w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-session1-1-1536x1156.jpg 1536w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-session1-1-2048x1542.jpg 2048w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-session1-1-284x214.jpg 284w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-session1-1-282x212.jpg 282w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></p>
<h3>A Deep Dive into Kafka Consumer Rebalance Protocols: Mechanisms and Migration Process Insights</h3>
<p>Kafka 4.0 で実装された新しい <a href="https://cwiki.apache.org/confluence/display/KAFKA/KIP-848%3A+The+Next+Generation+of+the+Consumer+Rebalance+Protocol" target="_blank">Consumer Rebalance Protocol</a> の詳細について、既存との違いをデモを交えてわかりやすく解説されていました。また、既存のプロトコルからの移行のメカニズムについてもオンラインとオフライン両方に対応した方法を紹介されていました。</p>
<p>Consumer Rebalance Protocol とは、ConsumerGroup 内でどの Partition をどの Consumer に割り当てるかを調整するメカニズムです。従来のプロトコルではグループ内のメンバが変化した際に、リバランスが完了するまで一時的に Consume が停止するという制約がありましたが、新しいプロトコルではそれが軽減・削除されています。また、リバランスによる再割り当てのロジックを Broker 側に移動しており、それによる大幅な高速化や安定性の向上も見込めるという利点もあります。</p>
<h3>The Kafka Protocol Deconstructed: A Live-Coded Deep Dive</h3>
<p>このセッションでは Kafka が持つ様々な機能を実現する上でどのようなプロトコルを用いているのかを、かなり根本的な部分まで深掘りして解説されていました。例えば、リクエストのヘッダやボディがどういった要素から構成されていて、それぞれの要素にはどういった内容のデータが格納されているかなど、Kafka が実際にやり取りしている通信プロトコルを明らかにし、それを一から再構築するといったところまで実演していました。</p>
<p>プロトコルを深く知ることで Kafka の内部挙動を本質的に理解できると共に、実用上でのチューニングや問題解決にも応用できそうな、私にとっては非常に有用な内容でした。</p>
<h2>Current party</h2>
<p>一日目の終わりには参加者ならだれでも参加できるパーティが開かれました。時期が近いこともあり、中はハロウィン風の装飾がされていたり、ニューオーリンズらしくライブ演奏やクレオール、ケイジャン料理が味わえたりと様々な趣向が凝らされており、参加者同士の交流を深めるという意味でも非常に有意義なパーティでした。</p>
<p><img decoding="async" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-party-1-300x225.jpg" alt="" width="240" class="alignnone size-medium wp-image-18912" srcset="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-party-1-300x225.jpg 300w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-party-1-1024x768.jpg 1024w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-party-1-768x576.jpg 768w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-party-1-1536x1152.jpg 1536w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-party-1-2048x1536.jpg 2048w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-party-1-285x214.jpg 285w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-party-1-282x212.jpg 282w" sizes="(max-width: 300px) 100vw, 300px" /><img decoding="async" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-party-2-300x225.jpg" alt="" width="240" class="alignnone size-medium wp-image-18913" srcset="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-party-2-300x225.jpg 300w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-party-2-1024x768.jpg 1024w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-party-2-768x576.jpg 768w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-party-2-1536x1152.jpg 1536w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-party-2-2048x1536.jpg 2048w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-party-2-285x214.jpg 285w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-party-2-282x212.jpg 282w" sizes="(max-width: 300px) 100vw, 300px" /><img decoding="async" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-party-3-300x225.jpg" alt="" width="240" class="alignnone size-medium wp-image-18914" srcset="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-party-3-300x225.jpg 300w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-party-3-1024x768.jpg 1024w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-party-3-768x576.jpg 768w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-party-3-1536x1152.jpg 1536w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-party-3-2048x1536.jpg 2048w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-party-3-285x214.jpg 285w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-party-3-282x212.jpg 282w" sizes="(max-width: 300px) 100vw, 300px" /></p>
<h2>二日目</h2>
<h3>Keynote (二日目): Be Ready for What&#8217;s Next</h3>
<p>二日目の Keynote では Confluent 社のアドボカシーおよびデベロッパーエクスペリエンスエンジニアリング部門責任者の Adi Polak 氏が登場し、リアルタイムシステムの現在までの発展の経緯について語りました。モノリシックなシステムからマイクロサービスへの転換、マイクロサービス同士をつなぐ Kafka の登場、そしてデータレイクとして Apache Hadoop と HDFS から Apache Iceberg、Apache Hudi、Delta Lake といったテーブルフォーマットを導入したことによる信頼性の向上。これらの発展によって今現実に起こっていることをリアルタイムで処理するための準備が整いました。そして現在 AI が登場しました。真に信頼できる AI のためには優れたモデルが必要ですが、それを構築・実用するには信頼できるリアルタイムデータ、ひいてはそれを作り出す信頼できるシステムを準備しておくことが必要であると彼女は述べていました。</p>
<p><img loading="lazy" decoding="async" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-keynote2-1-1024x768.jpg" alt="" width="1024" height="768" class="aligncenter size-large wp-image-18916" srcset="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-keynote2-1-1024x768.jpg 1024w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-keynote2-1-300x225.jpg 300w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-keynote2-1-768x576.jpg 768w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-keynote2-1-1536x1152.jpg 1536w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-keynote2-1-2048x1536.jpg 2048w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-keynote2-1-285x214.jpg 285w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-keynote2-1-282x212.jpg 282w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></p>
<p>このセッションではその他にもテレビ番組のトークショーを模した形式でのデータストリーミング分野の第一人者へのインタビューや、コミュニティやこの分野に貢献した企業への授賞式なども行われました。</p>
<p><img loading="lazy" decoding="async" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-award-1024x768.jpg" alt="" width="1024" height="768" class="aligncenter size-large wp-image-18918" srcset="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-award-1024x768.jpg 1024w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-award-300x225.jpg 300w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-award-768x576.jpg 768w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-award-1536x1152.jpg 1536w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-award-2048x1536.jpg 2048w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-award-285x214.jpg 285w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-award-282x212.jpg 282w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></p>
<p>続いて二日目の個別セッションの内容をご紹介します。</p>
<h3>What Can you do with a (Kafka) Queue?</h3>
<p>このセッションでは Kafka をメッセージキューとして利用可能にするための新しい Consumer Group の実装である、<a href="https://cwiki.apache.org/confluence/display/KAFKA/KIP-932%3A+Queues+for+Kafka" target="_blank">Share Group</a> について解説されていました。従来の Consumer Group では Partition 内でのメッセージ順序を維持するために、グループ内で重複して同じ Partition からメッセージを取得することはありませんが、Share Group ではそれを可能にすることでメッセージキューとして Kafka を使うことができるようになります。この機能はまだ完全に実装されてはいませんが、これによって Kafka の用途の可能性が広がる非常に興味深いものだと感じました。</p>
<p><img loading="lazy" decoding="async" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-session2-1-1024x770.jpg" alt="" width="1024" height="770" class="aligncenter size-large wp-image-18919" srcset="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-session2-1-1024x770.jpg 1024w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-session2-1-300x226.jpg 300w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-session2-1-768x577.jpg 768w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-session2-1-1536x1155.jpg 1536w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-session2-1-2048x1540.jpg 2048w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-session2-1-285x214.jpg 285w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-session2-1-282x212.jpg 282w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></p>
<h3>Playing Chess by Scaling Multi-Agent LLM Play with Kafka Queues</h3>
<p>これは上記の Kafka のキュー機能を利用して、LLM (大規模言語モデル) にチェスを並列で同時にプレイさせてみたという、中々面白い内容のセッションです。AI と Kafka の新機能を組み合わせることで、アイディアによってはこういう使い方もできるんだという一例だと思います。実際にセッション中にデモを披露していましたが、かなりスムーズに LLM がチェスを複数盤面で同時にプレイする様子も伺えました。</p>
<p><img loading="lazy" decoding="async" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-session2-2-1024x768.jpg" alt="" width="1024" height="768" class="aligncenter size-large wp-image-18920" srcset="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-session2-2-1024x768.jpg 1024w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-session2-2-300x225.jpg 300w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-session2-2-768x576.jpg 768w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-session2-2-1536x1152.jpg 1536w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-session2-2-2048x1536.jpg 2048w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-session2-2-285x214.jpg 285w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-session2-2-282x212.jpg 282w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></p>
<h2>AI 関連のセッション</h2>
<p>Keynote で言及もあったように、データストリーミングは AI とも関連の深い分野です。本イベントでも AI に関するセッションは数多くあり、AI Alley Theater という AI セッション専用のブースが設けられるほどでした。</p>
<p><img decoding="async" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-ai-alley-1-300x225.jpg" alt="" width="360" class="alignnone size-medium wp-image-18921" srcset="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-ai-alley-1-300x225.jpg 300w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-ai-alley-1-1024x768.jpg 1024w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-ai-alley-1-768x576.jpg 768w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-ai-alley-1-1536x1152.jpg 1536w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-ai-alley-1-2048x1536.jpg 2048w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-ai-alley-1-285x214.jpg 285w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-ai-alley-1-282x212.jpg 282w" sizes="(max-width: 300px) 100vw, 300px" /><img decoding="async" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-ai-alley-2-300x225.jpg" alt="" width="360" class="alignnone size-medium wp-image-18922" srcset="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-ai-alley-2-300x225.jpg 300w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-ai-alley-2-1024x768.jpg 1024w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-ai-alley-2-768x576.jpg 768w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-ai-alley-2-1536x1152.jpg 1536w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-ai-alley-2-2048x1536.jpg 2048w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-ai-alley-2-285x214.jpg 285w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-ai-alley-2-282x212.jpg 282w" sizes="(max-width: 300px) 100vw, 300px" /></p>
<h2>その他のイベントの様子</h2>
<p><img decoding="async" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-hall-3-300x225.jpg" alt="" width="360" class="alignnone size-medium wp-image-18923" srcset="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-hall-3-300x225.jpg 300w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-hall-3-1024x768.jpg 1024w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-hall-3-768x576.jpg 768w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-hall-3-1536x1152.jpg 1536w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-hall-3-2048x1536.jpg 2048w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-hall-3-285x214.jpg 285w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-hall-3-282x212.jpg 282w" sizes="(max-width: 300px) 100vw, 300px" /><img decoding="async" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-ai-gallary-2-300x225.jpg" alt="" width="360" class="alignnone size-medium wp-image-18924" srcset="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-ai-gallary-2-300x225.jpg 300w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-ai-gallary-2-1024x768.jpg 1024w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-ai-gallary-2-768x576.jpg 768w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-ai-gallary-2-1536x1152.jpg 1536w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-ai-gallary-2-2048x1536.jpg 2048w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-ai-gallary-2-285x214.jpg 285w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-ai-gallary-2-282x212.jpg 282w" sizes="(max-width: 300px) 100vw, 300px" /></p>
<p><img decoding="async" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-realtime-swag-300x225.jpg" alt="" width="360" class="alignnone size-medium wp-image-18925" srcset="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-realtime-swag-300x225.jpg 300w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-realtime-swag-1024x768.jpg 1024w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-realtime-swag-768x576.jpg 768w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-realtime-swag-1536x1152.jpg 1536w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-realtime-swag-2048x1536.jpg 2048w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-realtime-swag-285x214.jpg 285w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-realtime-swag-282x212.jpg 282w" sizes="(max-width: 300px) 100vw, 300px" /><img decoding="async" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-swag-300x225.jpg" alt="" width="360" class="alignnone size-medium wp-image-18926" srcset="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-swag-300x225.jpg 300w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-swag-1024x768.jpg 1024w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-swag-768x576.jpg 768w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-swag-1536x1152.jpg 1536w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-swag-2048x1536.jpg 2048w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-swag-285x214.jpg 285w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/11/current2025-swag-282x212.jpg 282w" sizes="(max-width: 300px) 100vw, 300px" /></p>
<h2>おわりに</h2>
<p>Current はデータストリーミングの現在を肌で感じることのできる唯一のイベントです。私も今回参加したことで、Kafka をはじめとしたストリーミング処理について、最新の動向や深い知見を大いに得ることができ、データストリーミングの分野が今いかにホットであるかということを知ることができました。</p>
<p>セッションの内容も幅広く、初心者向けに Kafka や Flink といったデータストリーミングプラットフォームを構成するソフトウェアの基礎を解説するものや、より深く内部動作を解説するもの、ソリューションや活用例を紹介するものなど、データストリーミングを知りたい様々な層に広く訴求するイベントだと感じました。皆さんもデータストリーミングに興味があれば、是非参加してみることをお勧めします。</p>
<p>また、本イベントのセッションは動画でアーカイブされており、誰でも見ることができます。非常に多くの有用なセッションがありますので、データストリーミングや Kafka、Flink などのソフトウェアについて知りたいという方は、<a href="https://current.confluent.io/archive/2025/new-orleans" target="_blank">こちら</a>もチェックしてみてください。</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>
		<item>
		<title>Kafka Streams 事始め</title>
		<link>https://www.sraoss.co.jp/tech-blog/kafka/kafka-streams-concept/</link>
		
		<dc:creator><![CDATA[赤松 俊弘 (Toshihiro Akamatsu )]]></dc:creator>
		<pubDate>Tue, 12 Aug 2025 02:00:30 +0000</pubDate>
				<category><![CDATA[Kafka]]></category>
		<category><![CDATA[Apache Kafka]]></category>
		<category><![CDATA[Kafka Streams]]></category>
		<category><![CDATA[OSS]]></category>
		<guid isPermaLink="false">https://www.sraoss.co.jp/tech-blog/?p=18121</guid>

					<description><![CDATA[この記事は SRA Advent Calendar 2024 の 12 月 25 日の記事を一部修正したものです。 Kafka Streams について、初心者向けに公式ドキュメントの Core Concepts から基 ...]]></description>
										<content:encoded><![CDATA[<p>この記事は <a href="https://qiita.com/advent-calendar/2024/sra" target="_blank">SRA Advent Calendar 2024</a> の <a href="https://qiita.com/t_akamatsu/items/bcd865c864e8145f64d1" target="_blank">12 月 25 日の記事</a>を一部修正したものです。</p>
<p>Kafka Streams について、初心者向けに公式ドキュメントの <a href="https://kafka.apache.org/documentation/streams/core-concepts" target="_blank">Core Concepts</a> から基礎的な概念などを解説していきます。</p>
<p><span id="more-18121"></span></p>
<h2>Kafka Streams とは</h2>
<p>Kafka Streams は Apache Kafka クラスタ上でストリーム処理アプリケーションを実装するためのクライアント・ライブラリです。Java および Scala のライブラリとして提供されており、簡単にストリーム処理アプリケーションを構築することができます。</p>
<p>Kafka Streams によるストリーム処理の基本の流れとしては、Kafka の Topic にあるデータを入力とし、変換処理を行った後、別の Topic に結果を書き戻す形になります。</p>
<p><img loading="lazy" decoding="async" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/08/kafka-streams-overview-1024x484.png" alt="" width="1024" height="484" class="aligncenter size-large wp-image-18122" srcset="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/08/kafka-streams-overview-1024x484.png 1024w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/08/kafka-streams-overview-300x142.png 300w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/08/kafka-streams-overview-768x363.png 768w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/08/kafka-streams-overview-304x144.png 304w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/08/kafka-streams-overview-282x133.png 282w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/08/kafka-streams-overview.png 1188w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></p>
<h2>Kafka Streams の特徴</h2>
<p>Kafka Streams には以下の特徴があります。</p>
<ul>
<li>扱いやすさ</li>
<ul>
<li>構築したアプリケーションは通常の Java アプリケーションとしてパッケージング、デプロイが可能</li>
<li>ベアメタル、仮想環境、コンテナ、クラウドといった様々な環境にデプロイ可能</li>
<li>規模を問わず様々なユースケースに適用可能</li>
</ul>
<li>高機能</li>
<ul>
<li>Kafka クラスタの持つ拡張性、弾力性、分散性、耐障害性をアプリケーション側でも利用可能</li>
<li>Exactly once (データの抜け漏れや重複なく必ず 1 回だけ) の処理セマンティクスをサポート</li>
<li>複数レコード間の結合や集約、ウィンドウ処理が可能</li>
</ul>
</ul>
<h2>ストリーム処理トポロジ</h2>
<p>ストリーム処理トポロジとは、ストリーム処理アプリケーションで実行されるデータ処理の流れを定義するものです。トポロジはデータ変換の処理単位をプロセッサ (ノード)、データの流れをストリーム (エッジ) としたグラフで表現されます。</p>
<p>トポロジの末端に位置するプロセッサには特別な名前が付けられています。</p>
<ul>
<li>ソースプロセッサ：トポロジの入力であり、Topic からレコードを読み込む</li>
<li>シンクプロセッサ：トポロジの出力であり、Topic へ処理結果を書き込む</li>
</ul>
<p><img decoding="async" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/08/kafka-streams-topology-300x278.png" alt="" width="500" class="aligncenter wp-image-18126" srcset="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/08/kafka-streams-topology-300x278.png 300w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/08/kafka-streams-topology-1024x948.png 1024w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/08/kafka-streams-topology-768x711.png 768w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/08/kafka-streams-topology-1536x1422.png 1536w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/08/kafka-streams-topology-2048x1897.png 2048w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/08/kafka-streams-topology-231x214.png 231w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/08/kafka-streams-topology-282x260.png 282w" sizes="(max-width: 300px) 100vw, 300px" /></p>
<p>Kafka Streams でストリーム処理アプリケーションを構築する場合は、ライブラリで提供される <b>Processor API</b> か <b>Kafka Streams DSL</b> を用いて、トポロジを定義します。</p>
<ul>
<li>Kafka Streams DSL</li>
<ul>
<li>Processor API を基盤に構築された宣言型、関数型の DSL</li>
<li>ステートレス変換 (map、filter) や結合 (join) や集約 (aggregate、count、reduce)、ウィンドウ処理といったステートフル変換を利用可能</li>
<li>複雑な変換処理を簡単に記述できるので初心者におすすめ</li>
</ul>
<li>Processor API</li>
<ul>
<li>命令型の低レベル API</li>
<li>ユーザ独自のプロセッサの定義やステートストアとの直接のやりとりが可能</li>
<li>柔軟性が高いがより多くのコーディングが必要</li>
</ul>
</ul>
<h2>ストリームにおける時刻の定義</h2>
<p>ストリーム処理においては時刻をモデル化することは重要な概念の 1 つです。ウィンドウなどの操作は時刻に基づいて定義、処理されるからです。</p>
<p>Kafka Streams では以下の時刻の定義が使用されます。</p>
<ul>
<li>イベント時刻：イベントまたはデータレコードが発生した時刻</li>
<li>処理時刻：イベントまたはデータレコードがストリーム処理アプリケーションによって処理された時刻</li>
<li>インジェスト時刻：イベントまたはデータレコードが Kafka Broker によって Topic Partition に格納された時刻</li>
</ul>
<h2>ストリームとテーブルの二重性</h2>
<p>ストリーム処理における重要な概念としてストリームとテーブルの二重性というものがあります。この二重性とは、本質的にストリームはテーブルとして、テーブルはストリームとして見なせるということです。</p>
<ul>
<li>テーブルとしてのストリーム：<br />
ストリームはテーブルの変更ログと見なすことができます。ストリーム内の各データレコードには、テーブルのステートの変更内容が記載されているため、これを最初から最後まで追うことでテーブルを再構築することができます。</li>
<li>ストリームとしてのテーブル：<br />
テーブルは、ストリーム内の各キーに対応するある時点での最新の値のスナップショットと見なすことができます。したがって、異なる時点のテーブル内容を比較することでその変更ログをそのままストリームに変換できます。</li>
</ul>
<p><img loading="lazy" decoding="async" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/08/kafka-streams-duality.png" alt="" width="955" height="705" class="aligncenter size-full wp-image-18136" srcset="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/08/kafka-streams-duality.png 955w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/08/kafka-streams-duality-300x221.png 300w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/08/kafka-streams-duality-768x567.png 768w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/08/kafka-streams-duality-290x214.png 290w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/08/kafka-streams-duality-282x208.png 282w" sizes="auto, (max-width: 955px) 100vw, 955px" /></p>
<p>Kafka Streams ではこの二重性を KStreams および KTable としてモデル化しています。</p>
<h2>ステートフル操作</h2>
<p>Kafka Streams ではステートレス操作に加えて、ステートフル操作にも対応しています。ステートフル操作には状態の保存が必要なため、Kafka Streams ではステートストアが提供されます。ステートフル操作の例としては集約、結合、ウィンドウ化があります。</p>
<h3>集約</h3>
<p>集約操作では 1 つのストリームもしくはテーブルを入力として受け取り、複数のレコードを 1 つに結合してテーブルとして出力します。count や sum といった操作が集約にあたります。</p>
<p>Kafka Streams DSL では入力ストリームは KStream か KTable、出力ストリームは KTable になります。</p>
<p>参考：<a href="https://kafka.apache.org/documentation/streams/developer-guide/dsl-api.html#aggregating" target="_blank">Kafka Streams/Developer Guide/Streams DSL/aggregationg</a></p>
<h3>結合</h3>
<p>結合操作では、データレコードのキーに基づいて 2 つの入力ストリームまたはテーブルをマージして、新しいストリームまたはテーブルを生成します。</p>
<p>Kafka Streams では KStream 同士、KTable 同士、KStream と KTable の結合などが可能ですが、それぞれで可能な結合の種類は異なります。</p>
<p>参考：<a href="https://kafka.apache.org/documentation/streams/developer-guide/dsl-api#joining" target="_blank">Kafka Streams/Developer Guide/Streams DSL/Joining</a></p>
<h3>ウィンドウ化</h3>
<p>ウィンドウ化では、集約や結合などのステートフル操作において同じキーを持つレコードをグループ化し、ウィンドウと呼ばれる単位に分けて処理を行います。</p>
<p>参考：<a href="https://kafka.apache.org/documentation/streams/developer-guide/dsl-api#windowing" target="_blank">Kafka Streams/Developer Guide/Streams DSL/Windowing</a></p>
<h2>ステートストア</h2>
<p>ステートストアはステートフル操作を行う際のデータの保存やクエリに利用されます。ステートストアは Kafka Streams の各タスクに組み込まれています。</p>
<p>またローカルのステートストアの変更ログは Kafka の専用の Topic に保存されるため、障害時の自動復旧にも対応しています。</p>
<p>参考：<a href="https://kafka.apache.org/documentation/streams/architecture#streams_architecture_recovery" target="_blank">Kafka Streams/Architecture/Fault Tolerance</a></p>
<h2>アプリケーションの例</h2>
<p>最後に、<a href="https://kafka.apache.org/40/documentation/streams/tutorial" target="_blank">公式ドキュメント</a>にあるアプリケーションの例を使って Kafka Streams DSL でのアプリケーションの書き方や処理について説明します。</p>
<h3>LineSplit</h3>
<p>LineSplit は入力文字列をスペースをデリミタとして、単語ごとに区切って出力するアプリケーションです。</p>
<p><img loading="lazy" decoding="async" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/08/kafka-streams-linesplit-1024x318.png" alt="" width="1024" height="318" class="aligncenter size-large wp-image-18138" srcset="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/08/kafka-streams-linesplit-1024x318.png 1024w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/08/kafka-streams-linesplit-300x93.png 300w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/08/kafka-streams-linesplit-768x238.png 768w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/08/kafka-streams-linesplit-304x94.png 304w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/08/kafka-streams-linesplit-282x88.png 282w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/08/kafka-streams-linesplit.png 1195w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></p>
<pre>
public class LineSplit {
    public static void main(String[] args) throws Exception {
        // アプリケーションの設定
        Properties props = new Properties();
        props.put(StreamsConfig.APPLICATION_ID_CONFIG, "streams-linesplit");
        props.put(StreamsConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092");
        props.put(StreamsConfig.DEFAULT_KEY_SERDE_CLASS_CONFIG, Serdes.String().getClass());
        props.put(StreamsConfig.DEFAULT_VALUE_SERDE_CLASS_CONFIG, Serdes.String().getClass());

        // トポロジを定義するためのビルダ
        final StreamsBuilder builder = new StreamsBuilder();

        // 処理内容を DSL で記述
        KStream<String, String> source = builder.stream("streams-plaintext-input"); // 入力用 Topic を指定
        source.flatMapValues(value -> Arrays.asList(value.split("\\W+"))) // 入力をスペースで区切って分割
              .to("streams-linesplit-output"); // 出力用 Topic に書き込む

        // ビルダからトポロジに変換し、実行
        final Topology topology = builder.build();
        final KafkaStreams streams = new KafkaStreams(topology, props);
        streams.start();
    }
}
</pre>
<h3>WordCount</h3>
<p>WordCount は入力文字列の単語ごとに区切ってその出現数を出力するアプリケーションです。この処理は過去の入力文字列のカウント結果を保存しておく必要があるので、ステートストアを利用したステートフルな処理になります。</p>
<p><img loading="lazy" decoding="async" src="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/08/kafka-streams-wordcount-1024x382.png" alt="" width="1024" height="382" class="aligncenter size-large wp-image-18141" srcset="https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/08/kafka-streams-wordcount-1024x382.png 1024w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/08/kafka-streams-wordcount-300x112.png 300w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/08/kafka-streams-wordcount-768x287.png 768w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/08/kafka-streams-wordcount-304x114.png 304w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/08/kafka-streams-wordcount-282x105.png 282w, https://www.sraoss.co.jp/tech-blog/wp-content/uploads/2025/08/kafka-streams-wordcount.png 1277w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></p>
<pre>
public class WordCount {
    public static void main(String[] args) throws Exception {
        // アプリケーションの設定
        Properties props = new Properties();
        props.put(StreamsConfig.APPLICATION_ID_CONFIG, "streams-wordcount");
        props.put(StreamsConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092");
        props.put(StreamsConfig.DEFAULT_KEY_SERDE_CLASS_CONFIG, Serdes.String().getClass());
        props.put(StreamsConfig.DEFAULT_VALUE_SERDE_CLASS_CONFIG, Serdes.String().getClass());

        // トポロジを定義するためのビルダ
        final StreamsBuilder builder = new StreamsBuilder();

        // 処理内容を DSL で記述
        KStream<String, String> source = builder.stream("streams-plaintext-input"); // 入力用 Topic を指定
        source.flatMapValues(value -> Arrays.asList(value.split("\\W+"))) // 入力をスペースで区切って分割
              .groupBy((key, value) -> value) // 単語ごとにグループ化
              .count(Materialized.<String, Long, KeyValueStore<Bytes, byte[]>>as("counts-store")) // 単語をカウントしてステートストアにテーブルとして保存
              .toStream() // テーブルからストリームに変換
              .to("streams-wordcount-output", Produced.with(Serdes.String(), Serdes.Long())); // 出力用 Topic に書き込む

        // ビルダからトポロジに変換し、実行
        final Topology topology = builder.build();
        final KafkaStreams streams = new KafkaStreams(topology, props);
        streams.start();
    }
}
</pre>
<h2>おわりに</h2>
<p>この記事では Kafka Streams の基本的な概念について説明しました。</p>
<p>Kafka Streams は難しく見えるかもしれませんが、実際に使ってみると簡単にストリーム処理アプリケーションを実装することができます。みなさんも是非機会があれば Kafka Streams を使ってみてください。</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>誰でも試せる Apache Kafka</title>
		<link>https://www.sraoss.co.jp/tech-blog/kafka/apache-kafka-entry/</link>
		
		<dc:creator><![CDATA[山崎 修平 (Shuhei Yamasaki)]]></dc:creator>
		<pubDate>Wed, 07 May 2025 00:30:35 +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=17494</guid>

					<description><![CDATA[この記事は SRA Advent Calendar 2024 の12月24日の記事を一部改変したものです。 本記事においては Apache Kafka 4.0 におけるコードを参照しています。 Apache Kafka  ...]]></description>
										<content:encoded><![CDATA[
<div>この記事は <a href="https://qiita.com/advent-calendar/2024/sra" target="_blank" rel="noopener noreferrer">SRA Advent Calendar 2024</a> の<a href="https://qiita.com/yamasakisua/items/d8eb3158bb9fd1de2be0" target="_blank" rel="noopener noreferrer">12月24日の記事</a>を一部改変したものです。</div>
<div>本記事においては Apache Kafka 4.0 におけるコードを参照しています。</div>
<h2 class="wp-block-heading">Apache Kafka について</h2>
<div>Apache Kafka（以下、Kafka）はストリーミング処理に欠かせない重要な OSS です。Kafka を利用することにより高可用性、スケーラブル、低レイテンシといった様々なメリットを得ることができます。</div>
<div>並列分散処理の環境を構築するためには複数のサーバを用意したり、環境設定用の Puppet、Ansible を準備したり、といった作業を想定される方もいらっしゃるかと思います。しかし、Kafka には動作を簡単に確認できる Docker 環境などが用意されており、テスト用に試すのであれば意外と簡単に環境を立てることが可能です。</div>
<div>また、性能測定のために Producer と Consumer をそれぞれ用意する必要がありますが、テスト用のツールについてもコミュニティ提供のものが存在しています。</div>
<div>本記事においては、Kafka に興味のある方に向けて、Docker 環境を用いて簡単に Kafka を試すための手順についてご説明いたします。</div>
<br>
<span id="more-17494"></span>

<h2 class="wp-block-heading"> Kafka の Docker image</h2>
<div>Kafka では3.7.0のリリース以降、コミュニティから<a href="https://hub.docker.com/r/apache/kafka/tags" target="_blank" rel="noopener noreferrer">KafkaのDocker イメージ</a></div>
<div>このイメージを利用することで、簡単に Broker を起動することができます。</div>
<div> </div>
<pre>docker run -d --name broker apache/kafka:latest</pre>
<div>また、最近では Kafka の中でも GraalVM ベースで開発された<a href="https://hub.docker.com/r/apache/kafka-native" target="_blank" rel="noopener noreferrer">Kafka-native というイメージ</a>が登場しています。</div>
<div>こちらについては本記事では詳しく取り上げませんが、GraalVM ベースの Kafka ではさらに軽量で高速に起動することができます。</div>
<div>興味のある方はぜひ<a href="https://cwiki.apache.org/confluence/display/KAFKA/KIP-974%3A+Docker+Image+for+GraalVM+based+Native+Kafka+Broker" target="_blank" rel="noopener noreferrer">KIP-974</a>をご確認ください。</div>
<h3> Docker Compose ファイルについて</h3>
<div>Docker Compose ファイルについても、コミュニティ付帯のものを利用することが可能です。</div>
<div>Kafka のリポジトリには docker/examples というディレクトリがあり、その中は以下のとおりのディレクトリ構造をしています。このディレクトリのなかに docker-compose.yml がそれぞれ用意されており、目的に応じて使い分けることが可能です。</div>
<pre>├── examples<br />│   ├── docker-compose-files<br />│   │   ├── cluster<br />│   │   │   ├── combined<br />│   │   │   │   ├── plaintext<br />│   │   │   │   └── ssl<br />│   │   │   └── isolated<br />│   │   │       ├── plaintext<br />│   │   │       └── ssl<br />│   │   └── single-node<br />│   │       ├── file-input<br />│   │       ├── plaintext<br />│   │       └── ssl</pre>
<div> </div>
<div>各ディレクトリの中について少し見てみましょう。</div>
<div>まず、1ノードで起動するモード（single-node）とクラスタで起動するモード（cluster）があります。さらに、クラスタの中では Controller と Broker が別のコンテナで動作するモード（isolated）と同じコンテナで動作するモード（combined）にさらに分かれています。それぞれのパターンに対し、Kafka 内での通信が暗号化されているモード（ssl）と平文で通信するモード（plaintext）が用意されている、といった構造になっています。</div>
<div>一例として Compose ファイルの中身を見てみます。</div>
<div>今回は Compose ファイルの中から、cluster -&gt; isolate -&gt; plaintext のものを確認します。</div>
<div> </div>
<pre>  controller-1:<br />    image: ${IMAGE}<br />    environment:<br />      KAFKA_NODE_ID: 1<br />      KAFKA_PROCESS_ROLES: 'controller'<br />      KAFKA_CONTROLLER_QUORUM_VOTERS: '1@controller-1:9093,2@controller-2:9093,3@controller-3:9093'<br />      KAFKA_INTER_BROKER_LISTENER_NAME: 'PLAINTEXT'<br />      KAFKA_CONTROLLER_LISTENER_NAMES: 'CONTROLLER'<br />      CLUSTER_ID: '4L6g3nShT-eMCtK--X86sw'<br />...<br />  kafka-1:<br />    image: ${IMAGE}<br />    ports:<br />      - 29092:9092<br />    hostname: kafka-1<br />    container_name: kafka-1<br />    environment:<br />      KAFKA_NODE_ID: 4<br />      KAFKA_PROCESS_ROLES: 'broker'<br />      KAFKA_CONTROLLER_QUORUM_VOTERS: '1@controller-1:9093,2@controller-2:9093,3@controller-3:9093'<br />      KAFKA_LISTENERS: 'PLAINTEXT://:19092,PLAINTEXT_HOST://:9092'</pre>
<div> </div>
<div>利用する Docker イメージは <code>IMAGE</code> 変数によって指定することが可能です。バージョンを切り替えたい場合など、簡単に利用するイメージを変更することができます。</div>
<div>また、各ノード設定内容は <code>environment</code> 内の変数でそれぞれ定義されています。</div>
<div>controller では <code>KAFKA_PROCESS_ROLES</code> として <code>controller</code>、Broker では <code>broker</code> がそれぞれ定義されることにより、各ノード上での動作を切り替えています。（なお、combined モードのクラスタを利用する場合には、<code>broker,controller</code> が設定されます）</div>
<div>Broker が動作するノード上では <code>9092</code> 番ポートがそれぞれフォワードされています。cluster 環境では3台の Broker が起動し、ローカル上の <code>29092, 39092, 49092</code> にアクセスすることで各 Broker に接続をすることが可能です。</div>
<h2> 実際に動かしてみる</h2>
<h3> Kafka クラスタの起動</h3>
<div>では、実際に Kafka クラスタを動作させてみましょう。</div>
<div>Compose ファイルを使って Kafka クラスタを起動するには、以下のように <code>IMAGE</code> 変数に docker イメージのタグを指定します。</div>
<div>今回は Compose ファイルの中から、前節の「docker-compose-ファイルについて」で中身を参照した cluster -&gt; isolate -&gt; plaintext のものを選択して利用します。</div>
<div> </div>
<pre>$ IMAGE=apache/kafka:latest docker compose -f docker/examples/docker-compose-files/cluster/isolated/plaintext/docker-compose.yml up -d<br />[+] Running 6/6<br /> &#x2714; Container plaintext-controller-3-1  Started                                                                     0.7s<br /> &#x2714; Container plaintext-controller-2-1  Started                                                                     0.7s<br /> &#x2714; Container plaintext-controller-1-1  Started                                                                     0.7s<br /> &#x2714; Container kafka-3                   Started                                                                     1.4s<br /> &#x2714; Container kafka-1                   Started                                                                     1.3s<br /> &#x2714; Container kafka-2                   Started                                                                     1.4s<br /><br />$ docker ps<br />CONTAINER ID   IMAGE                 COMMAND                  CREATED         STATUS         PORTS                                           NAMES<br />f6c59323b6dc   apache/kafka:latest   "/__cacert_entrypoin…"   4 seconds ago   Up 3 seconds   0.0.0.0:39092-&gt;9092/tcp, [::]:39092-&gt;9092/tcp   kafka-2<br />9c8aea6a29e5   apache/kafka:latest   "/__cacert_entrypoin…"   4 seconds ago   Up 3 seconds   0.0.0.0:29092-&gt;9092/tcp, [::]:29092-&gt;9092/tcp   kafka-1<br />22124b348942   apache/kafka:latest   "/__cacert_entrypoin…"   4 seconds ago   Up 3 seconds   0.0.0.0:49092-&gt;9092/tcp, [::]:49092-&gt;9092/tcp   kafka-3<br />fceba9972dca   apache/kafka:latest   "/__cacert_entrypoin…"   4 seconds ago   Up 4 seconds   9092/tcp                                        plaintext-controller-2-1<br />9f097d2dffe7   apache/kafka:latest   "/__cacert_entrypoin…"   4 seconds ago   Up 4 seconds   9092/tcp                                        plaintext-controller-3-1<br />3e326f5b2031   apache/kafka:latest   "/__cacert_entrypoin…"   4 seconds ago   Up 4 seconds   9092/tcp                                        plaintext-controller-1-1</pre>
<h3>メッセージの送受信</h3>
<div>起動した Kafka クラスタに対してデータの送受信を行ってみます。</div>
<div>自作のアプリケーションを用いてもよいですが、今回は簡単に <code>kafka-console-producer.sh, kafka-console-consumer.sh</code> を利用します。</div>
<div>なお、ソースコードをビルドできる環境でれば自分でを実行した上で、<code>bin</code> ディレクトリ以下のスクリプトを利用できます。ビルド済みのバイナリも<a href="https://kafka.apache.org/downloads" target="_blank" rel="noopener noreferrer">コミュニティページ</a>に配布されていますので、こちらのバイナリを利用しても実行できます。</div>
<div>まず、送受信用のトピックを作成しておきましょう。</div>
<div> </div>
<pre>$ bin/kafka-topics.sh --bootstrap-server localhost:29092,localhost:39092,localhost:49092 --create --topic testTopic --partitions 3<br />...<br />Created topic testTopic.</pre>
<div>produce, consume のテストのためには別途コンソールを開いておき、</div>
<div>それぞれのコンソールで以下のコマンドを実行します。</div>
<div> </div>
<div>・コンソール1 (Producer)</div>
<pre>$ ./bin/kafka-console-producer.sh --bootstrap-server localhost:29092,localhost:39092,localhost:49092 --topic testTopic<br />&gt; hoge  # プロンプトが表示されたら入力</pre>
<div> </div>
<div>・ コンソール2 （Consumer）</div>
<pre> ./bin/kafka-console-consumer.sh --bootstrap-server localhost:29092,localhost:39092,localhost:49092 --topic testTopic --from-beginning<br />  hoge  # コンソール1で入力すると表示される</pre>
<h3>デバッガの接続</h3>
<div>Kafka 内部での細かい動作を確認したい場合、動作中のプロセスに対してデバッガを接続したくなることがあります。</div>
<div>コミュニティの Compose ファイルそのままではデバッガ用のポートは解放されていませんが、設定を追加することでデバッガをアタッチすることも可能です。</div>
<div>Kafka においては daemon の起動など、スクリプトによる操作時に <code>kafka-run-class.sh</code> が利用されており、<code>kafka-run-class.sh</code> では環境変数に応じて起動時のオプションが設定されるようになっています。</div>
<pre># Set Debug options if enabled<br />if [ "x$KAFKA_DEBUG" != "x" ]; then<br />    # Use default ports<br />    DEFAULT_JAVA_DEBUG_PORT="5005"<br />    if [ -z "$JAVA_DEBUG_PORT" ]; then<br />        JAVA_DEBUG_PORT="$DEFAULT_JAVA_DEBUG_PORT"<br />    fi<br />    # Use the defaults if JAVA_DEBUG_OPTS was not set<br />    DEFAULT_JAVA_DEBUG_OPTS="-agentlib:jdwp=transport=dt_socket,server=y,suspend=${DEBUG_SUSPEND_FLAG:-n},address=$JAVA_DEBUG_PORT"<br />    if [ -z "$JAVA_DEBUG_OPTS" ]; then<br />        JAVA_DEBUG_OPTS="$DEFAULT_JAVA_DEBUG_OPTS"<br />    fi<br />    echo "Enabling Java debug options: $JAVA_DEBUG_OPTS"<br />    KAFKA_OPTS="$JAVA_DEBUG_OPTS $KAFKA_OPTS"<br />fi</pre>
<div> </div>
<div>そのため、以下のように Compose ファイルに記載を追加することで、ローカルの <code>25005</code> から Broker プロセスにデバッガを接続することができます。</div>
<div>（docker-compose ファイルの修正後はクラスタを再作成してください）</div>
<pre>kafka-1:<br />  image: ${IMAGE}<br />  ports:<br />     - 29092:9092<br />+      - 25005:5005<br />   environment:<br />+      KAFKA_DEBUG: 'y'<br />+      JAVA_DEBUG_PORT: '*:5005'<br />...</pre>
<h2>テストに便利なツール群</h2>
<div>これまでで Kafka クラスタ環境は構築できましたが、より本格的にテストを行うためのツールも Kafka には付帯しています。現在の Kafka の bin ディレクトリ以下には、約40のスクリプトが用意されていますが、今回はそのうちのいくつかについてご紹介します。</div>
<div> </div>
<h3>kafka-[producer,consumer]-perf-test.sh</h3>
<div>Producer と Consumer で性能がどの程度かを簡単に測定するためには、<code>perf-test.sh</code> というツールが利用できます。</div>
<div>Producer と Consumer で別のスクリプトが用意されており、それぞれメッセージのサイズや多重度を指定することができます。</div>
<div>任意のパラメータを指定することで、任意の負荷を簡単に掛けることが可能です。</div>
<div>コマンドの実行例としては以下の通りです。</div>
<pre>$ bin/kafka-producer-perf-test.sh --producer-props bootstrap.servers=localhost:29092,localhost:39092,localhost:49092 --topic testTopic --num-records 1000 --record-size 10 --throughput 10<br />...<br />1000 records sent, 99.930049 records/sec (0.00 MB/sec), 3.31 ms avg latency, 263.00 ms max latency, 2 ms 50th, 4 ms 95th, 38 ms 99th, 263 ms 99.9th.<br /><br /></pre>
<pre>$ bin/kafka-consumer-perf-test.sh --bootstrap-server localhost:29092,localhost:39092,localhost:49092 --topic testTopic --messages 1000<br />...<br />start.time, end.time, data.consumed.in.MB, MB.sec, data.consumed.in.nMsg, nMsg.sec, rebalance.time.ms, fetch.time.ms, fetch.MB.sec, fetch.nMsg.sec<br />2024-12-23 11:15:57:371, 2024-12-23 11:15:57:808, 0.0095, 0.0218, 1000, 2288.3295, 375, 62, 0.1537, 16129.0323</pre>
<div> </div>
<div>送受信したデータに対して、どの程度のレイテンシとなっているか等を測定することができます。</div>
<h3>kafka-e2e-latency.sh</h3>
<div><code>kafka-[producer,consumer]-perf-test.sh</code> は Producer と Consumer の性能を確認するためのツールでしたが、送信から受信までの End-to-End でのレイテンシを計測したい場合もあります。</div>
<div>他の Producer などと異なり、引数ごとの指定内容が決まっていますので注意が必要です。</div>
<div>各引数についてはコマンド実行時にヘルプが表示され、以下の通りの内容となっています。</div>
<ul>
<li> broker_list: Broker</li>
<li> topic: 送信先トピック</li>
<li> num_messages: 送信するメッセージ</li>
<li> producer_acks: producer が送信の際に利用する Acks の設定</li>
<li> message_size_bytes: 送信する1メッセージのサイズ（バイト数）</li>
</ul>
<pre>$./bin/kafka-e2e-latency.sh<br />USAGE: java org.apache.kafka.tools.EndToEndLatency broker_list topic num_messages producer_acks message_size_bytes [optional] properties_file<br />$ ./bin/kafka-e2e-latency.sh localhost:29092,localhost:39092,localhost:49092 testTopic 1000 all 10<br />...<br />0       142.06386600000002<br />Avg latency: 3.2986 ms<br />Percentiles: 50th = 2, 99th = 7, 99.9th = 142</pre>
<h3>trogdor.sh</h3>
<div>Kafka における障害試験の実施を行うためのツールです。</div>
<div>trogdor 用の Coordinator,Agent と呼ばれるプロセスを事前に動作させておきます。</div>
<div>また、別途試験用のファイルを定義しておき、ジョブとして登録することでディスク障害・ネットワーク障害などを疑似的に再現することが可能です。</div>
<div>詳しくは <a href="https://github.com/apache/kafka/tree/trunk/trogdor" target="_blank" rel="noopener noreferrer">trogdor の README</a>、もしくは <a href="https://cwiki.apache.org/confluence/display/KAFKA/Fault+Injection" target="_blank" rel="noopener noreferrer">Wiki</a> を参照ください。</div>
<div> </div>
<h2>まとめ</h2>
<div>何かと面倒に感じることの多い並列分散環境の構築ですが、最近では用途に応じて簡単に環境を構築することが可能です。これを機に、みなさんもApache Kafkaの世界に飛び込んでみてはいかがでしょうか。</div>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
