v1.4 では Kafka Simulator にトランザクションモジュールが加わります。エンジニアが最もよく頷き、最も実際には目にしないテーマ — exactly-once セマンティクス — をめぐる10 本の新しいシナリオです。カリキュラムは 125 本中 55 本に到達します。
v1.4 の内容
トランザクションは書き込みの流れを一つの原子的な単位に変え、コンシューマーが何を見てよいかまで変えます。
read_committedと last stable offset(LSO) — トランザクショナルなコンシューマーが high watermark ではなく LSO まで読む理由と、開いたままのトランザクションがその天井をどう押しとどめるか。- begin / commit / abort — プロデューサーのトランザクションのライフサイクルを、自分で動かせる状態機械として。abort マーカーが対象レコードに何をするかも含めて。
- consume–process–produce ループ —
sendOffsetsToTransactionと、オフセットのコミットをトランザクションの内側で行うことこそがエンドツーエンドの exactly-once を成立させる理由。 - フェンシング — ゾンビプロデューサーがエポックによって締め出される仕組みと、それがモデル全体を支える安全網である理由。
exactly-once が教えにくいのは、その多くが目に見えないからです。マーカー、LSO、エポック、そして中断されたレコードを黙って読み飛ばすコンシューマー。シミュレーターはそのすべてをタイムラインに載せます — 開いたトランザクションの下で LSO が動かずにいて、コミットした瞬間に前へ跳ぶ様子を見られます。
フリープレイの新しいクラスタタイプ: アクティブ/アクティブ
v1.3 のアクティブ/パッシブから始まったトポロジーの階段は、さらに一段上がります。フリープレイのクラスタ選択に 3 つ目の形 — Active / active(アクティブ/アクティブ)が加わりました。2 つのリージョンがどちらも書き込みを受け付け、互いにミラーします。
これは意図的に「アクティブ/パッシブの矢印を二重にしただけ」ではありません。このプリセットは対称です。
- 各リージョンが自分のトピックを所有する。
westはwest.ordersを、eastはeast.ordersを所有し、それぞれが相手リージョンへ読み取り専用でミラーされます。こうして両側がストリーム全体を保持しつつ、同じ名前をめぐって誰が書けるのかという曖昧さが生じません。 - 各リージョンはローカルに書き、グローバルに読む。 プロデューサーは自分のリージョンのトピックにしか追記しません。各リージョンのコンシューマーグループはローカルのトピックとミラーされてきたコピーの両方を読むので、どのレコードも片側につき一度ずつ見えます。
- 各リージョンがそれぞれ独立したクラスタ。 どちらも独立した KRaft クォーラムを持つため、片方のリージョンのコントローラー — あるいはリージョンごと — を落として、生き残った側に何ができて何ができないのかを観察できます。
この最後の点こそ、このパックが教えるトランザクションの保証との鋭い対比です。exactly-once はクラスタ単位の約束であり、アクティブ/アクティブのペアは 2 つのクラスタです。トランザクションモジュールが与えてくれるものは 1 つのリージョンの内側で成り立ち、ミラーのところで止まります。
これらの形を解説する DR のカリキュラム自体は、引き続き v1.8 で登場します。サンドボックスが先に着地するのは意図的で、シナリオが語り出す前にアイデアを試せる場所を用意するためです。
レプリケーションの上に積み上げる
このパックは v1.3 の真上に立っています。トランザクションとは耐久性の保証に原子性を足したものなので、そこで読めるようになった ISR と high watermark はここでも土台のままです — LSO はその上に載る、より厳しい天井にすぎません。
シミュレーターを開いて、トランザクションを開始し、その中に produce して、abort してみてください。そのうえで read_committed のコンシューマーに何が見えて何が見えないかを確かめましょう。