rajinisivaram commented on code in PR #22187:
URL: https://github.com/apache/kafka/pull/22187#discussion_r3194789873


##########
clients/src/main/java/org/apache/kafka/clients/NetworkClient.java:
##########
@@ -1024,7 +1038,10 @@ private void 
handleApiVersionsResponse(List<ClientResponse> responses,
                                            InFlightRequest req, long now, 
ApiVersionsResponse apiVersionsResponse) {
         final String node = req.destination;
         if (apiVersionsResponse.data().errorCode() != Errors.NONE.code()) {
-            if (req.request.version() == 0 || 
apiVersionsResponse.data().errorCode() != Errors.UNSUPPORTED_VERSION.code()) {
+            if (metadataRecoveryStrategy == 
MetadataRecoveryStrategy.REBOOTSTRAP && apiVersionsResponse.data().errorCode() 
== Errors.REBOOTSTRAP_REQUIRED.code()) {
+                log.info("Rebootstrap requested by server due to cluster 
metadata mismatch.");

Review Comment:
   I guess we don't have the broker-side info in the response to log what 
didn't match. Maybe we could at least log the cluster id and node id that we 
sent?



##########
core/src/main/scala/kafka/server/KafkaApis.scala:
##########
@@ -1529,10 +1529,22 @@ class KafkaApis(val requestChannel: RequestChannel,
         apiVersionRequest.getErrorResponse(requestThrottleMs, 
Errors.UNSUPPORTED_VERSION.exception)
       } else if (!apiVersionRequest.isValid) {
         apiVersionRequest.getErrorResponse(requestThrottleMs, 
Errors.INVALID_REQUEST.exception)
+      } else if (clusterIdOrNodeIdIsInvalid(apiVersionRequest)) {

Review Comment:
   Is there any risk that broker may not have initialized its cluster id during 
start up when processing the first client request?



##########
core/src/main/scala/kafka/server/KafkaApis.scala:
##########
@@ -1529,10 +1529,22 @@ class KafkaApis(val requestChannel: RequestChannel,
         apiVersionRequest.getErrorResponse(requestThrottleMs, 
Errors.UNSUPPORTED_VERSION.exception)
       } else if (!apiVersionRequest.isValid) {
         apiVersionRequest.getErrorResponse(requestThrottleMs, 
Errors.INVALID_REQUEST.exception)
+      } else if (clusterIdOrNodeIdIsInvalid(apiVersionRequest)) {
+        apiVersionRequest.getErrorResponse(requestThrottleMs, 
Errors.REBOOTSTRAP_REQUIRED.exception)
       } else {
         apiVersionManager.apiVersionResponse(requestThrottleMs, 
request.header.apiVersion() < 4)
       }
     }
+
+    // KIP-1242 checks the cluster ID and node ID in the request if provided 
to ensure the
+    // client is connecting to the correct broker. If both are specified, they 
must match
+    // the expected values for this broker.
+    def clusterIdOrNodeIdIsInvalid(apiVersionRequest: ApiVersionsRequest): 
Boolean = {
+      apiVersionRequest.version >= 5 &&
+        apiVersionRequest.data.clusterId != null &&
+        (!apiVersionRequest.data.clusterId.equals(clusterId) || 
apiVersionRequest.data.nodeId != brokerId)

Review Comment:
   nit: `apiVersionRequest.data.clusterId != clusterId`



##########
clients/src/main/java/org/apache/kafka/clients/NetworkClient.java:
##########
@@ -1107,6 +1124,19 @@ private void handleInitiateApiVersionRequests(long now) {
                 // not before ready.
                 this.connectionStates.checkingApiVersions(node);
                 ApiVersionsRequest.Builder apiVersionRequestBuilder = 
entry.getValue();
+                // If we know the cluster ID and node ID we are connecting to, 
we can include
+                // those details in the ApiVersions request for checking in 
the broker,
+                // provided that the metadata recovery strategy is not NONE. 
(KIP-1242)
+                if (metadataRecoveryStrategy != MetadataRecoveryStrategy.NONE 
&& metadataClusterCheckEnable) {
+                    String clusterId = this.metadataUpdater.clusterId();
+                    int nodeId = Integer.parseInt(node);
+                    // When connecting to coordinators, the client uses large 
positive node ID
+                    // values which do not match the target broker's node ID. 
Exclude those.
+                    if (clusterId != null && nodeId > 0 && nodeId < 
Integer.MAX_VALUE / 2) {

Review Comment:
   Can we define `Integer.MAX_VALUE / 2` as a constant with the comment about 
coordinator's use of `Integer.MAX_VALUE - nodeId` which is the reason for using 
half?



##########
clients/src/test/java/org/apache/kafka/clients/NetworkClientTest.java:
##########
@@ -297,6 +297,41 @@ defaultRequestTimeoutMs, connectionSetupTimeoutMsTest, 
connectionSetupTimeoutMax
         assertEquals(3, rebootstrapCount.get());
     }
 
+    @Test
+    public void testMetadataClusterCheckFailureCausesRebootstrap() {

Review Comment:
   This check is not testing `MetadataClusterCheckFailure`, it is simply 
returns REBOOTSTRAP_REQUIRED in the response. We should rename this method to 
reflect what it is actually doing. We also need a test to verify the new 
broker-side validation - maybe we can add a test to `ApiVersionsRequestTest`. 
Ideally, we would also want a test in `ClientRebootstrapTest` to validate 
client-side handling of the response.



##########
clients/src/main/java/org/apache/kafka/clients/NetworkClient.java:
##########
@@ -1024,7 +1038,10 @@ private void 
handleApiVersionsResponse(List<ClientResponse> responses,
                                            InFlightRequest req, long now, 
ApiVersionsResponse apiVersionsResponse) {
         final String node = req.destination;
         if (apiVersionsResponse.data().errorCode() != Errors.NONE.code()) {
-            if (req.request.version() == 0 || 
apiVersionsResponse.data().errorCode() != Errors.UNSUPPORTED_VERSION.code()) {
+            if (metadataRecoveryStrategy == 
MetadataRecoveryStrategy.REBOOTSTRAP && apiVersionsResponse.data().errorCode() 
== Errors.REBOOTSTRAP_REQUIRED.code()) {

Review Comment:
   As @mingyen066 mentioned, we need to close all connections before 
rebootstrapping. We should add a test as well to ensure connections are closed.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to