-
Notifications
You must be signed in to change notification settings - Fork 14.1k
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
KAFKA-1215: Rack-Aware replica assignment option #132
Changes from 55 commits
3cccc5d
982c047
80be83c
3e75b60
233331a
f9481fb
fdb88e7
4990a96
b5f3c51
57eb1c6
479b94c
a84a289
ecaad6e
33a3953
800eadd
4326b5d
b010c5c
b7f1a39
5862943
596f948
6453ed6
78b505c
99cc7cc
2fe598e
ab0d80c
b7d9437
1d87d41
befedfa
ab60287
bd60dbb
397cb35
930f110
3c7ea09
946e677
e9d3381
b2d6d27
e19f109
133165b
2f1cf1f
2f48f23
22c9d3f
337c889
1afddb1
f63f3f0
b77ad30
62f8ddd
8cf62bd
362f470
1094361
b60fa8f
0839d69
e07c499
c5abd44
95d5fd1
346ab6d
fa3eb3c
b046eee
22beaaf
c5bfcc8
a237bc0
569b5f0
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 |
---|---|---|
|
@@ -49,16 +49,22 @@ public PartitionState(int controllerEpoch, int leader, int leaderEpoch, List<Int | |
this.zkVersion = zkVersion; | ||
this.replicas = replicas; | ||
} | ||
|
||
} | ||
|
||
public static final class Broker { | ||
public final int id; | ||
public final Map<SecurityProtocol, EndPoint> endPoints; | ||
public final String rack; | ||
|
||
public Broker(int id, Map<SecurityProtocol, EndPoint> endPoints) { | ||
public Broker(int id, Map<SecurityProtocol, EndPoint> endPoints, String rack) { | ||
this.id = id; | ||
this.endPoints = endPoints; | ||
this.rack = rack; | ||
} | ||
|
||
@Deprecated | ||
public Broker(int id, Map<SecurityProtocol, EndPoint> endPoints) { | ||
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. This constructor is only used in tests, does it make sense to keep it? I guess the question is whether the request classes are API. As I understand, they are not, but I would like to get @junrao's take. |
||
this(id, endPoints, null); | ||
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. Related to my protocol question above. Would defaulting to empty string work? 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. I discussed this in KIP discussion. NULLABLE_STRING was recommended in the discussion. I think it makes sense as rack itself is designed to be nullable (Option[String]). It is legal to define rack as an empty string. There isn't really any null checks in the code as far as I can tell. null just means no rack is defined. |
||
} | ||
} | ||
|
||
|
@@ -91,6 +97,7 @@ public EndPoint(String host, int port) { | |
// Broker key names | ||
private static final String BROKER_ID_KEY_NAME = "id"; | ||
private static final String ENDPOINTS_KEY_NAME = "end_points"; | ||
private static final String RACK_KEY_NAME = "rack"; | ||
|
||
// EndPoint key names | ||
private static final String HOST_KEY_NAME = "host"; | ||
|
@@ -117,20 +124,20 @@ private static Set<Broker> brokerEndPointsToBrokers(Set<BrokerEndPoint> brokerEn | |
for (BrokerEndPoint brokerEndPoint : brokerEndPoints) { | ||
Map<SecurityProtocol, EndPoint> endPoints = Collections.singletonMap(SecurityProtocol.PLAINTEXT, | ||
new EndPoint(brokerEndPoint.host(), brokerEndPoint.port())); | ||
brokers.add(new Broker(brokerEndPoint.id(), endPoints)); | ||
brokers.add(new Broker(brokerEndPoint.id(), endPoints, null)); | ||
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. Could use the constructor that doesn't take a rack. 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. sure. 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. @granthenke Given the comment from @junrao that the old constructor should be deprecated, I think it is better to use the new constructor. 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. Works for me |
||
} | ||
return brokers; | ||
} | ||
|
||
/** | ||
* Constructor for version 1. | ||
* Constructor for version 2. | ||
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. We will still need a separate constructor for v1 of UpdateMetadataRequest since in ControllerChannelManager, we may need to send a v1 request depending on inter.broker.protocol. 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. @junrao This may not be necessary. See my comment in ControllerChannelManager. 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. Note that this constructor is only used in tests. Does it even make sense to keep it? |
||
*/ | ||
public UpdateMetadataRequest(int controllerId, int controllerEpoch, Map<TopicPartition, | ||
PartitionState> partitionStates, Set<Broker> liveBrokers) { | ||
this(1, controllerId, controllerEpoch, partitionStates, liveBrokers); | ||
this(2, controllerId, controllerEpoch, partitionStates, liveBrokers); | ||
} | ||
|
||
private UpdateMetadataRequest(int version, int controllerId, int controllerEpoch, Map<TopicPartition, | ||
public UpdateMetadataRequest(int version, int controllerId, int controllerEpoch, Map<TopicPartition, | ||
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. Is this only public for testing? Would protected or default also work? 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. No, it is used in ControllerChannelManager and has to be public. 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. Is that because we're depending on this constructor for version 1? I know we depend on choosing the right constructor in other request objects to get the right version, but I wonder if it would be better to have explicit static factory methods (e.g. 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. We depend on this constructor to create version 1 and 2 UpdateMetadataRequest, and possibly for future versions as well. 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. Fair enough. I was only wondering if there was a way to keep the version better encapsulated (like all of the other requests). Perhaps at least there should be a check on the version to make sure it is greater than 1? I might even enforce only version 1 and 2 since we'll almost certainly have to touch this code anyway if there is another version bump. 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. I think my preference would probably be to have static factory methods with the versions included in the name. Using constructors is kind of annoying because you have to check the comment to make sure you get the right one. 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. Yeah, we should use more static factories and less overloaded constructors in Kafka. 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. @ijuma @hachikuji Would you mind if I leave this code refactoring of constructors to you guys? 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. Fine by me. 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. Ditto |
||
PartitionState> partitionStates, Set<Broker> liveBrokers) { | ||
super(new Struct(ProtoUtils.requestSchema(ApiKeys.UPDATE_METADATA_KEY.id, version))); | ||
struct.set(CONTROLLER_ID_KEY_NAME, controllerId); | ||
|
@@ -173,6 +180,9 @@ private UpdateMetadataRequest(int version, int controllerId, int controllerEpoch | |
|
||
} | ||
brokerData.set(ENDPOINTS_KEY_NAME, endPointsData.toArray()); | ||
if (version >= 2) { | ||
brokerData.set(RACK_KEY_NAME, broker.rack); | ||
} | ||
} | ||
|
||
brokersData.add(brokerData); | ||
|
@@ -226,8 +236,8 @@ public UpdateMetadataRequest(Struct struct) { | |
int port = brokerData.getInt(PORT_KEY_NAME); | ||
Map<SecurityProtocol, EndPoint> endPoints = new HashMap<>(1); | ||
endPoints.put(SecurityProtocol.PLAINTEXT, new EndPoint(host, port)); | ||
liveBrokers.add(new Broker(brokerId, endPoints)); | ||
} else { // V1 | ||
liveBrokers.add(new Broker(brokerId, endPoints, null)); | ||
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. Could use the constructor that doesn't take a rack. |
||
} else { // V1 or V2 | ||
Map<SecurityProtocol, EndPoint> endPoints = new HashMap<>(); | ||
for (Object endPointDataObj : brokerData.getArray(ENDPOINTS_KEY_NAME)) { | ||
Struct endPointData = (Struct) endPointDataObj; | ||
|
@@ -236,11 +246,13 @@ public UpdateMetadataRequest(Struct struct) { | |
short protocolTypeId = endPointData.getShort(SECURITY_PROTOCOL_TYPE_KEY_NAME); | ||
endPoints.put(SecurityProtocol.forId(protocolTypeId), new EndPoint(host, port)); | ||
} | ||
liveBrokers.add(new Broker(brokerId, endPoints)); | ||
String rack = null; | ||
if (brokerData.hasField(RACK_KEY_NAME)) { // V2 | ||
rack = brokerData.getString(RACK_KEY_NAME); | ||
} | ||
liveBrokers.add(new Broker(brokerId, endPoints, rack)); | ||
} | ||
|
||
} | ||
|
||
controllerId = struct.getInt(CONTROLLER_ID_KEY_NAME); | ||
controllerEpoch = struct.getInt(CONTROLLER_EPOCH_KEY_NAME); | ||
this.partitionStates = partitionStates; | ||
|
@@ -249,14 +261,11 @@ public UpdateMetadataRequest(Struct struct) { | |
|
||
@Override | ||
public AbstractRequestResponse getErrorResponse(int versionId, Throwable e) { | ||
switch (versionId) { | ||
case 0: | ||
case 1: | ||
return new UpdateMetadataResponse(Errors.forException(e).code()); | ||
default: | ||
throw new IllegalArgumentException(String.format("Version %d is not valid. Valid versions for %s are 0 to %d", | ||
versionId, this.getClass().getSimpleName(), ProtoUtils.latestVersion(ApiKeys.UPDATE_METADATA_KEY.id))); | ||
} | ||
if (versionId <= 2) | ||
return new UpdateMetadataResponse(Errors.forException(e).code()); | ||
else | ||
throw new IllegalArgumentException(String.format("Version %d is not valid. Valid versions for %s are 0 to %d", | ||
versionId, this.getClass().getSimpleName(), ProtoUtils.latestVersion(ApiKeys.UPDATE_METADATA_KEY.id))); | ||
} | ||
|
||
public int controllerId() { | ||
|
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.
We should probably mark this as deprecated.