-
Notifications
You must be signed in to change notification settings - Fork 15.4k
KAFKA-9437: KIP-559: Make the Kafka Protocol Friendlier with L7 Proxies #7994
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 6 commits
effa65d
6988e54
525e84d
aa10086
832a6db
f345790
8c160c9
6b78131
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -436,7 +436,7 @@ boolean joinGroupIfNeeded(final Timer timer) { | |
| // Duplicate the buffer in case `onJoinComplete` does not complete and needs to be retried. | ||
| ByteBuffer memberAssignment = future.value().duplicate(); | ||
|
|
||
| onJoinComplete(generationSnapshot.generationId, generationSnapshot.memberId, generationSnapshot.protocol, memberAssignment); | ||
| onJoinComplete(generationSnapshot.generationId, generationSnapshot.memberId, generationSnapshot.protocolName, memberAssignment); | ||
|
|
||
| // Generally speaking we should always resetJoinGroupFuture once the future is done, but here | ||
| // we can only reset the join group future after the completion callback returns. This ensures | ||
|
|
@@ -574,7 +574,11 @@ private class JoinGroupResponseHandler extends CoordinatorResponseHandler<JoinGr | |
| @Override | ||
| public void handle(JoinGroupResponse joinResponse, RequestFuture<ByteBuffer> future) { | ||
| Errors error = joinResponse.error(); | ||
| if (error == Errors.NONE) { | ||
| if (isProtocolTypeInconsistent(joinResponse.data().protocolType())) { | ||
| log.debug("JoinGroup failed: Received inconsistent ProtocolType ({})", | ||
| joinResponse.data().protocolType()); | ||
| future.raise(Errors.INCONSISTENT_GROUP_PROTOCOL); | ||
| } else if (error == Errors.NONE) { | ||
| log.debug("Received successful JoinGroup response: {}", joinResponse); | ||
| sensors.joinSensor.record(response.requestLatencyMs()); | ||
|
|
||
|
|
@@ -654,6 +658,8 @@ private RequestFuture<ByteBuffer> onJoinFollower() { | |
| new SyncGroupRequestData() | ||
| .setGroupId(rebalanceConfig.groupId) | ||
| .setMemberId(generation.memberId) | ||
| .setProtocolType(protocolType()) | ||
| .setProtocolName(generation.protocolName) | ||
| .setGroupInstanceId(this.rebalanceConfig.groupInstanceId.orElse(null)) | ||
| .setGenerationId(generation.generationId) | ||
| .setAssignments(Collections.emptyList()) | ||
|
|
@@ -681,6 +687,8 @@ private RequestFuture<ByteBuffer> onJoinLeader(JoinGroupResponse joinResponse) { | |
| new SyncGroupRequestData() | ||
| .setGroupId(rebalanceConfig.groupId) | ||
| .setMemberId(generation.memberId) | ||
| .setProtocolType(protocolType()) | ||
| .setProtocolName(generation.protocolName) | ||
| .setGroupInstanceId(this.rebalanceConfig.groupInstanceId.orElse(null)) | ||
| .setGenerationId(generation.generationId) | ||
| .setAssignments(groupAssignmentList) | ||
|
|
@@ -704,7 +712,12 @@ private class SyncGroupResponseHandler extends CoordinatorResponseHandler<SyncGr | |
| public void handle(SyncGroupResponse syncResponse, | ||
| RequestFuture<ByteBuffer> future) { | ||
| Errors error = syncResponse.error(); | ||
| if (error == Errors.NONE) { | ||
| if (isProtocolTypeInconsistent(syncResponse.data.protocolType()) | ||
| || isProtocolNameInconsistent(syncResponse.data.protocolName())) { | ||
| log.debug("SyngGroup failed: Received inconsistent ProtocolType ({}) and/or ProtocolName ({})", | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: I'd suggest breaking this into two separate cases so that the user doesn't have to guess what was inconsistent. Also, can we include the expected value?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That makes sense. I will also include the expected value. |
||
| syncResponse.data.protocolType(), syncResponse.data.protocolName()); | ||
| future.raise(Errors.INCONSISTENT_GROUP_PROTOCOL); | ||
| } else if (error == Errors.NONE) { | ||
| sensors.syncSensor.record(response.requestLatencyMs()); | ||
| future.complete(ByteBuffer.wrap(syncResponse.data.assignment())); | ||
| } else { | ||
|
|
@@ -887,6 +900,14 @@ protected synchronized void requestRejoin() { | |
| this.rejoinNeeded = true; | ||
| } | ||
|
|
||
| private boolean isProtocolTypeInconsistent(String protocolType) { | ||
| return protocolType != null && !protocolType.equals(protocolType()); | ||
| } | ||
|
|
||
| private boolean isProtocolNameInconsistent(String protocolName) { | ||
| return protocolName != null && !protocolName.equals(generation().protocolName); | ||
| } | ||
|
|
||
| /** | ||
| * Close the coordinator, waiting if needed to send LeaveGroup. | ||
| */ | ||
|
|
@@ -1320,12 +1341,12 @@ protected static class Generation { | |
|
|
||
| public final int generationId; | ||
| public final String memberId; | ||
| public final String protocol; | ||
| public final String protocolName; | ||
|
|
||
| public Generation(int generationId, String memberId, String protocol) { | ||
| public Generation(int generationId, String memberId, String protocolName) { | ||
| this.generationId = generationId; | ||
| this.memberId = memberId; | ||
| this.protocol = protocol; | ||
| this.protocolName = protocolName; | ||
| } | ||
|
|
||
| /** | ||
|
|
@@ -1343,20 +1364,20 @@ public boolean equals(final Object o) { | |
| final Generation that = (Generation) o; | ||
| return generationId == that.generationId && | ||
| Objects.equals(memberId, that.memberId) && | ||
| Objects.equals(protocol, that.protocol); | ||
| Objects.equals(protocolName, that.protocolName); | ||
| } | ||
|
|
||
| @Override | ||
| public int hashCode() { | ||
| return Objects.hash(generationId, memberId, protocol); | ||
| return Objects.hash(generationId, memberId, protocolName); | ||
| } | ||
|
|
||
| @Override | ||
| public String toString() { | ||
| return "Generation{" + | ||
| "generationId=" + generationId + | ||
| ", memberId='" + memberId + '\'' + | ||
| ", protocol='" + protocol + '\'' + | ||
| ", protocol='" + protocolName + '\'' + | ||
| '}'; | ||
| } | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -29,7 +29,9 @@ | |
| // Version 5 is bumped to apply group.instance.id to identify member across restarts. | ||
| // | ||
| // Version 6 is the first flexible version. | ||
| "validVersions": "0-6", | ||
| // | ||
| // Starting from version 7, the broker sends back the Protocol Type to the client (KIP-599). | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. KIP-559 (and elsewhere)
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good catch! Thanks! |
||
| "validVersions": "0-7", | ||
| "flexibleVersions": "6+", | ||
| "fields": [ | ||
| { "name": "ThrottleTimeMs", "type": "int32", "versions": "2+", "ignorable": true, | ||
|
|
@@ -38,6 +40,9 @@ | |
| "about": "The error code, or 0 if there was no error." }, | ||
| { "name": "GenerationId", "type": "int32", "versions": "0+", "default": "-1", | ||
| "about": "The generation ID of the group." }, | ||
| { "name": "ProtocolType", "type": "string", "versions": "7+", | ||
| "nullableVersions": "7+", "default": "null", "ignorable": true, | ||
| "about": "The group protocol name." }, | ||
| { "name": "ProtocolName", "type": "string", "versions": "0+", | ||
| "about": "The group protocol selected by the coordinator." }, | ||
| { "name": "Leader", "type": "string", "versions": "0+", | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -22,7 +22,11 @@ | |
| // Starting from version 3, we add a new field called groupInstanceId to indicate member identity across restarts. | ||
| // | ||
| // Version 4 is the first flexible version. | ||
| "validVersions": "0-4", | ||
| // | ||
| // Starting from version 5, the client sends the Protocol Type and the Protocol Name | ||
| // to the broker (KIP-599). The broker will reject the request if they are inconsistent | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. KIP-559 |
||
| // with the Type and Name known by the broker. | ||
| "validVersions": "0-5", | ||
| "flexibleVersions": "4+", | ||
| "fields": [ | ||
| { "name": "GroupId", "type": "string", "versions": "0+", "entityType": "groupId", | ||
|
|
@@ -34,6 +38,12 @@ | |
| { "name": "GroupInstanceId", "type": "string", "versions": "3+", | ||
| "nullableVersions": "3+", "default": "null", | ||
| "about": "The unique identifier of the consumer instance provided by end user." }, | ||
| { "name": "ProtocolType", "type": "string", "versions": "5+", | ||
| "nullableVersions": "5+", "default": "null", "ignorable": true, | ||
| "about": "The group protocol type." }, | ||
| { "name": "ProtocolName", "type": "string", "versions": "5+", | ||
| "nullableVersions": "5+", "default": "null", "ignorable": true, | ||
| "about": "The group protocol name." }, | ||
| { "name": "Assignments", "type": "[]SyncGroupRequestAssignment", "versions": "0+", | ||
| "about": "Each assignment.", "fields": [ | ||
| { "name": "MemberId", "type": "string", "versions": "0+", | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the error code should take precedence over this validation. Perhaps we do this only when the error is NONE? Similarly for the JoinGroup response.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right. Let me do this.