DUE TO SPAM, SIGN-UP IS DISABLED. Goto Selfserve wiki signup and request an account.
| Table of Contents |
|---|
Status
Current state: Under DiscussionAccepted
Discussion thread: here
JIRA: here
...
All non-assignment metadata as defined in the
ConsumerGroupHeartbeatRequestsuch as the group ID, member ID, member epoch, instance ID, rack ID and rebalance timeout.The currently assigned active, standby and warm-up tasks. Each task is identified by a subtopology ID (which can be an arbitrary string in protocol for future extensibility, even though subtopologies are currently numbered) and a partition number.
The process ID to identify multiple members running in the same process (i.e. the same Streams client).
The user-defined endpoint to be used for running interactive queries.
- Topology metadata needed for creating internal topics and computing the assignment.
The topology epoch, which is defined by the client, and will be 0 normallyby default. The epoch can be bumped by the client to deploy a new version of the topology metadata.
For each task, the current sum of task changelog offsets and task changelog end offsets. These are used to determine whether a warm-up task is below
acceptable.recovery.lagand can be used to optimize the assignment in the assignor. For more details on these offsets see "Cumulative task changelog offsets and task changelog end offsets" section belowA flag to request shutdown of the whole application (only if the member epoch is the group leave epoch).
Group ID, member ID, member epoch, and instance ID (if defined by the client) are sent with each heartbeat request. Any other information that has not changed since the last heartbeat can be omitted, unless an error occurred.
...
The metadata sent to the broker via the heartbeat is persisted as a new record type in the __consumer_offsets topic and is part of the group coordinator state in subsequent requests. If one or more source topics or internal topics do not exist, the group will enter state NOT_READY and will attempt to create any missing internal topics (see more details below). Only after the topology metadata is initialized and all source topics and internal topics exist, the group coordinator starts assigning tasks to the members of the group.
Topology updates
To avoid unintential unintentional topology updates or rollbacks, updating the broker-side topology after it has been initialized for a group requires bumping the client-side configuration topology.epoch, which defaults to 0. By default, whenever a Streams member joins the group with a topology that is different from the current topology of the streams group, and the topology epoch is not bumped, the group coordinator will respond with an error, indicating that the member is incorrectly updating the broker-side topology.
...
- Source topics missing
Condition: A source topic is missing or a source topic regex resolves to zero topics.
Behavior: The group will enter/remain in stateNOT_READY. Heartbeat responses will indicate statusMISSING_SOURCE_TOPICS. In the status detail, we specify all missing source topics and all regular expressions matching zero topics. - Topics incorrectly partitionedSource topics inconsistent
Condition: The source Some topics are inconsistentincorrectly partitioned, if two source topics are supposed to be copartitioned according to the topology, but in the current topic metadata on the broker, the number of partitions for the two topics is different.
Behavior: The group will enter/remain in stateNOT_READY. Heartbeat responses will indicate statusSOURCE_TOPICS_INCONSISTENT. In the status detail, we specify at least one inconsistency.Internal topics are inconsistent
Condition: One or more internal topics are inconsistent, for example, they are not copartition despite being part of a copartition group, or the number of partitions in a changelog topic does not correspond to the maximal number of source topic partition for that subtopology.
Behavior: The group will enter/remain in stateNOT_READY. Heartbeat responses will indicate statusINTERNALINCORRECTLY_PARTITIONED_TOPICS_INCONSISTENT. In the status detail, we specify at least one inconsistencyincorrectly partitioned topic. - Internal topics are missing
Condition: One or more internal topics are missing.
Behavior: If discovered during a heartbeat, the group coordinator will attempt to create the internal topics by sending a corresponding topic create request will be sent to the Kraft coordinator. There can only be one such request in-flight at a time, an appropriate back-off mechanism will be used to prevent too many attempts to create the topics. If the appropriate ACL for topic creation are not assigned to the principle executing the heartbeat, no such attempt will be made. The group will enter/remain in stateNOT_READY. Heartbeat responses will indicate statusMISSING_INTERNAL_TOPICS. In the status detail, we specify whether an attempt to create the topics was made, whether and why a previous attempt failed, whether sufficient ACLs to create the topics are available. - Topic configuration mismatches
If an internal topic exists, but does not have the same configuration as defined in the topology (all parameters of the topic beside number of partitions, that is, replication factor, retention time, etc.), this will be logged on the broker, but otherwise be ignored.
...
The partition metadata for the group, which is tracked by the group coordinator, is the partition metadata of all input topics (i.e., user source topics and internal repartition topics we read from).
The group epoch is bumped:
- When a member joins or leaves the group.
- When a member is fenced or removed from the group by the group coordinator.
- When the partition metadata is updated. For instance when a new partition is added or a new topic matching the subscribed topics is created.
- When a member with an assigned warm-up task reports a task changelog offset and task changelog end offset whose difference is less that than
acceptable.recovery.lag. - When a member updates its topology metadata, rack ID, client tags or process ID. Note: Typically, these do not change within the lifetime of a Streams client, so this only happens when a member with static membership rejoins with an updated configuration.
- When an assignment configuration for the group is updated.
...
For active processing tasks, the cumulative task changelog end offset is the same as the cumulative task changelog offset
For all restoring tasks (active, standby or warm-up), the cumulative end-offset is the sum of the last end offsets cached by the restore consumer. If an end offset of a topic partition is unknown, no end-offset is reported.
For dormant standby tasks, no end-offset is reported.
...
Active tasks are reconciled like topic partitions in the KIP-848 consumer group protocol, that is, for reconciling the target assignment, the reconciliation follows three phases:
The group coordinator first asks the member to revoke any active tasks that are not assigned to that member in the target assignment any more (if either no warmup tasks are used at all, or if the target member has a hot standby/warmup task), by removing those active tasks from the set of tasks sent to the member in the heartbeat response
The member must first confirm revocation of these active tasks by removing them from the set of active tasks sent in the heartbeat request
Now, active tasks will be incrementally assigned to the member. An active task is assigned as soon as no other client owns it anymore, that is, once the previous owner (if any) has confirmed the revocation of the corresponding active task.
Standby and warm-up tasks are reconciled in parallel with active tasks, but following slightly different logic:
As for active tasks, standby and warm-up tasks removed from the members target assignment are removed from the assignment sent in the heartbeat response immediately, that is, with the next heartbeat. The member confirms the revocation of the tasks as soon as the state directory (or any other resource related to the task) is closed.
Newly assigned standby and warm-up tasks await that any member with the same
processIdowning that task (as active or standby) confirms revocation of the task by removing it from the corresponding set in a heartbeat response. That is, a task that is not an active task or a standby task on any other member with the sameprocessIdcan be assigned immediately. Otherwise, it is assigned as soon as the blocking task is revoked. Target assignments that assign a task to two members with the sameprocessIdare invalid.
...
The possible states of the streams group are EMPTY, ASSIGNING, RECONCILING , STABLE, NOT_READY, DEAD. The states are similar as for consumer groups, but contain an extra stat NOT_READY, which is used when a group is not empty and has a topology set, but not all topics are present to start processing using the topology.
Global & Dynamic Group Configuration
We make core assignment options configurable centrally on the broker, without relying on each clients configuration. This allows tuning a streams group without redeploying the streams application. The three core assignment options will be introduced on the broker-side: acceptable.recovery.lag, num.warmup.replicas and , num.standby.replicas, and rack.aware.assignment.tags. They can be configured both globally on the broker, and dynamically for specific streams groups through the IncrementalAlterConfigs and DescribeConfigs RPCs.
We store the last used assignment configuration in the group metadata on the broker. This way, we can detect if an assignment configuration is dynamically changed, and we can trigger reassignment immediately.
Online Migration from a Online Migration from a Classic Consumer Group to a Streams Group
...
Let's recapitulate how the classic rebalance protocol works in Streams. First, the consumers in a Streams client join or re-join the group with the JoinGroup API. The JoinGroup request contains the subscribed topics, the owned partitions, the generation ID, the Streams-specific subscription info, and some other fields. The Streams-specific subscription info contains the process ID of the Streams client, the owned active and standby tasks, the task offset sums, the user endpoints for Interactive Query, and some more fields. When all the consumers of the Streams clients of the Streams application have joined, the group coordinator picks a leader for the group out of the consumers and sends back the JoinGroup response to all the members of the group (i.e., consumers that joined). The JoinGroup response contains the member ID, the generation ID, and the member ID of the leader (to make the leader aware of leadership) as well as all the consumer and Streams-specific metadata about subscribed topics, owned partitions, tasks, etc. The leader uses the data in the JoinGroup response for computing the assignment. Second, all the members in the Streams clients collect their assignment—computed by the leader—by using the SyncGroup API. The leader sends the computed assignment with the SyncGroup request to the group coordinator, and the group coordinator distributes the assignment to the members through the SyncGroup response. In parallel, the members heartbeat with the Heartbeat API in order to maintain their session. The Heartbeat API is also used by the group coordinator to inform the members about an ongoing rebalance. All those interactions are synchronized on the generation of the group. It is important to note that the consumer does not make any assumption about the generation ID. It basically uses what it receives from the group coordinator. The classic rebalance protocol used in Streams supports two modes: Eager and Cooperative. In the eager mode, the consumer revokes all its partitions before rejoining the group during a rebalance. In the cooperative mode, the consumer does not revoke any partitions before rejoining the group. However, it revokes the partitions that it does not own anymore when it receives its new assignment and rejoins immediately if he it had to revoke any partitions.
...
The member must set all the (top level) fields with the exception of RackId and InstanceId when it joins for the first time or when an error occurs (e.g. request timed out). Otherwise, it is expected to only fill in the fields which have changed since the last heartbeat.
| Note |
|---|
Update for Apache Kafka 4.4 release. In Apache Kafka 4.2 release, there is a bug in the implementation of the |
| Code Block | ||||
|---|---|---|---|---|
| ||||
{
"apiKey": TBD,
"type": "request",
"listeners": ["broker"],
"name": " | ||||
| Code Block | ||||
| ||||
{ "apiKey": TBD, "type": "request", "listeners": ["broker", "zkBroker"], "name": "StreamsGroupHeartbeatRequest", "validVersions": "0", // "0" in 4.2/4.3 release; bumped to "0-1" in 4.4 release "flexibleVersions": "0+", "fields": [ { "name": "GroupId", "type": "string", "versions": "0+", "entityType": "groupId", "about": "The group identifier." }, { "name": "MemberId", "type": "string", "versions": "0+", "about": "The member ID generated by the streams coordinatorconsumer. The member ID must be kept during the entire lifetime of the memberstreams consumer process." }, { "name": "MemberEpoch", "type": "int32", "versions": "0+", "about": "The current member epoch; 0 to join the group; -1 to leave the group; -2 to indicate that the static member will rejoin." }, { "name": "InstanceIdEndpointInformationEpoch", "type": "stringint32", "versions": "0+", "nullableVersions": "0+", "default": "null", "about": "nullThe ifcurrent notendpoint providedepoch orof if this client, represents the latest endpoint epoch this client received"}, { "name": "InstanceId", "type": "string", "versions": "0+", "nullableVersions": "0+", "default": "null", "about": "null if not provided or if it didn't change since the last heartbeat; the instance ID for static membership otherwise." }, { "name": "RackId", "type": "string", "versions": "0+", "nullableVersions": "0+", "default": "null", "about": "null if not provided or if it didn't change since the last heartbeat; the rack ID of the consumermember otherwise." }, { "name": "RebalanceTimeoutMs", "type": "int32", "versions": "0+", "default": -1, "about": "-1 if it didn't change since the last heartbeat; the maximum time in milliseconds that the coordinator will wait on the member to revoke its partitionstasks otherwise." }, { "name": "Topology", "type": "Topology", "versions": "0+", "nullableVersions": "0+", "default": "null", "about": "The topology metadata of the streams application. Used to initialize the topology of the group and to check if the topology corresponds to the topology initialized for the group. Only sent when memberEpoch = 0, must be non-empty. Null otherwise.", "fields": [ { "name": "Epoch", "type": "int32", "versions": "0+", "about": "The epoch of the topology. Used to check if the topology corresponds to the topology initialized on the brokers." }, { "name": "Subtopologies", "type": "[]Subtopology", "versions": "0+", "about": "The sub-topologies of the streams application.", "fields": [ { "name": "SubtopologyId", "type": "string", "versions": "0+", "about": "String to uniquely identify the sub-topologysubtopology. Deterministically generated from the topology" }, { "name": "SourceTopics", "type": "[]string", "versions": "0+", "about": "The topics the topology reads from." }, { "name": "SourceTopicRegex", "type": "[]string", "versions": "0+", "about": "The regular expressions identifying topics the sub-topologysubtopology reads from." }, { "name": "StateChangelogTopics", "type": "[]TopicInfo", "versions": "0+", "about": "The set of state changelog topics associated with this sub-topologysubtopology. Created automatically." }, { "name": "RepartitionSinkTopics", "type": "[]string", "versions": "0+", "about": "The repartition topics the sub-topologysubtopology writes to." }, { "name": "RepartitionSourceTopics", "type": "[]TopicInfo", "versions": "0+", "about": "The set of source topics that are internally created repartition topics. Created automatically." }, { "name": "CopartitionGroups", "type": "[]CopartitionGroup", "versions": "0+", "about": "A subset of source topics that must be copartitioned.", "fields": [ { "name": "SourceTopics", "type": "[]int16", "versions": "0+", "about": "The topics the topology reads from. Index into the array on the subtopology level." }, { "name": "SourceTopicRegex", "type": "[]int16", "versions": "0+", "about": "Regular expressions identifying topics the subtopology reads from. Index into the array on the subtopology level." }, { "name": "RepartitionSourceTopics", "type": "[]int16", "versions": "0+", "about": "The set of source topics that are internally created repartition topics. Index into the array on the subtopology level." } ]} ]} ] }, { "name": "ActiveTasks", "type": "[]TaskIds", "versions": "0+", "nullableVersions": "0+", "default": "null", "about": "Currently owned active tasks for this client. Null if unchanged since last heartbeat." }, { "name": "StandbyTasks", "type": "[]TaskIds", "versions": "0+", "nullableVersions": "0+", "default": "null", "about": "Currently owned standby tasks for this client. Null if unchanged since last heartbeat." }, { "name": "WarmupTasks", "type": "[]TaskIds", "versions": "0+", "nullableVersions": "0+", "default": "null", "about": "Currently owned warm-up tasks for this client. Null if unchanged since last heartbeat." }, { "name": "ProcessId", "type": "string", "versions": "0+", "nullableVersions": "0+", "default": "null", "about": "Identity of the streams instance that may have multiple consumers. Null if unchanged since last heartbeat." }, { "name": "UserEndpoint", "type": "Endpoint", "versions": "0+", "nullableVersions": "0+", "default": "null", "about": "User-defined endpoint for Interactive Queries. Null if unchanged since last heartbeat or if not defined on the client." }, { "name": "ClientTags", "type": "[]KeyValue", "versions": "0+", "nullableVersions": "0+", "default": "null", "about": "Used for rack-aware assignment algorithm. Null if unchanged since last heartbeat." }, { "name": "TaskOffsets", "type": "[]TaskOffset", "versions": "0+", "nullableVersions": "0+", "default": "null", "about": "Cumulative changelog offsets for tasks. Only updated when a warm-up task has caught up, and according to the task offset interval. Null if unchanged since last heartbeat." }, { "name": "TaskEndOffsets", "type": "[]TaskOffset", "versions": "0+", "nullableVersions": "0+", "default": "null", "about": "Cumulative changelog end-offsets for tasks. Only updated when a warm-up task has caught up, and according to the task offset interval. Null if unchanged since last heartbeat." }, { "name": "ShutdownApplication", "type": "bool", "versions": "0+", "default": false, "about": "Whether all Streams clients in the group should shut down." } ], "commonStructs": [ { "name": "KeyValue", "versions": "0+", "fields": [ { "name": "Key", "type": "string", "versions": "0+", "about": "key of the config" }, { "name": "Value", "type": "string", "versions": "0+", "about": "value of the config" } ]}, { "name": "TopicInfo", "versions": "0+", "fields": [ { "name": "Name", "type": "string", "versions": "0+", "about": "The name of the topic." }, { "name": "Partitions", "type": "int32", "versions": "0+", "about": "The number of partitions in the topic. Can be 0 if no specific number of partitions is enforced. Always 0 for changelog topics." }, { "name": "ReplicationFactor", "type": "int16", "versions": "0+", "about": "The replication factor of the topic. Can be 0 if the default replication factor should be used." }, { "name": "TopicConfigs", "type": "[]KeyValue", "versions": "0+", "about": "Topic-level configurations as key-value pairs." } ]}, { "name": "Endpoint", "versions": "0+", "fields": [ { "name": "Host", "type": "string", "versions": "0+", "about": "host of the endpoint" }, { "name": "Port", "type": "uint16", "versions": "0+", "about": "port of the endpoint" } ]}, { "name": "TaskOffset", "versions": "0+", "fields": [ { "name": "SubtopologyId", "type": "string", "versions": "0+", "about": "The subtopology identifier." }, { "name": "Partition", "type": "int32", "versions": "0+", "about": "The partition." }, { "name": "Offset", "type": "int64", "versions": "0+", "about": "The offset." } ]}, { "name": "TaskIds", "versions": "0+", "fields": [ { "name": "SubtopologyId", "type": "string", "versions": "0+", "about": "The subtopology identifier." }, { "name": "Partitions", "type": "[]int32", "versions": "0+", "about": "The partitions of the input topics processed by this member." } ]} ] } |
...
READon groupCREATEon cluster resource, orCREATEon all topics inStateChangelogTopicsandRepartitionSourceTopics- Note that this ACLs are only required if the group coordinator should create the internal topics implicitly. If the internal topics are created explicitly, this ACL is not needed for the Streams group heartbeat.
DESCRIBE_CONFIGSon on all topics included in the message
...
GroupIdmust be non-empty.Either
MemberIdis must be non-empty orMemberEpochis 0.MemberEpochmust be >= -2.InstanceId, if not null, must be non-empty.RebalanceTimeoutMsmust be larger than zero in the first heartbeat request.ActiveTasks,StandbyTasksandWarmupTaskshave to be disjoint setsEach element ofActiveTasks,StandbyTasksandWarmupTaskshas to be a valid task ID in the topology initialized for the group ID.ActiveTasks,StandbyTasksandWarmupTaskshave to be non-null and empty when joining (member epoch is 0)- If
MemberEpochis 0,Topologyshould be non-null. Otherwise, it should benull.
...
- Performs request validation.
If the member joins the group (i.e. member epoch is 0):
- Look up or create the group.
- If the group is created the topology epoch of the group is set to the topology epoch sent by the member.
GROUP_ID_NOT_FOUNDis returned if the group ID is associated with a group type that is notstreamsorclassic(the latter will be allowed for migration).- Compare the topology epoch of the request ER to the topology epoch of the group EG
- If ER=EG, check if topology metadata in the request is equal to the topology metadata of the group, otherwise fail with
STREAMS_INVALID_TOPOLOGY_EPOCH - If ER<EG, fail with
STREAMS_TOPOLOGY_FENCED - If ER>EG+1, fail with
STREAMS_INVALID_TOPOLOGY_EPOCH - If ER=EG+1, update the topology by write riting the new topology record to the offset topic
- If ER=EG, check if topology metadata in the request is equal to the topology metadata of the group, otherwise fail with
- Creates the member.
- Look up or create the group.
- If the member is already part of the group (i.e. member epoch is greater than 0):
- Looks up the group.
GROUP_ID_NOT_FOUNDis returned if the group ID does not exist anymore.- If the member does not exist, returns
UNKNOWN_MEMBER_ID - Checks whether the member epoch matches the member epoch in its current assignment.
FENCED_MEMBER_EPOCHis returned otherwise. The member is also removed from the group.- There is an edge case here. When the group coordinator transitions a member to its target epoch, the heartbeat response with the new member epoch may be lost. In this case, the member will retry with the member epoch that it knows about and its request will be rejected with a
FENCED_MEMBER_EPOCH. This will be handled as in KIP-848.
- There is an edge case here. When the group coordinator transitions a member to its target epoch, the heartbeat response with the new member epoch may be lost. In this case, the member will retry with the member epoch that it knows about and its request will be rejected with a
- If the topology epoch in the request is less than the topology epoch of the group, set state
STALE_TOPOLOGYin the response.
- Updates information of the member if needed. The group epoch is incremented if there is any change.
- If the topology or topic metadata changed, detect any topology / topic mismatches as described earlier in this document.
- Reconcile the member assignments as explained earlier in this document.
...
- When a member assignment gets changed it will bump the StreamsGroup
EndpointEpochand bump the corresponding memberEndpointInformationEpochin the response. When all membersEndpointInformationEpochvalues converge on the same value as the group-wide EndpointEpoch updated IQ information will be included in the member heartbeat response.
Response Schema
The group coordinator will only set the ActiveTasks, StandbyTasks and WarmupTasks fields until the member acknowledges that it has converged to the desired assignment. This is done to ensure that the members converge to the target assignment.
| Note |
|---|
Update for Apache Kafka 4.4 release. In Apache Kafka 4.2 release, there is a bug in the implementation of the |
| Code Block | ||||
|---|---|---|---|---|
| ||||
{
"apiKey": TBD,
"type": "response",
"name": "StreamsGroupHeartbeatResponse",
"validVersions": "0", // "0" in 4.2/4.3 release; bumped to "0-1" in 4.4 release
" | ||||
| Code Block | ||||
| ||||
{ "apiKey": TBD, "type": "response", "name": "StreamsGroupHeartbeatResponse", "validVersions": "0", "flexibleVersions": "0+", // Supported errors: // - GROUP_AUTHORIZATION_FAILED (version 0+) // - GROUP_ID_NOT_FOUND (version 0+) // - NOT_COORDINATOR (version 0+) // - COORDINATOR_NOT_AVAILABLE (version 0+) // - COORDINATOR_LOAD_IN_PROGRESS (version 0+) // - INVALID_REQUEST (version 0+) // - UNKNOWN_MEMBER_ID (version 0+) // - FENCED_MEMBER_EPOCH (version 0+) // - UNRELEASED_INSTANCE_ID (version 0+) // - GROUP_MAX_SIZE_REACHED (version 0+) // - TOPIC_AUTHORIZATION_FAILED (version 0+) // - CLUSTER_AUTHORIZATION_FAILED (version 0+) // - STREAMS_INVALID_TOPOLOGY (version 0+) // - STREAMS_INVALID_TOPOLOGY_EPOCH (version 0+) // - STREAMS_TOPOLOGY_FENCED (version 0+) "fields": [ // Same as consumer group heart beat { "name": "ThrottleTimeMs", "type": "int32", "versions": "0+", "about": "The duration in milliseconds for which the request was throttled due to a quota violation, or zero if the request did not violate any quota." }, { "name": "ErrorCode", "type": "int16", "versions": "0+", "about": "The top-level error code, or 0 if there was no error" }, { "name": "ErrorMessage", "type": "string", "versions": "0+", "nullableVersions": "0+", "default": "null", "about": "The top-level error message, or null if there was no error." }, { "name": "MemberId", "type": "string", "versions": "0+", "nullableVersionsabout": "0+", "default": "null", "about": "The member idThe member id is always generated by the coordinator. Only provided when the member joins with MemberEpoch == 0." },streams consumer."}, { "name": "MemberEpoch", "type": "int32", "versions": "0+", "about": "The member epoch." }, { "name": "HeartbeatIntervalMs", "type": "int32", "versions": "0+", "about": "The heartbeat interval in milliseconds." }, { "name": "AcceptableRecoveryLag", "type": "int32", "versions": "0+", "about": "The maximal lag a warm-up task can have to be considered caught-up." }, // incorrectly implemented as `int32` in 4.2 release; updated to `int64` and request/response version bump to "1" in 4.4 release. { "name": "TaskOffsetIntervalMs", "type": "int32", "versions": "0+", "about": "The interval in which the task changelog offsets on a client are updated on the broker. The offsets are sent with the next heartbeat after this time has passed." }, { "name": "Status", "type": "[]Status", "versions": "0+", "nullableVersions": "0+", "default": "null", "about": "Indicate zero or more status for the group. Null if unchanged since last heartbeat." }, // The streams app knows which partitions to fetch from given this information { "name": "ActiveTasks", "type": "[]TaskIds", "versions": "0+", "nullableVersions": "0+", "default": "null", "about": "Assigned active tasks for this client. Null if unchanged since last heartbeat." }, { "name": "StandbyTasks", "type": "[]TaskIds", "versions": "0+", "nullableVersions": "0+", "default": "null", "about": "Assigned standby tasks for this client. Null if unchanged since last heartbeat." }, { "name": "WarmupTasks", "type": "[]TaskIds", "versions": "0+", "nullableVersions": "0+", "default": "null", "about": "Assigned warm-up tasks for this client. Null if unchanged since last heartbeat." }, // IQ-related information { "name": "EndpointInformationEpoch", "type": "int32", "versions": "0+", "about": "The endpoint epoch set in the response"}, { "name": "PartitionsByUserEndpoint", "type": "[]EndpointToPartitions", "versions": "0+", "nullableVersions": "0+", "default": "null", "about": "Global assignment information used for IQ. Null if unchanged since last heartbeat." , "fields": [ { "name": "UserEndpoint", "type": "Endpoint", "versions": "0+", "about": "User-defined endpoint to connect to the node" }, { "name": "PartitionsActivePartitions", "type": "[]TopicPartition", "versions": "0+", "about": "All active partitions available on the node" }, ] { } ], "commonStructs"name": "StandbyPartitions", "type": [ "[]TopicPartition", "versions": "0+", "about": "All standby paritions available on the node"} ] } ], "commonStructs": [ { "name": "Status", "versions": "0+", "fields": [ // Possible status codes // 0 - STALE_TOPOLOGY - The topology epoch supplied is lower than the topology epoch for this streams group. // 1 - MISSING_SOURCE_TOPICS - One or more source topics are missing or a source topic regex resolves to zero topics. // Missing topics are indicated in the StatusDetail. // 2 - INCONSISTENTINCORRECTLY_SOURCEPARTITIONED_TOPICS - One or more source topics are incorrectly inconsistentpartitioned, forthat exampleis, they are not copartitioncopartitioned despite being // part of a copartition group. , or the number of partitions //in a changelog topic does not correspond // Inconsistent topics are indicated in the StatusDetail. // 3to - INCONSISTENT_INTERNAL_TOPICS - One or more internal topics are inconsistent, for example, they are not copartition despite beingthe maximal number of source topic partition for that subtopology. // part Incorrectly ofpartitioned atopics copartitionare group,indicated orin the numberStatusDetail. of partitions in a changelog topic// does not correspond // to the maximal number of source topic partition for that subtopology. // Inconsistent topics are indicated in the StatusDetail. // 4 3 - MISSING_INTERNAL_TOPICS - One or more internal topics are missing. // Missing topics are indicated in the StatusDetail. // The group coordinator will attempt to create all missing internal topics, if any errors occur during // topic creation, this will be indicated in StatusDetail. // 54 - SHUTDOWN_APPLICATION - A client requested the shutdown of the whole application. { "name": "StatusCode", "type": "int8", "versions": "0+", // 5 - ASSIGNMENT_DELAYED "about": "A code to- indicateNo thatassignment a was provided because assignment computation was delayed. // 6 - MISSING_CLIENT_TAGS - (Response v1+ only) The GC is configured to use `client.tag.` for rack-aware standby task assignment, but the client does not provide this tag { "name": "StatusCode", "type": "int8", "versions": "0+", "about": "A code to indicate that a particular status is active for the group membership" }, { "name": "StatusDetail", "type": "string", "versions": "0+", "about": "A string representation of the status." } ]}, { "name": "TopicPartition", "versions": "0+", "fields": [ { "name": "Topic", "type": "string", "versions": "0+", "about": "topic name" }, { "name": "Partitions", "type": "[]int32", "versions": "0+", "about": "partitions" } ]}, { "name": "TaskIds", "versions": "0+", "fields": [ { "name": "SubtopologyId", "type": "string", "versions": "0+", "about": "The subtopology identifier." }, { "name": "Partitions", "type": "[]int32", "versions": "0+", "about": "The partitions of the input topics processed by this member." } ]}, { "name": "Endpoint", "versions": "0+", "fields": [ { "name": "Host", "type": "string", "versions": "0+", "about": "host of the endpoint" }, { "name": "Port", "type": "uint16", "versions": "0+", "about": "port of the endpoint" } ]} ] } |
...
| Code Block | ||||
|---|---|---|---|---|
| ||||
{
"apiKey": TBD,
"type": "request",
"listeners": ["broker", "zkBroker"],
"name": "StreamsGroupDescribeRequest",
"validVersions": "0",
"flexibleVersions": "0+",
"fields": [
{ "name": "GroupIds", "type": "[]string", "versions": "0+", "entityType": "groupId",
"about": "The ids of the groups to describe" },
{ "name": "IncludeAuthorizedOperations", "type": "bool", "versions": "0+",
"about": "Whether to include authorized operations." }
]
} |
Required ACL
DESCRIBE on the group resource
- DESCRIBE on all topics used in the group's topologyRead Group
Request Validation
INVALID_REQUEST is returned should the request not obey the schema definition.
INVALID_GROUP_ID is returned should the group ID be empty.
...
Checks whether the group ids exists. If it does not,
GROUP_ID_NOT_FOUNDis returned. Similarly, it is returned if the group ID is associated with a group type that is notstreams.Looks up the groups and returns the response.
Response Schema
| Code Block | ||||
|---|---|---|---|---|
| ||||
{
"apiKey": TBD,
"type": "response",
"name": "StreamsGroupDescribeResponse",
"validVersions": "0",
"flexibleVersions": "0+",
// Supported errors:
// - GROUP_AUTHORIZATION_FAILED (version 0+)
// - NOT_COORDINATOR (version 0+)
// - COORDINATOR_NOT_AVAILABLE (version 0+)
// - COORDINATOR_LOAD_IN_PROGRESS (version 0+)
// - INVALID_REQUEST (version 0+)
// - INVALID_GROUP_ID (version 0+)
// - GROUP_ID_NOT_FOUND (version 0+)
"fields": [
{ "name": "ThrottleTimeMs", "type": "int32", "versions": "0+",
"about": "The duration in milliseconds for which the request was throttled due to a quota violation, or zero if the request did not violate any quota." },
{ "name": "Groups", "type": "[]DescribedGroup", "versions": "0+",
"about": "Each described group.",
"fields": [
{ "name": "ErrorCode", "type": "int16", "versions": "0+",
"about": "The describe error, or 0 if there was no error." },
{ "name": "ErrorMessage", "type": "string", "versions": "0+", "nullableVersions": "0+", "default": "null",
"about": "The top-level error message, or null if there was no error." },
{ "name": "GroupId", "type": "string", "versions": "0+", "entityType": "groupId",
"about": "The group ID string." },
{ "name": "GroupState", "type": "string", "versions": "0+",
"about": "The group state string, or the empty string." },
{ "name": "GroupEpoch", "type": "int32", "versions": "0+",
"about": "The group epoch." },
{ "name": "AssignmentEpoch", "type": "int32", "versions": "0+",
"about": "The assignment epoch." },
{ "name": "Topology", "type": "Topology", "versions": "0+",
"about"nullableVersions": "The0+", "default": "null",
"about": "The topology metadata currently initialized for the streams application. Can be null in case of a describe error.",
"fields": [
{ "name": "Epoch", "type": "int32", "versions": "0+",
"about": "The epoch of the currently initialized topology for this group." },
{ "name": "Subtopologies", "type": "[]Subtopology", "versions": "0+", "nullableVersions": "0+", "default": "null",
"about": "The subtopologies of the streams application. This contains the configured subtopologies, where the number of partitions are set and any regular expressions are resolved to actual topics. Null if the group is uninitialized, source topics are missing or incorrectly inconsistentpartitioned.",
"fields": [
{ "name": "SubtopologyId", "type": "string", "versions": "0+",
"about": "String to uniquely identify the subtopology." },
{ "name": "SourceTopics", "type": "[]string", "versions": "0+",
"about": "The topics the subtopology reads from." },
{ "name": "RepartitionSinkTopics", "type": "[]string", "versions": "0+",
"about": "The repartition topics the subtopology writes to." },
{ "name": "StateChangelogTopics", "type": "[]TopicInfo", "versions": "0+",
"about": "The set of state changelog topics associated with this subtopology. Created automatically." },
{ "name": "RepartitionSourceTopics", "type": "[]TopicInfo", "versions": "0+",
"about": "The set of source topics that are internally created repartition topics. Created automatically." }
]}
]},
{ "name": "Members", "type": "[]Member", "versions": "0+",
"about": "The members.",
"fields": [
{ "name": "MemberId", "type": "string", "versions": "0+",
"about": "The member ID." },
{ "name": "MemberEpoch", "type": "int32", "versions": "0+",
"about": "The member epoch." },
{ "name": "InstanceId", "type": "string", "versions": "0+", "nullableVersions": "0+", "default": "null",
"about": "The member instance ID for static membership." },
{ "name": "RackId", "type": "string", "versions": "0+", "nullableVersions": "0+", "default": "null",
"about": "The rack ID." },
{ "name": "ClientId", "type": "string", "versions": "0+",
"about": "The client ID." },
{ "name": "ClientHost", "type": "string", "versions": "0+",
"about": "The client host." },
{ "name": "TopologyEpoch", "type": "int32", "versions": "0+",
"about": "The epoch of the topology on the client." },
{ "name": "ProcessId", "type": "string", "versions": "0+",
"about": "Identity of the streams instance that may have multiple clients. " },
{ "name": "UserEndpoint", "type": "Endpoint", "versions": "0+", "nullableVersions": "0+", "default": "null",
"about": "User-defined endpoint for Interactive Queries. Null if not defined for this client." },
{ "name": "ClientTags", "type": "[]KeyValue", "versions": "0+",
"about": "Used for rack-aware assignment algorithm." },
{ "name": "TaskOffsets", "type": "[]TaskOffset", "versions": "0+",
"about": "Cumulative changelog offsets for tasks." },
{ "name": "TaskEndOffsets", "type": "[]TaskOffset", "versions": "0+",
"about": "Cumulative changelog end offsets for tasks." },
{ "name": "Assignment", "type": "Assignment", "versions": "0+",
"about": "The current assignment." },
{ "name": "TargetAssignment", "type": "Assignment", "versions": "0+",
"about": "The target assignment." },
]},
{ "name": "AuthorizedOperationsIsClassic", "type": "int32bool", "versions": "0+", "default": "-2147483648",
"about": "32-bit bitfield to represent authorized operations for this groupTrue for classic members that have not been upgraded yet." }
]},
}
],
{ "commonStructsname": [
{ "name"AuthorizedOperations", "type": "TaskOffsetint32", "versions": "0+", "fieldsdefault": ["-2147483648",
{ "nameabout": "SubtopologyId", "type32-bit bitfield to represent authorized operations for this group." }
]
}
],
"commonStructs": [
{ "name": "stringEndpoint", "versions": "0+",
"aboutfields": "The subtopology identifier." },[
{ "name": "PartitionHost", "type": "int32string", "versions": "0+",
"about": "The partition.host of the endpoint" },
{ "name": "OffsetPort", "type": "int64uint16", "versions": "0+",
"about": "The offset.port of the endpoint" }
]},
{ "name": "TopicPartitionsTaskOffset", "versions": "0+", "fields": [
{ "name": "TopicIdSubtopologyId", "type": "uuidstring", "versions": "0+",
"about": "The topicsubtopology IDidentifier." },
{ "name": "TopicNamePartition", "type": "stringint32", "versions": "0+", "entityType": "topicName",
"about": "The topic namepartition." },
{ "name": "PartitionsOffset", "type": "[]int32int64", "versions": "0+",
"about": "The partitionsoffset." }
]},
{ "name": "AssignmentTopicPartitions", "versions": "0+", "fields": [
{ "name": "ActiveTasksTopicId", "type": "[]TaskIdsuuid", "versions": "0+",
"about": "ActiveThe tasks for this clienttopic ID." },
{ "name": "StandbyTasksTopicName", "type": "[]TaskIdsstring", "versions": "0+", "entityType": "topicName",
"about": "StandbyThe tasks for this clienttopic name." },
{ "name": "WarmupTasksPartitions", "type": "[]TaskIdsint32", "versions": "0+",
"about": "Warm-up tasks for this client. The partitions." }
]},
{ "name": "TaskIdsAssignment", "versions": "0+", "fields": [
{ "name": "SubtopologyIdActiveTasks", "type": "string[]TaskIds", "versions": "0+",
"about": "The subtopology identifierActive tasks for this client." },
{ "name": "PartitionsStandbyTasks", "type": "[]int32TaskIds", "versions": "0+",
"about": "The partitions of the input topics processed by this member.Standby tasks for this client." },
{ "name": "WarmupTasks", "type": "[]TaskIds", "versions": "0+",
"about": "Warm-up tasks for this client. " }
]},
{ "name": "KeyValueTaskIds", "versions": "0+", "fields": [
{ "name": "KeySubtopologyId", "type": "string", "versions": "0+",
"about": "keyThe of the configsubtopology identifier." },
{ "name": "ValuePartitions", "type": "string[]int32", "versions": "0+",
"about": "valueThe partitions of the config"input }
topics processed by this ]},member." }
]},
{ "name": "KeyValue", "versions": "0+", "fields": [
{ "name": "Key", "type": "string", "versions": "0+",
"about": "key of the config" },
{ "name": "Value", "type": "string", "versions": "0+",
"about": "value of the config" }
]},
{ "name": "TopicInfo", "versions": "0+", "fields": [
{ "name": "Name", "type": "string", "versions": "0+",
"about": "The name of the topic." },
{ "name": "Partitions", "type": "int32", "versions": "0+",
"about": "The number of partitions in the topic. Can be 0 if no specific number of partitions is enforced. Always 0 for changelog topics." },
{ "name": "TopicConfigsReplicationFactor", "type": "[]KeyValueint16", "versions": "0+",
"about": "Topic-level configurations as key-value pairs."
}
]}
The replication factor of the topic. Can be 0 if the default replication factor should be used." },
{ "name": "TopicConfigs", "type": "[]KeyValue", "versions": "0+",
"about": "Topic-level configurations as key-value pairs."
}
]}
]
} |
Response Handling
Nothing particular.
...
- The member metadata record, keyed by the group ID and the member ID, stores all relevant metadata that is sent by a member to the coordinator in a heartbeat request. A notable exception are task changelog offsets and task changelog end offsets, which are not persisted, as they are constantly changing.
- The group metadata, keyed by the group ID, contains the group epoch.
- The group epoch
- A hash of the topology metadata
- The epoch of the last validated topology
- The last configuration used by the assignor
The records evolve in the following way:
...
| Code Block | ||||
|---|---|---|---|---|
| ||||
{
"type": "data",
"name": "StreamsGroupMemberMetadataValue",
"validVersions": "0",
"flexibleVersions": "0+",
"fields": [
{ "name": "InstanceId", "versions": "0+", "nullableVersions": "0+", "type": "string",
"about": "The (optional) instance ID for static membership." },
{ "name": "RackId", "versions": "0+", "nullableVersions": "0+", "type": "string",
"about": "The (optional) rack id." },
{ "name": "ClientId", "versions": "0+", "type": "string",
"about": "The client id." },
{ "name": "ClientHost", "versions": "0+", "type": "string",
"about": "The client host." },
{ "name": "RebalanceTimeoutMs", "type": "int32", "versions": "0+", "default": -1,
"about": "The rebalance timeout." },
{ "name": "TopologyEpoch", "type": "int32", "versions": "0+",
"about": "The epoch of the topology. Must be non-zero." },
{ "name": "ProcessId", "type": "string", "versions": "0+",
"about": "Identity of the streams instance that may have multiple consumers." },
{ "name": "UserEndpoint", "type": "Endpoint", "versions": "0+",
"nullableVersions": "0+", "default": "null",
"about": "User-defined endpoint for running interactive queries on this instance." },
{ "name": "ClientTags", "type": "[]KeyValue", "versions": "0+",
"about": "Used for rack-aware assignment algorithm." }
],
"commonStructs": [
{ "name": "Endpoint", "versions": "0+", "fields": [
{ "name": "Host", "type": "string", "versions": "0+",
"about": "host of the endpoint" },
{ "name": "Port", "type": "uint16", "versions": "0+",
"about": "port of the endpoint" }
]},
{ "name": "KeyValue", "versions": "0+",
"fields": [
{ "name": "Key", "type": "string", "versions": "0+",
"about": "key of the config" },
{ "name": "Value", "type": "string", "versions": "0+",
"about": "value of the config" }
]
}
]
} |
...
| Code Block | ||||
|---|---|---|---|---|
| ||||
{
"type": "data",
"name": "StreamsGroupMetadataKey",
"validVersions": TBD,
"flexibleVersions": "none",
"fields": [
{ "name": "GroupId", "type": "string", "versions": TBD,
"about": "The group id." }
]
} |
StreamsGroupMetadataValue
...
| Code Block | ||||
|---|---|---|---|---|
| ||||
{
"type": "data",
"name": "StreamsGroupMetadataValue",
"validVersions": "0",
"flexibleVersions": "0+",
"fields": [
{ "name": "Epoch", "versions": "0+", "type": "int32",
"about": "The group epoch." },
]
} |
Group Topology Metadata
The topology for the group, and the metadata for input topic partitions consumed in the topology, are persisted in two records.
- The partition metadata record, keyed by the group ID, contains metadata of all topic partitions consumed by the current topology
- The topology record, keyed by the group ID, stores the topology metadata sent in the heartbeat request when members join.
The records are evolved in the following way
- When the group coordinator receives valid topology metadata in a heartbeat request, both records are created, using the topology sent in the request and the topic metadata currently known to the group coordinator.
- When the group coordinator detects that the partition metadata for one of the input partitions used in the topology changed (by comparing the previous partition metadata record to the currently known topic metadata in the broker) during the handling of a group heartbeat, the stream group partition metadata record is updated, and a new assignment is computed.
When the group lost all members and offsets.retention.minutes expires, tombstones is written to remove the records.
StreamsGroupPartitionMetadataKey
| Code Block | ||||
|---|---|---|---|---|
| ||||
{ "type": "data", "name": "StreamsGroupPartitionMetadataKey", "validVersions": TBD, "flexibleVersions": "none", "fields": [ { "name": "GroupId", "type": "string", "versions": TBD, "about": "The group id{ "name": "MetadataHash", "versions": "0+", "type": "int64", "about": "The hash of all topics in the group." }, { "name": "ValidatedTopologyEpoch", "versions": "0+", "taggedVersions": "0+", "tag": 0, "default": -1, "type": "int32", "about": "The topology epoch whose topics are validated to be present in a valid configuration in the metadata." }, { "name": "LastAssignmentConfigs","taggedVersions": "0+", "nullableVersions": "0+","tag": 1, "default": null, "type": "[]LastAssignmentConfig", "about": "The last used configuration parameters as key-value pairs." } ] } |
StreamsGroupPartitionMetadataValue
| Code Block | ||||
|---|---|---|---|---|
| ||||
{ "type": "data", "name": "StreamsGroupPartitionMetadataValue", "validVersions": "0", "flexibleVersions": "0+", "fields": , "commonStructs": [ { "name": "TopicsLastAssignmentConfig", "versions": "0+", "type": "[]TopicMetadata", "about": "The list of topic metadata.", "fields": [ { "name": "TopicIdKey", "versionstype": "0+string", "typeversions": "uuid0+", "about": "TheKey of topicthe idconfig." }, { "name": "TopicNameValue", "versions": "0+", "type": "string", "about": "The topic name." }, { "name": "NumPartitions", "versions": "0+", "type": "int32", "about": "The number of partitionsValue of the topicconfig." }, { "name": "PartitionMetadata", "versions": "0+", "type": "[]PartitionMetadata", "about": "Partitions mapped to a set of racks. If the rack information is unavailable for all the partitions, an empty list is stored", "fields": [ { "name": "Partition", "versions": "0+", "type": "int32", "about": "The partition number." }, ]} ] } |
Group Topology Metadata
The topology for the group, and the metadata for input topic partitions consumed in the topology, are persisted in two records.
- The partition metadata record, keyed by the group ID, contains metadata of all topic partitions consumed by the current topology
- The topology record, keyed by the group ID, stores the topology metadata sent in the heartbeat request when members join.
The records are evolved in the following way
- When the group coordinator receives valid topology metadata in a heartbeat request, both records are created, using the topology sent in the request and the topic metadata currently known to the group coordinator.
- When the group coordinator detects that the partition metadata for one of the input partitions used in the topology changed (by comparing the previous partition metadata record to the currently known topic metadata in the broker) during the handling of a group heartbeat, the stream group partition metadata record is updated, and a new assignment is computed.
When the group lost all members and offsets.retention.minutes expires, tombstones is written to remove the records.
StreamsGroupPartitionMetadataKey
| Code Block | ||||
|---|---|---|---|---|
| ||||
{ "type": "data", "name": "StreamsGroupPartitionMetadataKey", "validVersions": TBD, "flexibleVersions": "none", "fields": [ { "name": "RacksGroupId", "versionstype": "0+string", "typeversions": "[]string"TBD, "about": "The set of racks that the partition is mapped to." } ]} ]group id." } ] } |
...
StreamsGroupPartitionMetadataValue
| Code Block | ||||
|---|---|---|---|---|
| ||||
{
"type": "data",
"name": "StreamsGroupTopologyKeyStreamsGroupPartitionMetadataValue",
"validVersions": TBD"0",
"flexibleVersions": "none0+",
"fields": [
{ "name": "GroupIdTopics", "typeversions": "string0+", "versionstype": TBD"[]TopicMetadata",
"about": "The group idlist of topic metadata." }
]
} |
StreamsGroupTopologyValue
| Code Block | ||||
|---|---|---|---|---|
| ||||
{ "type, "fields": [ { "name": "dataTopicId", "nameversions": "StreamsGroupTopologyValue0+", "validVersionstype": "0uuid", "flexibleVersionsabout": "0+"The topic id." }, "fields": [ { "name": "EpochTopicName", "typeversions": "int320+", "versionstype": "0+string", "about": "The epoch of the topology. Must be non-zero. topic name." }, { "name": "SubtopologiesNumPartitions", "typeversions": "[]Subtopology0+", "versionstype": "0+int32", "about": "The sub-topologies number of partitions of the streams applicationtopic.", "fields": [ }, { "name": "SubtopologyIdPartitionMetadata", "typeversions": "string0+", "versionstype": "0+[]PartitionMetadata", "about": "StringPartitions mapped to uniquelya identifyset theof subtopologyracks." }, If the rack information is unavailable for all { "name": "SourceTopics", "type": "[]string", "versions": "0+", "about": "The topics the topology reads from." }, the partitions, an empty list is stored", "fields": [ { "name": "SourceTopicRegexPartition", "typeversions": "[]string0+", "versionstype": "0+int32", "about": "RegularThe expressions identifying topics the subtopology reads frompartition number." }, { "name": "StateChangelogTopicsRacks", "typeversions": "[]TopicInfo0+", "versionstype": "0+[]string", "about": "The set of stateracks changelogthat topicsthe associatedpartition withis thismapped subtopologyto." }, ]} { "name" ]} ] } |
StreamsGroupTopologyKey
| Code Block | ||||
|---|---|---|---|---|
| ||||
{ : "RepartitionSinkTopics", "type": "[]stringdata", "versionsname": "0+StreamsGroupTopologyKey", "validVersions": TBD, "aboutflexibleVersions": "The repartition topics the subtopology writes to." }none", "fields": [ { "name": "RepartitionSourceTopicsGroupId", "type": "[]TopicInfostring", "versions": "0+"TBD, "about": "The group id." } ] } |
StreamsGroupTopologyValue
| Code Block | ||||
|---|---|---|---|---|
| ||||
{ "type": "data", "name": "StreamsGroupTopologyValue", "validVersions": "0", "flexibleVersions": "0+", "fields": [ set of source topics that are internally created repartition topics." }, { "name": "CopartitionGroupsEpoch", "type": "[]CopartitionGroupint32", "versions": "0+", "about": "AThe subsetepoch of sourcethe topicstopology. that must be copartitioned."" }, { "name": "Subtopologies", "type": "[]Subtopology", "versions": "0+", "fieldsabout": [ "The sub-topologies of the streams application.", "fields": [ { "name": "SourceTopicsSubtopologyId", "type": "[]int16string", "versions": "0+", "about": "String to uniquely "aboutidentify the subtopology." }, { "name": "SourceTopics", "type": "[]string", "versions": "The topics the topology reads from. Index into the array on the subtopology level0+", "about": "The topics the topology reads from." }, { "name": "SourceTopicRegex", "type": "[]int16string", "versions": "0+", "about": "Regular expressions identifying topics the subtopology reads from. Index into the array on the subtopology level." }, { "name": "RepartitionSourceTopicsStateChangelogTopics", "type": "[]int16TopicInfo", "versions": "0+", "about": "The set of state sourcechangelog topics thatassociated arewith internally created repartition topics. Index into the array on the subtopology levelthis subtopology." }, { ] }"name": "RepartitionSinkTopics", "type": "[]string", "versions": "0+", ] } ], "commonStructsabout": [ "The repartition topics the { "name": "TopicConfig", "versions": "0+", "fields": [ subtopology writes to." }, { "name": "keyRepartitionSourceTopics", "type": "string[]TopicInfo", "versions": "0+", "about": "The keyset of the topic-level configuration source topics that are internally created repartition topics." }, { "name": "valueCopartitionGroups", "type": "string[]CopartitionGroup", "versions": "0+", "about": "TheA valuesubset of the topic-level configuration," } source topics that must be copartitioned.", "fields": [ ] }, { "name": "TopicInfoSourceTopics", "versionstype": "0+[]int16", "fieldsversions": ["0+", { "name": "Name", "type": "string", "versions "about": "0+", The topics the topology reads from. Index into "about": "The name of the topicthe array on the subtopology level." }, { "name": "PartitionsSourceTopicRegex", "type": "int32[]int16", "versions": "0+", "about": "TheRegular numberexpressions ofidentifying partitionstopics in the topic.subtopology Canreads befrom. 0Index ifinto nothe specificarray numberon ofthe partitionssubtopology is enforced. Always 0 for changelog topics." }, level." }, { "name": "ReplicationFactorRepartitionSourceTopics", "type": "[]int16", "versions": "0+", "about": "The replication factor of the topic. Can be 0 if the default replication factor should be usedset of source topics that are internally created repartition topics. Index into the array on the subtopology level." }, { "name": "TopicConfigs", "type": "[]TopicConfig", "versions": "0+", ] } "about": "Topic-level configurations as key-value pairs." ] } ]} ] } |
Current Member Assignment
...
, |
...
StreamsGroupCurrentMemberAssignmentKey
| Code Block | ||||
|---|---|---|---|---|
| ||||
{ "typecommonStructs": "data", [ { "name": "StreamsGroupCurrentMemberAssignmentKeyTopicConfig", "validVersionsversions": TBD, "flexibleVersions": "none"0+", "fields": [ { "name": "GroupIdkey", "type": "string", "versions": TBD"0+", "about": "The group idkey of the topic-level configuration." }, { "name": "MemberIdvalue", "type": "string", "versions": TBD"0+", "about": "The member id.value of the topic-level configuration," } ] } |
StreamsGroupCurrentMemberAssignmentValue
| Code Block | ||||
|---|---|---|---|---|
| ||||
{ "type": "data" }, "name": "StreamsGroupCurrentMemberAssignmentValue", { "validVersionsname": "0TopicInfo", "flexibleVersionsversions": "0+", "fields": [ { "name": "MemberEpochName", "versionstype": "0+string", "typeversions": "int320+", "about": "The currentname member epoch that is expected from the member in the heartbeat requestof the topic." }, { "name": "PreviousMemberEpochPartitions", "versionstype": "0+int32", "typeversions": "int320+", "about": "IfThe number of partitions in the lasttopic. epochCan bumpbe is0 lostif beforeno reachingspecific thenumber member,of thepartitions memberis willenforced. retryAlways with0 thefor previouschangelog epochtopics." }, { "name": "StateReplicationFactor", "versionstype": "0+int16", "typeversions": "int80+", "about": "The memberreplication state.factor See StreamsGroupMember.MemberState for of the possible valuestopic." }, Can be 0 if { "name": "ActiveTasks", "versions": "0+", "type": "[]TaskIds", "about": "Currently assigned active tasks for this streams clientthe default replication factor should be used." }, { "name": "StandbyTasksTopicConfigs", "versions": "0+", "type": "[]TaskIdsTopicConfig", "about": "Currently assigned standby tasks for this streams client." }, { "name": "WarmupTasks", "versions": "0+", "type": "[]TaskIds", "about": "Currently assigned warm-up tasks for this streams client." },Topic-level configurations as key-value pairs." { "name": "ActiveTasksPendingRevocation", "versions": "0+", "type": "[]TaskIds", "about": "The active tasks that must be revoked by this member." }, { } ]} ] } |
Current Member Assignment
For each member, there is a record to store the current member assignment. The record is first created when a member joins (with an empty assignment). Every time an assignment is computed for the member during reconciliation, it is compared to the previous assignment for the member. If the assignment changed, a new version of the current member assignment record is appended to the consumer offset topic. When the member leaves the group, a tombstone is written to remove the record.
Together with the assignment, we track the epoch at which an active task was assigned. This helps with offset commit validation: We allow offset commits for partitions that belong to tasks in all epochs since the assignment epoch of the task.
StreamsGroupCurrentMemberAssignmentKey
| Code Block | ||||
|---|---|---|---|---|
| ||||
{ "type": "data", "name": "StandbyTasksPendingRevocationStreamsGroupCurrentMemberAssignmentKey", "versionsvalidVersions": "0+"TBD, "typeflexibleVersions": "[]TaskIdsnone", "fields": [ { "name": "GroupId", "abouttype": "The standby tasks that must be revoked by this memberstring", "versions": TBD, "about": "The group id." }, { "name": "WarmupTasksPendingRevocationMemberId", "versionstype": "0+string", "typeversions": "[]TaskIds"TBD, "about": "The warmup tasks that must be revoked by this membermember id." } ] } |
StreamsGroupCurrentMemberAssignmentValue
| Code Block | ||||
|---|---|---|---|---|
| ||||
{, "commonStructstype": ["data", "name": "StreamsGroupCurrentMemberAssignmentValue", { "namevalidVersions": "TaskIds0", "versionsflexibleVersions": "0+", "fields": [ { "name": "SubtopologyIdMemberEpoch", "typeversions": "string0+", "versionstype": "0+int32", "about": "The subtopology identifier current member epoch that is expected from the member in the heartbeat request." }, { "name": "PartitionsPreviousMemberEpoch", "typeversions": "[]int320+", "versionstype": "0+int32", "about": "TheIf the partitionslast ofepoch thebump inputis topicslost processedbefore byreaching thisthe member." } ]} ] } |
Streams Group Target Assignment
The target assignment is stored in N + 1 records, where N is the number of members in the group. When a new target assignment is computed, the group coordinator will compare it with the current target assignment and only write the difference between the two assignments to the __consumer_offsets partition. That also means if a member left the group, a corresponding tombstone record is written. The assignment must be atomic, so the group coordinator will ensure that all the records are written in a single batch, limiting the size to the maximum batch size (default 1MB), as in consumer groups.
StreamsGroupTargetAssignmentMemberKey
| Code Block | ||||
|---|---|---|---|---|
| ||||
{ "type": "data", , the member will retry with the previous epoch." }, { "name": "StreamsGroupTargetAssignmentMemberKeyState", "validVersionsversions": TBD, "0+", "flexibleVersionstype": "noneint8", "fields": [ { "nameabout": "GroupId", "type": "string", "versions": TBD, "about": "The group idThe member state. See StreamsGroupMember.MemberState for the possible values." }, { "name": "MemberIdActiveTasks", "typeversions": "string0+", "versionstype": TBD"[]TaskIds", "about": "TheCurrently memberassigned id." } ] } |
StreamsGroupTargetAssignmentMemberValue
| Code Block | ||||
|---|---|---|---|---|
| ||||
{ "type": "data", "name": "StreamsGroupTargetAssignmentMemberValue", "validVersions": "0", "flexibleVersions": "0+", "fields": [ active tasks for this streams client." }, { "name": "ActiveTasksStandbyTasks", "versions": "0+", "type": "[]TaskIds", "about": "Currently assigned activestandby tasks for this streams client." }, { "name": "StandbyTasksWarmupTasks", "versions": "0+", "type": "[]TaskIds", "about": "Currently assigned standbywarm-up tasks for this streams client." }, { "name": "WarmupTasksActiveTasksPendingRevocation", "versions": "0+", "type": "[]TaskIds", "about": "Currently assigned warm-up tasks forThe active tasks that must be revoked by this streams clientmember." } ], "commonStructs": [ { "name": "TaskIdsStandbyTasksPendingRevocation", "versions": "0+", "fieldstype": "[]TaskIds", { "nameabout": "SubtopologyId", "type": "string", "versions": "0+", "about": "The subtopology identifierThe standby tasks that must be revoked by this member." }, { "name": "PartitionsWarmupTasksPendingRevocation", "typeversions": "[]int320+", "versionstype": "0+[]TaskIds", "about": "The partitionswarmup oftasks thethat inputmust topicsbe processedrevoked by this member." } ]}, ] } |
StreamsGroupTargetAssignmentMetadataKey
| Code Block | ||||
|---|---|---|---|---|
| ||||
{ "type"commonStructs": "data",[ { "name": "StreamsGroupTargetAssignmentMetadataKeyTaskIds", "validVersions": TBD, "flexibleVersions""versions": "none0+", "fields": [ { "name": "GroupIdSubtopologyId", "type": "string", "versions": TBD"0+", "about": "The groupsubtopology ididentifier." }, ] } |
StreamsGroupTargetAssignmentMetadataValue
| Code Block | ||||
|---|---|---|---|---|
| ||||
{ "type": "data", { "name": "StreamsGroupTargetAssignmentMetadataValuePartitions", "validVersionstype": "0[]int32", "flexibleVersionsversions": "0+", "fields": [ { "nameabout": "AssignmentEpoch", "versions": "The partitions of the input topics processed by this member." }, { "name": "AssignmentEpochs", "versions": "0+", "nullableVersions": "0+", "taggedVersions": "0+", "tag": 0, "type": "[]int32", "default": null, "about": "The epoch at which any partition was assigned to the member. Used to fence zombie commits requests. Of the same length as partitions. If null, all assignment epochs are considered to be equal to the member epoch." } ]} ] } |
Broker Metrics
The existing group metrics are extended to differentiate between streams groups and consumer groups and account for streams group states.
Number of groups based on type of the protocol, where the list of protocols is extended by the
protocol=streamsvariation.
kafka.server:type=group-coordinator-metrics,name=group-count,protocol={consumer|classic|streams}
Number of streams groups based on state
kafka.server:type=group-coordinator-metrics,name=streams-group-count,state={empty|not_ready|assigning|reconciling|stable|dead}Streams group rebalances sensor
kafka.server:type=group-coordinator-metrics,name=streams-group-rebalance-rate
kafka.server:type=group-coordinator-metrics,name=streams-group-rebalance-count
Broker Configurations
The new group protocol would be guarded by enabling a new version of the group.version feature flag on the broker side.
Updated properties
Configuration | Description | Values |
|---|---|---|
| The list of enabled rebalance protocols. |
This will be added to the default value of this configuration property once this feature is complete. |
New properties
Name | Type | Default | Doc |
|---|---|---|---|
group.streams.session.timeout.ms | int | 45s | The timeout to detect client failures when using the streams group protocol. |
group.streams.min.session.timeout.ms | int | 45s | The minimum session timeout. |
group.streams.max.session.timeout.ms | int | 60s | The maximum session timeout. |
group.streams.heartbeat.interval.ms | int | 5s | The heartbeat interval given to the members. |
group.streams.min.heartbeat.interval.ms | int | 5s | The minimum heartbeat interval. |
group.streams.max.heartbeat.interval.ms | int | 15s | The maximum heartbeat interval. |
group.streams.max.size | int | MaxValue | The maximum number of streams clients that a single streams group can accommodate. |
group.streams.acceptable.recovery.lag | long | 10’000 | The maximum acceptable lag (number of offsets to catch up) for a client to be considered caught-up enough to receive an active task assignment. |
group.streams.num.warmup.replicas | int | 2 | The maximum number of warmup replicas. |
group.streams.max.warmup.replicas | int | 20 | Maximum for dynamic configurations of the warmup replica configuration |
group.streams.num.standby.replicas | int | 0 | The number of standby replicas for each task. |
group.streams.max.standby.replicas | int | 2 | Maximum for dynamic configurations of the standby replica configuration |
group.streams.task.offset.interval.ms | int | 60s | The interval in which the task changelog offsets on a client are updated on the broker. The offsets are sent with the next heartbeat after this time has passed. |
group.streams.min.task.offset.interval.ms | int | 15s | Minimum for dynamic configurations of the task offset interval. Used to restrict users of the cluster from sending the task changelog offsets too often. |
group.streams.assignor.name | string | null | The name of the task assignor used for all streams groups. Can be |
Group Configurations
We will add new configurations for the resource type GROUP in DescribeConfigs and IncrementalAlterConfigs to override the default broker configurations dynamically for specific groups.
Name | Type | Default | Doc |
|---|---|---|---|
group.streams.session.timeout.ms | int | 45s | The timeout to detect client failures when using the streams group protocol. |
group.streams.heartbeat.interval.ms | int | 5s | The heartbeat interval given to the members. |
group.streams.acceptable.recovery.lag | long | 10’000 | The maximum acceptable lag (number of offsets to catch up) for a client to be considered caught-up enough to receive an active task assignment. |
group.streams.num.warmup.replicas | int | 2 | The maximum number of warmup replicas. |
group.streams.num.standby.replicas | int | 0 | The number of standby replicas for each task. |
group.streams.task.offset.interval.ms | int | 60s | The interval in which the task changelog offsets on a client are updated on the broker. The offsets are sent with the next heartbeat after this time has passed. |
group.streams.assignor.name | string | null | The name of the task assignor used for this streams groups. Can be |
Streams API
In a future major version, when the classic group protocol will be deprecated, the interfaces introduced in KIP-924 would be deprecated, unless an integration with this KIP is proposed in a follow-up KIP.
Streams Configurations
New configurations
Name | Type | Default | Doc |
|---|---|---|---|
group.protocol | enum | classic | A flag which indicates if the new protocol should be used or not. It could be: classic or streams |
topology.epoch | int | 0 | The epoch of the topology for the streams group. Ignored if |
Deprecations
In a future major version, when the classic group protocol will be deprecated, the following configuration options will be deprecated:
acceptable.recovery.lag
max.warmup.replicas
num.standby.replicas
probing.rebalance.interval.ms
rack.aware.assignment.tags
rack.aware.assignment.strategy
rack.aware.assignment.traffic_cost
rack.aware.assignment.non_overlap_cost
task.assignor.class
Note that both the rack-aware task assignor and customizable client-side task assignment may be introduced into the new protocol in follow-up KIPs (see Future Work section). In this case, the latter 5 configuration options would not be deprecated in the future major version.
Admin API
Add the following methods to the org.apache.kafka.client.admin.AdminClient interface, mostly backed by the same implementations as the consumer group API.
...
Method signature
...
Description
...
RPC used
...
Streams Group Target Assignment
The target assignment is stored in N + 1 records, where N is the number of members in the group. When a new target assignment is computed, the group coordinator will compare it with the current target assignment and only write the difference between the two assignments to the __consumer_offsets partition. That also means if a member left the group, a corresponding tombstone record is written. The assignment must be atomic, so the group coordinator will ensure that all the records are written in a single batch, limiting the size to the maximum batch size (default 1MB), as in consumer groups.
StreamsGroupTargetAssignmentMemberKey
| Code Block | ||||
|---|---|---|---|---|
| ||||
{
"type": "data",
"name": "StreamsGroupTargetAssignmentMemberKey",
"validVersions": TBD,
"flexibleVersions": "none",
"fields": [
{ "name": "GroupId", "type": "string", "versions": TBD,
"about": "The group id." },
{ "name": "MemberId", "type": "string", "versions": TBD,
"about": "The member id." }
]
} |
StreamsGroupTargetAssignmentMemberValue
| Code Block | ||||
|---|---|---|---|---|
| ||||
{
"type": "data",
"name": "StreamsGroupTargetAssignmentMemberValue",
"validVersions": "0",
"flexibleVersions": "0+",
"fields": [
{ "name": "ActiveTasks", "versions": "0+", "type": "[]TaskIds",
"about": "Currently assigned active tasks for this streams client." },
{ "name": "StandbyTasks", "versions": "0+", "type": "[]TaskIds",
"about": "Currently assigned standby tasks for this streams client." },
{ "name": "WarmupTasks", "versions": "0+", "type": "[]TaskIds",
"about": "Currently assigned warm-up tasks for this streams client." }
],
"commonStructs": [
{ "name": "TaskIds", "versions": "0+", "fields": [
{ "name": "SubtopologyId", "type": "string", "versions": "0+",
"about": "The subtopology identifier." },
{ "name": "Partitions", "type": "[]int32", "versions": "0+",
"about": "The partitions of the input topics processed by this member." }
]}
]
} |
StreamsGroupTargetAssignmentMetadataKey
| Code Block | ||||
|---|---|---|---|---|
| ||||
{
"type": "data",
"name": "StreamsGroupTargetAssignmentMetadataKey",
"validVersions": TBD,
"flexibleVersions": "none",
"fields": [
{ "name": "GroupId", "type": "string", "versions": TBD,
"about": "The group id." }
]
} |
StreamsGroupTargetAssignmentMetadataValue
| Code Block | ||||
|---|---|---|---|---|
| ||||
{
"type": "data",
"name": "StreamsGroupTargetAssignmentMetadataValue",
"validVersions": "0",
"flexibleVersions": "0+",
"fields": [
{ "name": "AssignmentEpoch", "versions": "0+", "type": "int32",
"about": "The assignment epoch." }
]
} |
Broker Metrics
The existing group metrics are extended to differentiate between streams groups and consumer groups and account for streams group states.
Number of groups based on type of the protocol, where the list of protocols is extended by the
protocol=streamsvariation.
kafka.server:type=group-coordinator-metrics,name=group-count,protocol={consumer|classic|streams}
Number of streams groups based on state
kafka.server:type=group-coordinator-metrics,name=streams-group-count,state={empty|not_ready|assigning|reconciling|stable|dead}Streams group rebalances sensor
kafka.server:type=group-coordinator-metrics,name=streams-group-rebalance-rate
kafka.server:type=group-coordinator-metrics,name=streams-group-rebalance-count
Broker Configurations
The new group protocol would be guarded by enabling a new version of the group.version feature flag on the broker side.
Updated properties
Configuration | Description | Values |
|---|---|---|
| The list of enabled rebalance protocols. |
This will be added to the default value of this configuration property once this feature is complete. |
New properties
Name | Type | Default | Doc |
|---|---|---|---|
group.streams.session.timeout.ms | int | 45s | The timeout to detect client failures when using the streams group protocol. |
group.streams.min.session.timeout.ms | int | 45s | The minimum session timeout. |
group.streams.max.session.timeout.ms | int | 60s | The maximum session timeout. |
group.streams.heartbeat.interval.ms | int | 5s | The heartbeat interval given to the members. |
group.streams.min.heartbeat.interval.ms | int | 5s | The minimum heartbeat interval. |
group.streams.max.heartbeat.interval.ms | int | 15s | The maximum heartbeat interval. |
group.streams.max.size | int | MaxValue | The maximum number of streams clients that a single streams group can accommodate. |
group.streams.acceptable.recovery.lag | long | 10’000 | The maximum acceptable lag (number of offsets to catch up) for a client to be considered caught-up enough to receive an active task assignment. |
group.streams.num.warmup.replicas | int | 2 | The maximum number of warmup replicas. |
group.streams.max.warmup.replicas | int | 20 | Maximum for dynamic configurations of the warmup replica configuration |
group.streams.num.standby.replicas | int | 0 | The number of standby replicas for each task. |
group.streams.max.standby.replicas | int | 2 | Maximum for dynamic configurations of the standby replica configuration |
group.streams.task.offset.interval.ms | int | 60s | The interval in which the task changelog offsets on a client are updated on the broker. The offsets are sent with the next heartbeat after this time has passed. |
group.streams.min.task.offset.interval.ms | int | 15s | Minimum for dynamic configurations of the task offset interval. Used to restrict users of the cluster from sending the task changelog offsets too often. |
group.streams.assignor.name | string | null | The name of the task assignor used for all streams groups. Can be |
group.streams.initial.rebalance.delay.ms | int | 3000 | The first rebalance of a group is delayed by this amount to allow more members to join the group. |
group.streams.rack.aware.assignment.tags | string[] | empty list | The client tags used for rack aware standby task assignment. |
Group Configurations
We will add new configurations for the resource type GROUP in DescribeConfigs and IncrementalAlterConfigs to override the default broker configurations dynamically for specific groups.
Name | Type | Default |
|---|---|---|
streams.session.timeout.ms | int | 45s |
streams.heartbeat.interval.ms | int | 5s |
streams.acceptable.recovery.lag | long | 10’000 |
streams.num.warmup.replicas | int | 2 |
streams.num.standby.replicas | int | 0 |
streams.task.offset.interval.ms | int | 60s |
streams.assignor.name | string | null |
streams.initial.rebalance.delay.ms | int | 3000 |
streams.rack.aware.assignment.tags | string[] | empty list |
Streams API
In a future major version, when the classic group protocol will be deprecated, the interfaces introduced in KIP-924 would be deprecated, unless an integration with this KIP is proposed in a follow-up KIP.
Streams Configurations
New configurations
Name | Type | Default | Doc |
|---|---|---|---|
group.protocol | enum | classic | A flag which indicates if the new protocol should be used or not. It could be: classic or streams |
topology.epoch | int | 0 | The epoch of the topology for the streams group. Ignored if |
Deprecations
In a future major version, when the classic group protocol will be deprecated, the following configuration options will be deprecated:
acceptable.recovery.lag
max.warmup.replicas
num.standby.replicas
probing.rebalance.interval.ms
rack.aware.assignment.tags
rack.aware.assignment.strategy
rack.aware.assignment.traffic_cost
rack.aware.assignment.non_overlap_cost
task.assignor.class
Note that both the rack-aware task assignor and customizable client-side task assignment may be introduced into the new protocol in follow-up KIPs (see Future Work section). In this case, the latter 5 configuration options would not be deprecated in the future major version.
Admin API
Add the following methods to the org.apache.kafka.client.admin.AdminClient interface, mostly backed by the same implementations as the consumer group API.
Method signature | Description | RPC used |
|---|---|---|
AlterStreamsGroupOffsetsResult alterStreamsGroupOffsets(String groupId, Map<TopicPartition, Long> offsets) | Alter offset information for a streams group. | OffsetCommit |
AlterStreamsGroupOffsetsResult alterStreamsGroupOffsets(String groupId, Map<TopicPartition, Long> offsets, AlterStreamsGroupOffsetsOptions options) | Alter offset information for a streams group. | OffsetCommit |
DeleteStreamsGroupOffsetsResult deleteStreamsGroupOffsets(String groupId, Set<String> topics) | Delete offset information for a set of topics in a streams group. | OffsetDelete |
DeleteStreamsGroupOffsetsResult deleteStreamsGroupOffsets(String groupId, Set<String> topics, DeleteStreamsGroupOffsetsOptions options) | Delete offset information for a set of topics in a streams group. | OffsetDelete |
DeleteStreamsGroupResult deleteStreamsGroups(Collection<String> groupIds) | Delete streams groups from the cluster. | DeleteGroups |
DeleteStreamsGroupResult deleteStreamsGroups(Collection<String> groupIds, DeleteStreamsGroupOptions options) | Delete streams groups from the cluster. | DeleteGroups |
DescribeStreamsGroupsResult describeStreamsGroups(Collection<String> groupIds) | Describe some streams groups in the cluster. | StreamsGroupDescribe |
DescribeStreamsGroupsResult describeStreamsGroups(Collection<String> groupIds, DescribeStreamsGroupsOptions options) | Describe some streams groups in the cluster. | StreamsGroupDescribe |
ListStreamsGroupOffsetsResult listStreamsGroupOffsets(Map<String, ListStreamsGroupOffsetsSpec> groupSpecs) | List the streams group offsets available in the cluster for the specified Streams groups. | OffsetFetch |
ListStreamsGroupOffsetsResult listStreamsGroupOffsets(Map<String, ListStreamsGroupOffsetsSpec> groupSpecs, ListStreamsGroupOffsetsOptions options) | List the streams group offsets available in the cluster for the specified Streams groups. | OffsetFetch |
These correspond to existing APIs for consumer groups and some of the code will be shared. The main reason for duplicating them is the naming, as the current API uses "consumerGroup" in the name, despite the RPCs just using "group". There are some differences:
- The
describeStreamsGroupsuses the DescribeStreamsGroup RPC and contains other information than consumer groups. - A streams group has an extra state - NOT_READY, and no legacy states from the classic protocol.
removeMembersFromConsumerGroupwill not have a corresponding API in this first version, as it is using the LeaveGroup RPC for classic consumer groups, which is not available for KIP-848-style groups.
Admin
| Code Block | ||||||
|---|---|---|---|---|---|---|
|
These correspond to existing APIs for consumer groups and some of the code will be shared. The main reason for duplicating them is the naming, as the current API uses "consumerGroup" in the name, despite the RPCs just using "group". There are some differences:
- The
describeStreamsGroupsuses the DescribeStreamsGroup RPC and contains other information than consumer groups. - A streams group has an extra state - NOT_READY, and no legacy states from the classic protocol.
removeMembersFromConsumerGroupwill not have a corresponding API in this first version, as it is using the LeaveGroup RPC for classic consumer groups, which is not available for KIP-848-style groups.
Admin
| Code Block | ||||||
|---|---|---|---|---|---|---|
| ||||||
/** * Alters offsets for the specified group. In order to succeed, the group must be empty. * * <p>This is a convenience method for {@link #alterStreamsGroupOffsets(String, Map, AlterStreamsGroupOffsetsOptions)} with default options. * See the overload for more details. * * @param groupId The group for which to alter offsets. * @param offsets A map of offsets by partition. * @return The AlterStreamsGroupOffsetsResult. */ default AlterStreamsGroupOffsetsResult alterStreamsGroupOffsets(String groupId, Map<TopicPartition, Long> offsets) { return alterStreamsGroupOffsets(groupId, offsets, new AlterStreamsGroupOffsetsOptions()); } /** * Alters offsets for the specified group. In order to succeed, the group must be empty. * * <p>This operation is not transactional so it may succeed for some partitions while fail for others. * * @param groupId The group for which to alter offsets. * @param offsets A map of offsets by partition. Partitions not specified in the map are ignored. * @param options The options to use when altering the offsets. * @return The AlterStreamsGroupOffsetsResult. */ AlterStreamsGroupOffsetsResult alterStreamsGroupOffsets(String groupId, Map<TopicPartition, Long> offsets, AlterStreamsGroupOffsetsOptions options); /** * DeleteAlters offsets for a set of topics in a Streamsthe specified group. In order to succeed, the group withmust thebe default optionsempty. * * <p>This is a convenience method for {@link #deleteStreamsGroupOffsets#alterStreamsGroupOffsets(String, SetMap, DeleteStreamsGroupOffsetsOptionsAlterStreamsGroupOffsetsOptions)} with default options. * See the overload for more details. * * @param groupId The group for which to deletealter offsets. * @param topics The topics offsets A map of offsets by partition. * @return The DeleteStreamsGroupOffsetsResultAlterStreamsGroupOffsetsResult. */ default DeleteStreamsGroupOffsetsResultAlterStreamsGroupOffsetsResult deleteStreamsGroupOffsetsalterStreamsGroupOffsets(String groupId, Set<String> topicsMap<TopicPartition, Long> offsets) { return deleteStreamsGroupOffsetsalterStreamsGroupOffsets(groupId, topicsoffsets, new DeleteStreamsGroupOffsetsOptionsAlterStreamsGroupOffsetsOptions()); } /** * DeleteAlters offsets for the aspecified setgroup. ofIn topicsorder into asucceed, Streamsthe group must be empty. * * @param groupId The group for which to delete offsets <p>This operation is not transactional so it may succeed for some partitions while fail for others. * * @param topicsgroupId The topicsgroup for which to alter offsets. * @param offsets A optionsmap Theof optionsoffsets toby usepartition. whenPartitions deletingnot offsetsspecified in the amap Streamsare groupignored. * @param @returnoptions The DeleteStreamsGroupOffsetsResult. */ options to use when altering the offsets. DeleteStreamsGroupOffsetsResult deleteStreamsGroupOffsets(String groupId, * @return The AlterStreamsGroupOffsetsResult. */ Set<String> topics, AlterStreamsGroupOffsetsResult alterStreamsGroupOffsets(String groupId, Map<TopicPartition, Long> offsets, DeleteStreamsGroupOffsetsOptionsAlterStreamsGroupOffsetsOptions options); /** * Delete Streams groups from the cluster offsets for a set of topics in a Streams group with the default options. * * <p>This is a convenience method for {@link #deleteStreamsGroups(Collection<String>#deleteStreamsGroupOffsets(String, Set, DeleteStreamsGroupsOptionsDeleteStreamsGroupOffsetsOptions)} with default options. * See the overload for more details. * * @param groupIdsgroupId The IDsgroup offor the groupswhich to delete offsets. * @param topics The topics. * @return The DeleteStreamsGroupsResultDeleteStreamsGroupOffsetsResult. */ default DeleteStreamsGroupsResultDeleteStreamsGroupOffsetsResult deleteStreamsGroups(Collection<String> groupIdsdeleteStreamsGroupOffsets(String groupId, Set<String> topics) { return deleteStreamsGroups(groupIdsdeleteStreamsGroupOffsets(groupId, topics, new DeleteStreamsGroupsOptionsDeleteStreamsGroupOffsetsOptions()); } /** * Delete Streams groups from the cluster offsets for a set of topics in a Streams group. * * @param groupIdsgroupId The IDsgroup offor thewhich groups to delete offsets. * @param topics The topics. * @param options The options to use when deleting offsets in a Streams group. * @return The DeleteStreamsGroupsResultDeleteStreamsGroupOffsetsResult. */ DeleteStreamsGroupsResultDeleteStreamsGroupOffsetsResult deleteStreamsGroups(Collection<String> groupIds, DeleteStreamsGroupsOptionsdeleteStreamsGroupOffsets(String groupId, Set<String> topics, DeleteStreamsGroupOffsetsOptions options); /** * Describe someDelete Streams groups infrom the cluster, with the default options. * * <p>This is a convenience method for {@link #describeStreamsGroups#deleteStreamsGroups(CollectionCollection<String>, DescribeStreamsGroupsOptionsDeleteStreamsGroupsOptions)} * with default options. * See the overload for more details. * * @param groupIds The IDs of the groups to describedelete. * @return The DescribeStreamsGroupsResultDeleteStreamsGroupsResult. */ default DescribeStreamsGroupsResultDeleteStreamsGroupsResult describeStreamsGroupsdeleteStreamsGroups(Collection<String> groupIds) { return describeStreamsGroupsdeleteStreamsGroups(groupIds, new DescribeStreamsGroupsOptionsDeleteStreamsGroupsOptions()); } /** * DescribeDelete some Streams groups infrom the cluster. * * @param groupIds The IDs of the groups to describedelete. * @param options The options to use when deleting describinga theStreams groupsgroup. * @return The DescribeStreamsGroupsResultDeleteStreamsGroupsResult. */ DescribeStreamsGroupsResultDeleteStreamsGroupsResult describeStreamsGroupsdeleteStreamsGroups(Collection<String> groupIds, DeleteStreamsGroupsOptions options); /** * Describe some Streams groups in the cluster, with the default options. * * <p>This is a convenience method for {@link #describeStreamsGroups(Collection, DescribeStreamsGroupsOptions)} * with default options. See the overload for DescribeStreamsGroupsOptions options);more details. /** * List@param thegroupIds StreamsThe groupIDs offsets availableof in the clustergroups forto thedescribe. specified Streams groups with* the@return defaultThe optionsDescribeStreamsGroupsResult. */ * <p>This is a convenience method for {@link #listStreamsGroupOffsets(Map, ListStreamsGroupOffsetsOptions)}default DescribeStreamsGroupsResult describeStreamsGroups(Collection<String> groupIds) { return describeStreamsGroups(groupIds, new DescribeStreamsGroupsOptions()); } * to list offsets/** of all partitions for* theDescribe specifiedsome Streams groups within defaultthe optionscluster. * * @param @paramgroupIds groupSpecsThe MapIDs of Streamsthe group idsgroups to adescribe. spec that specifies the* topic@param partitionsoptions of theThe groupoptions to list offsets foruse when describing the groups. * @return The ListStreamsGroupOffsetsResultDescribeStreamsGroupsResult. */ defaultDescribeStreamsGroupsResult ListStreamsGroupOffsetsResult listStreamsGroupOffsets(Map<String, ListStreamsGroupOffsetsSpec> groupSpecs) { describeStreamsGroups(Collection<String> groupIds, return listStreamsGroupOffsets(groupSpecs, new ListStreamsGroupOffsetsOptions()); } /** * List the Streams group offsets available in the cluster for the specified Streams groups. * * @param groupSpecs Map of Streams group ids to a spec that specifies the topic partitions of the group to list offsets for. * @param options The options to use when listing the Streams group offsetsDescribeStreamsGroupsOptions options); /** * List the Streams group offsets available in the cluster for the specified Streams groups with the default options. * @return The ListStreamsGroupOffsetsResult * <p>This is a */ convenience method for ListStreamsGroupOffsetsResult{@link listStreamsGroupOffsets#listStreamsGroupOffsets(Map<StringMap, ListStreamsGroupOffsetsSpec> groupSpecs, ListStreamsGroupOffsetsOptions options);} /** * List* to list offsets of all partitions for the specified Streams groups available in the cluster with the default options. * * <p>This@param isgroupSpecs aMap convenienceof methodStreams forgroup {@link #listStreamsGroups(ListStreamsGroupsOptions)} with default options. * See the overload for more details. *ids to a spec that specifies the topic partitions of the group to list offsets for. * @return The ListStreamsGroupsResult.ListStreamsGroupOffsetsResult */ default ListStreamsGroupsResultListStreamsGroupOffsetsResult listStreamsGroups(listStreamsGroupOffsets(Map<String, ListStreamsGroupOffsetsSpec> groupSpecs) { return listStreamsGroupslistStreamsGroupOffsets(groupSpecs, new ListStreamsGroupsOptionsListStreamsGroupOffsetsOptions()); } /** * List the Streams groupsgroup offsets available in the cluster for the specified Streams groups. * * @param groupSpecs Map of Streams group ids to a spec that specifies the topic partitions of the group to list offsets for. * @param options The options to use when listing the Streams group groupsoffsets. * @return The ListStreamsGroupsResult.ListStreamsGroupOffsetsResult */ ListStreamsGroupsResultListStreamsGroupOffsetsResult listStreamsGroups(ListStreamsGroupsOptionslistStreamsGroupOffsets(Map<String, ListStreamsGroupOffsetsSpec> groupSpecs, ListStreamsGroupOffsetsOptions options); |
AlterStreamsGroupOffsetResult
...
| Code Block | ||||||
|---|---|---|---|---|---|---|
| ||||||
/**
* A detailed description of a single streams group in the cluster.
*/
public class StreamsGroupDescription {
public StreamsGroupDescription(
final String groupId,
final int groupEpoch,
final int targetAssignmentEpoch,
final int topologyEpoch,
final Collection<StreamsGroupSubtopologyDescription> subtopologies,
final Collection<StreamsGroupMemberDescription> members,
final StreamsGroupStateGroupState stategroupState,
final Node coordinator,
final Set<AclOperation> authorizedOperations
);
/**
* The id of the streams group.
*/
public String groupId();
/**
* The epoch of the currently used topology, or null if uninitialized consumer group.
*/
public int groupEpoch();
/**
* The epoch of the target assignment.
*/
public int targetAssignmentEpoch();
/**
* The epoch of the currently used topology.
*/
public Stringint topologyEpoch();
/**
* A list of the members of the streams group.
*/
public Collection<StreamsGroupMemberDescription> members();
/**
* A list of the subtopologies in the streams group.
*/
public Collection<StreamsGroupSubtopologyDescription> subtopologies();
/**
* The state of the streams group state, or UNKNOWN if the state is too new for us to parse.
*/
public StreamsGroupStateGroupState stategroupState();
/**
* The streams group coordinator, or null if the coordinator is not known.
*/
public Node coordinator();
/**
* authorizedOperations for this group, or null if that information is not known.
*/
public Set<AclOperation> authorizedOperations();
} |
...
| Code Block | ||||||
|---|---|---|---|---|---|---|
| ||||||
/**
* A detailed description of a single member in the group.
*/
public class StreamsGroupMemberDescription {
public StreamsGroupMemberDescription(
final String memberId,
final Optional<String>int instanceIdmemberEpoch,
final Stringint clientIdcurrentAssignmentEpoch,
final StringOptional<String> clientHostinstanceId,
final intOptional<String> topologyEpochrackId,
final String processIdclientId,
final Map<String, String> clientTags,
final List<TaskOffset> taskOffsets,
final List<TaskOffset> taskEndOffsets,
final StreamsGroupMemberAssignment assignmentString clientHost,
final Optional<StreamsGroupMemberAssignment> targetAssignment);
int topologyEpoch,
/**
final *String TheprocessId,
id of the group member.
final Optional<Endpoint> */userEndpoint,
public String memberId();
final Map<String, String> /**clientTags,
* The id offinal theList<TaskOffset> instancetaskOffsets, used
for static membership, if available.
final List<TaskOffset> */taskEndOffsets,
public Optional<String> instanceId();
final StreamsGroupMemberAssignment /**assignment,
* The client idfinal ofStreamsGroupMemberAssignment thetargetAssignment,
group member.
*/
final boolean isClassic
public String clientId( );
/**
* The hostid of the group member.
*/
public String clientHostmemberId();
/**
* The epoch of the topology present on the clientgroup member.
*/
public int topologyEpochmemberEpoch();
/**
* The Identityid of the streams instance, thatused mayfor havestatic multiple clients.
*/
public String processId();
/**
* Used for rack-aware assignment algorithmmembership, if available.
*/
public Map<String, String> clientTagsOptional<String> instanceId();
/**
* Cumulative offsets for tasks The rack ID of the group member.
*/
public List<TaskOffset>Optional<String> taskOffsetsrackId();
/**
* CumulativeThe taskclient changelogid endof offsetsthe forgroup tasksmember.
*/
public List<TaskOffset>String taskEndOffsetsclientId();
/**
* The current assignment host of the group member.
*/
public StreamsGroupMemberAssignmentString assignmentclientHost();
/**
* The target assignment.epoch of the group member.
*/
public Optional<StreamsGroupMemberAssignment>int targetAssignmentmemberEpoch();
/**
* The cumulativeepoch offsetof forthe onecurrent taskassignment.
*/
public static class TaskOffset {
int currentAssignmentEpoch();
/**
* The epoch of the publictopology TaskOffset(finalpresent Stringon subtopology, final int partition, final long offset);
the client.
*/
public int topologyEpoch();
/**
* Identity of the *streams Theinstance subtopologythat identifier.
may have multiple clients.
*/
public String subtopologyprocessId();
/**
* The partition of the task.
User-defined endpoint for Interactive Queries.
*/
public intOptional<Endpoint> partitionuserEndpoint();
/**
* TheUsed cumulativefor offset (sum of offsets in all input partitions)rack-aware assignment algorithm.
*/
public Map<String, public long offsetString> clientTags();
}
} |
StreamsGroupMemberAssignment
| Code Block | ||||||
|---|---|---|---|---|---|---|
| ||||||
/** * A description of* theCumulative assignmentsoffsets offor atasks. specific streams group member. */ public class StreamsGroupMemberAssignment { public List<TaskOffset> public StreamsGroupMemberAssignment( taskOffsets(); /** final* List<TaskIds>Cumulative activeTasks, task changelog end offsets for tasks. final List<TaskIds> standbyTasks,*/ public final List<TaskIds> warmupTasksList<TaskOffset> taskEndOffsets(); /** * ActiveThe tasks for this clientcurrent assignment. */ public List<TaskIds>StreamsGroupMemberAssignment activeTasksassignment(); /** * StandbyThe tasks for this clienttarget assignment. */ public List<TaskIds>StreamsGroupMemberAssignment standbyTaskstargetAssignment(); /** * Warmup tasks for this client The flag indicating whether a member is classic. */ public List<TaskIds>boolean warmupTasksisClassic(); /** * The Allcumulative tasksoffset for one subtopology of a membertask. */ public static class TaskIdsTaskOffset { public TaskIdsTaskOffset(final String subtopologysubtopologyId, final int partition, final List<Integer>long partitionsoffset); /** * The subtopology identifier. */ public String subtopologysubtopologyId(); /** * The partitionspartition of the input topics processed by this member. */task. public List<Integer> partitions(); } } |
StreamsGroupSubtopologyDescription
| Code Block | ||||||
|---|---|---|---|---|---|---|
| ||||||
/** * A detailed description of a single subtopology */ public class StreamsGroupSubtopologyDescription { public StreamsGroupSubtopologyDescription( final String subtopology, final List<String> sourceTopics, final List<String> repartitionSinkTopics, final Map<String, TopicInfo> stateChangelogTopics, */ finalpublic Map<String, TopicInfo> repartitionSourceTopicsint partition(); /** * String to uniquely identify the subtopology The cumulative offset (sum of offsets in all input partitions). */ public Stringlong subtopologyoffset(); } } |
StreamsGroupMemberAssignment
| Code Block | ||||||
|---|---|---|---|---|---|---|
| ||||||
/** * A description of *the assignments Theof topicsa thespecific topologystreams readsgroup frommember. */ public class StreamsGroupMemberAssignment */{ public List<String> sourceTopicsStreamsGroupMemberAssignment(); final List<TaskIds> /**activeTasks, * The repartitionfinal topicsList<TaskIds> thestandbyTasks, topology writes to. */ final List<TaskIds> warmupTasks public List<String> repartitionSinkTopics(); /** * TheActive set of state changelog topics associated withtasks for this sub-topologyclient. */ public Map<String, TopicInfo> stateChangelogTopicsList<TaskIds> activeTasks(); /** * TheStandby settasks offor source topics that are internally created repartition topicsthis client. */ public Map<String, TopicInfo>List<TaskIds> repartitionSourceTopicsstandbyTasks(); /** * Warmup Informationtasks aboutfor athis topicclient. */ public static class TopicInfo { public TopicInfo(final int partitions, final Map<String, String> topicConfigsList<TaskIds> warmupTasks(); /** * All tasks for one subtopology *of Thea numbermember. of partitions in the topic.*/ public static class TaskIds */{ public int TaskIds(final String subtopologyId, final List<Integer> partitions(); /** * ConfigurationsThe ofsubtopology the topicidentifier. */ public Map<String, String> topicConfigsString subtopologyId(); } } |
DescribeStreamsGroupsOptions
| Code Block | ||||||
|---|---|---|---|---|---|---|
| ||||||
package org.apache.kafka.client.admin; /** * Options for {@link Admin#describeStreamsGroups(Collection<String>, DescribeStreamsGroupsOptions)}. * * The APIpartitions of thisthe classinput istopics evolving,processed seeby {@link Admin} for details. */ @InterfaceStability.Evolving public class DescribeStreamsGroupsOptions extends AbstractOptions<DescribeStreamsGroupsOptions> { this member. public*/ DescribeStreamsGroupsOptions includeAuthorizedOperations(boolean includeAuthorizedOperations); public booleanList<Integer> includeAuthorizedOperationspartitions(); } } |
...
StreamsGroupSubtopologyDescription
| Code Block | ||||||
|---|---|---|---|---|---|---|
| ||||||
package org.apache.kafka.clients.admin; /** * A Thedetailed resultdescription of the {@link Admin#listStreamsGroupOffsets(Map<String, ListStreamsGroupOffsetsSpec>, ListStreamsGroupOffsetsOptions)} call. * <p> * The API of this class is evolving, see {@link Admin} for details. */ @InterfaceStability.Evolving public class ListStreamsGroupOffsetsResult { a single subtopology */ public class StreamsGroupSubtopologyDescription { public StreamsGroupSubtopologyDescription( final String subtopologyId, final List<String> sourceTopics, final List<String> repartitionSinkTopics, final Map<String, TopicInfo> stateChangelogTopics, final Map<String, TopicInfo> repartitionSourceTopics); /** * String to uniquely identify the subtopology. */ public String subtopologyId(); /** * ReturnThe atopics futurethe whichtopology yieldsreads allfrom. Map<String, Map<TopicPartition, Long> objects, if*/ requests for all thepublic groups succeed.List<String> sourceTopics(); /**/ public KafkaFuture<Map<String, Map<TopicPartition, Long>>> all() { * The repartition topics the topology writes to. }*/ public List<String> repartitionSinkTopics(); /** * Return a future which yields a map of topic partitions to offsets for the specified groupThe set of state changelog topics associated with this subtopology. */ public KafkaFuture<Map<TopicPartitionMap<String, Long>>TopicInfo> partitionsToOffset(String groupId) { } } |
ListStreamsGroupOffsetsOptions
| Code Block | ||||||
|---|---|---|---|---|---|---|
| ||||||
package org.apache.kafka.client.admin;
/**
* Options for {@link Admin#listStreamsGroupOffsets(Map<String, ListStreamsGroupOffsetsSpec>, ListStreamsGroupOffsetsOptions)}.
* <p>
* The API of this class is evolving, see {@link Admin} for details.
*/
@InterfaceStability.Evolving
public class ListStreamsGroupOffsetsOptions extends AbstractOptions<ListStreamsGroupOffsetsOptions> {
} |
ListStreamsGroupOffsetsSpec
| Code Block | ||||||
|---|---|---|---|---|---|---|
| ||||||
package org.apache.kafka.client.admin;
/**
* Specification of Streams group offsets to list using {@link Admin#listStreamsGroupOffsets(Map<String, ListStreamsGroupOffsetsSpec>, ListStreamsGroupOffsetsOptions)}.
* <p>
* The API of this class is evolving, see {@link Admin} for details.
*/
@InterfaceStability.Evolving
public class ListStreamsGroupOffsetsSpec {
public ListStreamsGroupOffsetsSpec();
/**
* Set the topic partitions whose offsets are to be listed for a Streams group.
*/
ListStreamsGroupOffsetsSpec topicPartitions(Collection<TopicPartition> topicPartitions);
/**
* Returns the topic partitions whose offsets are to be listed for a Streams group.
*/
Collection<TopicPartition> topicPartitions();
} |
...
stateChangelogTopics();
/**
* The set of source topics that are internally created repartition topics.
*/
public Map<String, TopicInfo> repartitionSourceTopics();
/**
* Information about a topic.
*/
public static class TopicInfo {
public TopicInfo(final int partitions, final Map<String, String> topicConfigs);
/**
* The number of partitions in the topic.
*/
public int partitions();
/**
* Configurations of the topic.
*/
public Map<String, String> topicConfigs();
}
} |
DescribeStreamsGroupsOptions
| Code Block | ||||||
|---|---|---|---|---|---|---|
| ||||||
package org.apache.kafka.clientsclient.admin; /** * The result of theOptions for {@link Admin#listStreamsGroups(ListStreamsGroupsOptionsAdmin#describeStreamsGroups(Collection<String>, DescribeStreamsGroupsOptions)} call. * <p> * The API of this class is evolving, see {@link Admin} for details. */ @InterfaceStability.Evolving public class ListStreamsGroupsResultDescribeStreamsGroupsOptions { extends AbstractOptions<DescribeStreamsGroupsOptions> /**{ public *DescribeStreamsGroupsOptions includeAuthorizedOperations(boolean includeAuthorizedOperations); public boolean includeAuthorizedOperations(); } |
ListStreamsGroupOffsetsResult
| Code Block | ||||||
|---|---|---|---|---|---|---|
| ||||||
package org.apache.kafka.clients.admin; /** * The result of the {@link Admin#listStreamsGroupOffsets(Map<String, ListStreamsGroupOffsetsSpec>, ListStreamsGroupOffsetsOptions)} call. * <p> * The API of this class is evolving, see {@link Admin} for details. */ @InterfaceStability.Evolving public class ListStreamsGroupOffsetsResultReturns a future that yields either an exception, or the full set of Streams group listings. */ public KafkaFuture<Collection<StreamsGroupListing>> all() { } /** * Returns a future which yields just the valid listings. */ public KafkaFuture<Collection<StreamsGroupListing>> valid() { } /** * ReturnsReturn a future which yields just all Map<String, Map<TopicPartition, Long> objects, if requests for all the errorsgroups which occurredsucceed. */ public KafkaFuture<Collection<Throwable>> errorsKafkaFuture<Map<String, Map<TopicPartition, Long>>> all() { } } |
StreamsGroupListing
| Code Block | ||||||
|---|---|---|---|---|---|---|
| ||||||
package org.apache.kafka.client.admin; import org.apache.kafka.common.StreamsGroupState; /** * A listing of a* StreamsReturn groupa infuture thewhich cluster. yields *a <p> map *of Thetopic APIpartitions ofto thisoffsets classfor isthe evolving, see {@link Admin} for details. specified group. */ @InterfaceStability.Evolving public class StreamsGroupListing { public KafkaFuture<Map<TopicPartition, publicLong>> StreamsGroupListingpartitionsToOffset(String groupId); { public StreamsGroupListing(String groupId, Optional<StreamsGroupState> state); } } |
ListStreamsGroupOffsetsOptions
| Code Block | ||||||
|---|---|---|---|---|---|---|
| ||||||
package org.apache.kafka.client.admin; /** * TheOptions idfor of the Streams group{@link Admin#listStreamsGroupOffsets(Map<String, ListStreamsGroupOffsetsSpec>, ListStreamsGroupOffsetsOptions)}. * <p> */ The publicAPI String groupId(); /** * The Streams group state. */ public Optional<StreamsGroupState> state(); } |
...
of this class is evolving, see {@link Admin} for details.
*/
@InterfaceStability.Evolving
public class ListStreamsGroupOffsetsOptions extends AbstractOptions<ListStreamsGroupOffsetsOptions> {
} |
ListStreamsGroupOffsetsSpec
| Code Block | ||||||
|---|---|---|---|---|---|---|
| ||||||
package org.apache.kafka.client.admin; import org.apache.kafka.common.StreamsGroupState; /** * Options for Specification of Streams group offsets to list using {@link Admin#listStreamsGroups(ListStreamsGroupsOptionsAdmin#listStreamsGroupOffsets(Map<String, ListStreamsGroupOffsetsSpec>, ListStreamsGroupOffsetsOptions)}. * <p> * The API of this class is evolving, see {@link Admin} for details. */ @InterfaceStability.Evolving public class ListStreamsGroupOffsetsSpec ListStreamsGroupsOptions{ extends AbstractOptions<ListStreamsGroupsOptions> {public ListStreamsGroupOffsetsSpec(); /** * IfSet statesthe is set, only groups in these states willtopic partitions whose offsets are to be returned.listed Otherwise,for alla groupsStreams are returnedgroup. */ public ListStreamsGroupsOptions inStates(Set<StreamsGroupState> statesListStreamsGroupOffsetsSpec topicPartitions(Collection<TopicPartition> topicPartitions); /** * ReturnReturns the listtopic ofpartitions Stateswhose thatoffsets are requestedto orbe emptylisted iffor noa states have been specifiedStreams group. */ public Set<StreamsGroupState> statesCollection<TopicPartition> topicPartitions(); } |
GroupType
Another case is added to the org.apache.kafka.common.GroupType enum:
Enum constant | Description |
|---|---|
StreamsSTREAMS("Streams") | Streams group |
StreamsGroupState
GroupState
Another case is added to theA new enum org.apache.kafka.common.StreamsGroupStateGroupState is addedenum:
Enum constant | |
|---|---|
NOT_READY | |
| |
| |
| |
|
Exceptions
The following new exception is exceptions are added to the org.apache.kafka.common.errors package, corresponding to the new error codes in the Kafka protocol.
StreamsInvalidTopology- The supplied topology is invalid. Returned if the client sends a topology that does not fulfill the expected invariants.
StreamsInvalidTopology is fatal.
Command-line tools
.
StreamsInvalidTopologyException- The supplied topology is invalid. Returned if the client sends a topology that does not fulfill the expected invariants.StreamsInvalidTopologyEpochException - The client provided a invalid topology epoch with respect to the stream group state, for example, the topology was changed by the epoch not bumped.StreamsTopologyFencedException - When a client attempts to join with an outdated topology epoch.
Command-line tools
kafka-groups.sh
We add an option --streams to the above commad-line tool, which filter the groups to show share groups. Furthermore streams becomes one of the possible values for --group-type .
kafka-streams-groups.sh
A new tool called kafka-streams-groups.sh is added for working with streams groups. It has the following options:
Option | Description |
|---|---|
--version | Display Kafka version. |
--verbose | Use with Use with Use with |
--allall-input-topics | Use with --reset-offsets or --delete-offsets. If specified, includes all input topics of the streams group, as stored by the topology metadata on the broker. |
--input-topics topic <String: topics>topic> | Use with --reset-offsets or --delete-offsets. Comma-separated list of user input Defines a user input topic to be modified. Multiple such options can be used to define multiple topics. For these topics, the tool by default will reset the offset to the earliest available offset, or delete the offsets. Reset to other offset position by appending other reset offset option, ex: --input-topics topic foo --shift-by 5. |
--internal-topics <String: topics> | Use with --delete. Comma-separated list of internal topics to delete. Must be a subset of the internal topics marked for deletion by the default behaviour (do a dry-run without this option to view these topics). |
--to-offset <Long: offset> | Reset input topic offsets to a specific offset |
--to-latest | Reset input topic offsets to latest offset. |
--to-earliest | Reset input topic offsets to earliest offset. |
--by-duration <String: duration> | Reset input topic offsets to offset by duration from current timestamp. Format: 'PnDTnHnMnS' |
--to-datetime <String: datetime> | Reset input topic offsets to offset from datetime. Format: 'YYYY-MM-DDTHH:mm:SS.sss'. |
--from-file | Reset input topic offsets to values defined in CSV file. |
--shift-by <Long: n> | Reset input topic offsets shifting current offset by 'n', where 'n' can be positive or negative. |
--timeout <Long: timeout (ms)> | The timeout that can be set for some use cases. For example, it can be used when describing the group to specify the maximum amount of time in milliseconds to wait before the group stabilizes (when the group is just created, or is going through some changes). (default: 5000) |
--state [String] | When specified with '--describe', includes the state of the group. When specified with '--list', it displays the state of all groups. It can also be used to list groups with specific states. The valid values are 'Empty', 'Not Ready', 'Reconciling', 'Assigning', 'Stable' and 'Dead'. |
--reset-offsets | Reset input topic offsets of streams group. Supports one streams group at a time, and instances should be inactive. You must choose one of the following reset specifications: --to-datetime, --by-duration, --to-earliest, --to-latest, --shift-by, --from-file, --to-current, --to-offset. To define the scope use --all-input-topics or --input-topics. One scope must be specified unless you use '--from-file'. Fails if neither '--dry-run' nor '–execute--execute' is specified. |
--offsets | Describe the group and list all input topic partitions in the group along with their offset lag. This is the default sub-action of --describe and may be used with the '--describe' option only. |
--members | Describe members of the group. This option may be used with the '--describe' option only. |
--list | List all streams groups. |
--help | Print usage information. |
--group <String: streams group ID> | The group ID (application ID) of the streams ID we wish to to act on. |
--all-groups | To act on all groups. Only allowed with --delete |
--execute | Execute operation. Supported operations: reset-offsets. |
--dry-run | Only show results without executing changes on streams groups. Supported operations: reset-offsets. |
--describe | Describe streams group and list offset lag (number of records not yet processed) related to given group. |
--delete-offsets | Delete offsets of streams group. Supports one streams group at the time. To define the scope use --all-input-topics or --input-topics. One scope must be specified unless you use '--from-file'. |
--delete | Pass in a group to delete entire streams group. For instance --group g1. Deletes offsets, internal topics of the streams group and and topology and ownership information on the broker. Instances should be inactive. |
--command-config <String: command config property file> | Property file containing configs to be passed to Admin Client. |
--bootstrap-server <String: server to connect to> | REQUIRED: The server(s) to connect to. |
...
KIP-848 originally envisioned that Kafka Streams continues to using a byte-array metadata protocol on top of regular consumer group RPCs, and use a client-side assignor, and provided a rough proposal how to do so. The described approach was never implemented. In this KIP, we propose to use broker-side assignment by default for several reasons (mostly already mentioned in the motivation section):
Client-side assignment makes it hard to debug and tune the assignment logic, where a simple parameter change requires redeploying of all streams clients.
Using opaque byte-arrays to exchange the required metadata makes it hard to understand the state of a streams group on the protocol level. One has to discover the information from logs spread across all client machines. Central mechanisms of the Kafka protocol, such as versioning of RPCs, needs to be reimplemented on the level of RPCs.
One could argue that the Kafka protocol is simpler without Kafka Streams specific RPCs, but we think the opposite is true. The KIP-848 consumer group protocol was extended with client-side assignment, byte-array metadata and metadata versioning just for Kafka Streams. Having the concerns of Kafka Streams dealt with in separate RPCs mainly introduces a clearer separation and gives the Kafka community the ability to simplify the upcoming consumer protocol.
Instead of using a separate initialize RPCthe heartbeat RPC during joining to initialize the topology, we considered just using the heartbeat with
memberEpoch=0to initialize the Streams group and initiate the creation of all topics. This would have a number of downsides, such as that every member needs to send the initialization data every time they start (and the initialization data may be large already in the current schema and may grow larger in the future), and the heartbeat requiring the ACL for creating topics. Furthermore, since the initialization may take a certain amount of time, we’d likely still have to respond to the initial heartbeat without having fully initialized the group, leading to temporary “initializing” state for the group that we also get in this proposala dedicated group intialization RPC. Using the heartbeat RPC for initialization turned out to be simpler and we realized that the drawbacks that we wanted to avoid with the dedicated initialization RPC where not that significant. For example, we thought that we could save on data sent for intitialization with a dedicated intialization call. However, sending the topology metadata in the heartbeat when joining does not seem to be too much and we can ensure all clients use the same topology metadata. Also with two different calls we had the overhead to coordinate the initialization and the heartbeat requests.An earlier draft of this KIP proposed introducing optional client-side task assignment, that would allow customization of the task assignment similar to KIP-924. We decided to remove it from this KIP, to limit the scope of the KIP and not introduce features in the protocol whose use we cannot fully envision yet. The RPCs defined in this KIP are, however, defined in a way that they could easily be extended with client-side assignment in a follow-up KIP, possibly together with a public interface for adding custom task assignors on the client side.
...