Kafka の順序保証はトピック全体ではなくパーティション単位で成立する。したがって、メッセージキーの設計は配分だけでなく順序保証のスコープを決める中核となる。
本稿では、公式ドキュメントの挙動を前提に、デフォルトパーティショナーの動作、ホットパーティション回避、シリアライズの安定性、パーティション数変更の影響を試験観点と実務観点の両面から整理する。
Kafka が提供する順序保証は「同一パーティション内の書き込み順序」に限られる。したがって、同じキーを常に同じパーティションに送る設計であれば、そのキーのメッセージは順序を維持できる。一方で、異なるパーティションを横断した全順序は保証されない。
プロデューサは1パーティションに対して送信順序を維持する。ただしリトライや同時送信数の設定次第で乱れうる。コンシューマグループでは1パーティションは同時に1コンシューマスレッドにだけ割り当てられるため、並列度の最小単位もパーティション数に一致する。
Kafka の標準的なプロデューサは、キーが設定されている場合、キーをシリアライズしたバイト列にハッシュを取り、その結果をパーティション数で割った余りで配分する。同じキーのバイト列であれば常に同じパーティションに送られる。
キーが null の場合は、ラウンドロビンに近い戦略(バッチ効率を考慮した粘着的な配分)でパーティションに分散される。null キーではキー単位の順序保証は得られないため、順序が必要な場合は必ずキーを付与する。
キーによる配分と順序保証の流れ
偏ったキー分布は単一パーティションへの集中を招き、遅延やスループット低下につながる。キー設計時は順序のスコープとスケーリングの両立を明確にする必要がある。
完全なキー順序を維持しつつスループットを上げたい場合は、パーティション数を増やしつつプロデューサ・コンシューマの並列度を合わせるのが基本路線。順序を一部緩和できる場合はソルトや合成キーでスケールを取りに行く。
| キー戦略 | 順序保証の範囲 | スキューリスク | スケーラビリティ |
|---|---|---|---|
| null キー | なし | 低 | 高 |
| ビジネスキー単体(例: userId) | キー内で強い | 分布次第で高 | 中 |
| ソルト付きキー(userId + ランダム) | 事実上なし | 低 | 高 |
| 合成キー(userId + sessionId 等) | セッション等の下位粒度 | 中 | 中〜高 |
| カスタムパーティショナー(安定ハッシュ) | キー内で強い | 分布次第 | 中 |
デフォルトパーティショナーは、キーオブジェクトそのものではなく、シリアライズ後のバイト列をハッシュする。つまり、論理的に同じキーでも、シリアライザやエンコーディングが変わればパーティション配分が変わる可能性がある。
複合キーを文字列連結で表現する場合は、区切り文字や正規化ルールを固定し、将来的な変更でバイト列が変わらないようにする。Avro/Protobuf のバイナリ表現を使う場合も、フィールド順やデフォルト値、可変長エンコーディングの影響を理解して安定化させる。
Kafka の標準ハッシュは単純な剰余演算を使うため、パーティション数を変更するとキー→パーティションの対応関係が広範に変わる。これにより、同一キーが別パーティションに移動し、コンシューマ側の状態や順序前提に影響が出る。
Kafka Streams や ksqlDB では、キー変更やシャッフルが必要な演算で自動的に再パーティション用トピックが使われる。外部のプロデューサ設計でも、パーティション数変更を前提にした可観測性(遅延・スループット・ホットパーティション検知)を準備しておくと安全。
順序と重複制御を両立する場合、プロデューサ側では冪等送信を有効化し、acks=all と組み合わせる。in-flight リクエスト数は冪等時の上限内に収め、リトライ時の順序崩れを回避する。コンシューマ側は1パーティション1スレッド処理を守り、必要なら整列用のバッファとタイムアウトを設ける。
ホットパーティション検知のために、キー分布のメトリクス(partitionごとのレコード数・レイテンシ)を可視化する。スキューが閾値を超えたら、要件に応じて合成キー化、限定的ソルト、あるいはパーティション数の増加を検討する。
Java: カスタムパーティショナーの雛形(安定ハッシュの例)
package example;
import java.util.Map;
import org.apache.kafka.clients.producer.Partitioner;
import org.apache.kafka.common.Cluster;
import org.apache.kafka.common.utils.Utils;
public class StableHashPartitioner implements Partitioner {
private int virtualNodes = 64; // 調整可能。増やすと分散が滑らかに
@Override
public void configure(Map<String, ?> configs) {
Object v = configs.get("stable.partitioner.vnodes");
if (v instanceof String) {
try { virtualNodes = Integer.parseInt((String) v); } catch (NumberFormatException ignore) {}
}
}
@Override
public int partition(String topic, Object keyObj, byte[] keyBytes,
Object value, byte[] valueBytes, Cluster cluster) {
int partitionCount = cluster.partitionsForTopic(topic).size();
if (keyBytes == null || partitionCount <= 0) {
// フォールバック: デフォルトの粘着分配に近い動きはしない。単純剰余にする
return 0;
}
// 簡易な HRW/Rendezvous 風: 複数の仮想ノードに対してスコアを計算し、最大のものを選ぶ
int selected = 0;
long bestScore = Long.MIN_VALUE;
for (int p = 0; p < partitionCount; p++) {
long score = 0L;
for (int v = 0; v < virtualNodes; v++) {
// Utils.murmur2 は Kafka が内部で使う 32bit murmur2
int h1 = Utils.murmur2(keyBytes);
int h2 = Utils.murmur2((topic + ":" + p + ":" + v).getBytes());
long combined = ((long)h1 << 32) ^ (h2 & 0xffffffffL);
score = Math.max(score, combined);
}
if (score > bestScore) { bestScore = score; selected = p; }
}
return selected;
}
@Override
public void close() {}
}
CCDAK
問題 1
Kafka トピックのパーティション数を変更せずに、プロデューサ側の設定だけを調整した。どの変更が既存の論理キーに対する「キー→パーティション」対応を変える可能性が最も高いか?
正解: A
デフォルトパーティショナーはキーのシリアライズ後のバイト列をハッシュしてパーティションを決める。シリアライザやフォーマット変更は同一論理キーでもバイト列を変え、配分が変化する。他の選択肢は配分アルゴリズムそのものには影響しない。
null キーとログコンパクションの関係は?
ログコンパクションはキー単位で最新版を残す。キーが null のレコードはコンパクションの対象にならない。削除を表す Tombstone は「非 null キーかつ null バリュー」の組み合わせで表現する。
順序保証を維持したままスループットを上げるには?
キーを維持したままパーティション数とコンシューマ並列度を増やす。プロデューサは冪等送信と acks=all を有効化し、max.in.flight.requests.per.connection を安全な範囲に設定する。キーのソルトは順序を壊すため、要件的に許される範囲に限定する。
パーティション数を増やすとキー→パーティション対応は維持される?
いいえ。デフォルトのハッシュは剰余演算に依存するため、パーティション数変更で対応は広範に変わる。安定性が重要なら、安定ハッシュを用いたカスタムパーティショナーや、変更を前提にした再処理・再整列の設計を行う。
NicheeLab編集部
データエンジニアリング・クラウド資格の専門家。Databricks・Snowflake等の認定資格を保有し、実務経験に基づいた問題作成・解説を行っています。NicheeLab運営。
Kafka Topic と Partition の基礎: 分散とスケーラビリティの要
CCDAK 対策と実務の両立を意識し、Topic/Partition/Replica/Consumer Group の役...
CCDAK 試験ガイド:出題範囲・配点・申込み・対策
Confluent Certified Developer for Apache Kafka (CCDAK) の出題範囲...
Confluent Certified Administrator (CCAAK) 対策: 出題範囲・配点の考え方・運用観点の要点
CCAAKに向けて、試験領域の押さえどころを運用目線で整理。プロダクションで通用する設定・監視・セキュリティの実践知を、...
Kafka の Replica と In-Sync Replicas を正しく設計する: 耐障害性と一貫性
レプリカとISRの仕組みを起点に、acks と min.insync.replicas、クリーン/アンクリーンリーダー選...
Kafka の Offset とコミット: ポジション管理と at-least-once の基礎
CCDAK 対策と実務の両立を意識して、Kafka コンシューマのオフセット管理とコミット戦略を整理。at-least-...