- メッセージを取得する前に、次のことを確認する必要があります
- クライアントがコーディネーターに接続しました
- コンシューマは、コーディネータによって割り当てられたパーティションを受け取ります。
- コンシューマーがメッセージをプルするための準備
- 接続コーディネーター
- コンシューマ グループに参加するリクエストをコーディネータに送信し、コーディネータから割り当てられたパーティションを取得します。
1. コンシューマーがメッセージをプルする前のシーケンス
- 消費者はコーディネーターに消費者グループへの参加を申請します。
- サーバー側でコンシューマを管理するコーディネータがあり、コーディネータがコンシューマ グループにコンシューマを追加します。
- コーディネーターはすべてのコンシューマにパーティションを割り当てます
- コンシューマは、コーディネータから割り当てられたパーティションを取得します。
- コンシューマはパーティションからメッセージをプルします
2. リクエストを送信して結果を取得する
- 各コンシューマーは JoinGroupRequest (コンシューマー グループへの参加リクエスト) をコーディネーターに送信する必要があり、各コンシューマーは JoinGroupResponse (コンシューマー グループへの参加応答) から割り当てられたパーティションを取得します。
- 処理の疑似コードは次のとおりです。実際のコードは、AbstractCoordinator の joinGroupIfNeeded メソッド内にあります。
JoinGroupResponse joinResult = sendJoinGroupRequest();
Assignment assignment = partitionAssignment(joinResult);
subscriptions.assignFromSubscribed(assignment.partitions());
![ここに画像の説明を挿入](https://img-blog.csdnimg.cn/3e11891bddce4cd7b9850b3683df7274.png)
- 実際の状況では、すべてのコンシューマがコンシューマ グループに参加するのを待ってからパーティションを割り当てるアルゴリズムを実行するため、最初に返されるのは非同期オブジェクトです。
RequestFuture<JoinGroupResponse> future = sendJoinGroupRequest();
client.poll(future);
Assignment assignment = partitionAssignment(future.get());
3. 消費者が消費者グループに参加する
- ensureActiveGroup を呼び出してコンシューマ ステップに参加します
- onJoin準備フェーズでの準備
- リクエストを開始する sendJoinGroupRequest
- 結合が成功した場合は onJoinComplete
onJoinPrepare(generation.generationId, generation.memberId);
joinFuture = sendJoinGroupRequest();
onJoinComplete(generation.generationId, generation.memberId, generation.protocol, future.value());
- 注: リクエストが開始されたときのメンバー番号は UNKNOWN_MEMBER_ID で、最初の結合後に実際のメンバー番号が返されます。再結合またはリバランスが発生するときに実際のメンバー番号を指定する必要があります。
- コンシューマーがコーディネーターに接続し、「コンシューマー グループに参加」リクエストを送信し、パーティションを取得するためのロジックはすべて AbstractCoordinator にあります。
public abstract class AbstractCoordinator implements Closeable {
private boolean rejoinNeeded = true;
private boolean needsJoinPrepare = true;
protected synchronized boolean needRejoin() {
return rejoinNeeded;
}
public void ensurePartitionAssignment(){
if(subscriptions.partitionsAutoAssigned())
ensureActiveGroup();
}
public void ensureActiveGroup(){
if(!needRejoin()) return;
if (needsJoinPrepare) {
onJoinPrepare(generation.generationId, generation.memberId);
needsJoinPrepare = false;
}
while (needRejoin() || rejoinIncomplete()) {
ensureCoordinatorReady();
RequestFuture<ByteBuffer> future = sendJoinGroupRequest();
client.poll(future);
if (future.succeeded()) {
needsJoinPrepare = true;
onJoinComplete(generation.generationId, generation.memberId, generation.protocol, future.value());
}
}
}
}
- 処理を実行するパーティションに必ず割り当ててください
- 最初の needJoinPrepare と rejoinNeeded は両方とも true であり、コンシューマーは開始時にデフォルトでコンシューマー グループに参加します。
- needRejoin() が完了したら、まず onJoinPrepare() を呼び出して、オフセットの送信などの準備作業を実行します。
- コンシューマ・グループに参加する前に複数の準備が行われないように、準備が完了した後に needJoinPrepare=false を変更します。
- needRejoin() を満たし、ループ本体を実行します。リクエストを送信し、クライアントのポーリングを 1 回呼び出して結果の取得を試みます。
- コンシューマはパーティションに割り当てられ、rejoinNeeded を false に更新し、needsJoinPrepare を true にリセットします。
- onJoinComplete() メソッドは、コンシューマがコンシューマ グループに正常に参加し、それをパーティションに割り当てた後、サブスクリプション ステータスの needPartitionsAssigned を false に更新します。この変数は、コンシューマ グループに再参加するかどうかを決定します。
- コンシューマーが開始すると、さまざまなイベント (パーティションの変更、コンシューマー メンバーの変更、セッション タイムアウトなど) のリスナーを ZK に登録します。登録されたイベントが発生すると、ZKRebalanceListener のリバランス操作がトリガーされます。