|
24 | 24 | import java.util.HashMap; |
25 | 25 | import java.util.List; |
26 | 26 | import java.util.Map; |
| 27 | +import java.util.Objects; |
27 | 28 | import java.util.Optional; |
28 | 29 | import java.util.Set; |
29 | 30 | import java.util.function.Function; |
@@ -134,7 +135,6 @@ private List<String> convertFailureReasons(List<HardConstraint> hardConstraints) |
134 | 135 | .collect(Collectors.toList()); |
135 | 136 | } |
136 | 137 |
|
137 | | - // TODO investigate better ways to sort replicas. One option is sorting based on the creation time. |
138 | 138 | private List<AssignableReplica> getOrderedAssignableReplica(ClusterModel clusterModel) { |
139 | 139 | Map<String, Set<AssignableReplica>> replicasByResource = clusterModel.getAssignableReplicaMap(); |
140 | 140 | List<AssignableReplica> orderedAssignableReplicas = |
@@ -162,11 +162,23 @@ private List<AssignableReplica> getOrderedAssignableReplica(ClusterModel cluster |
162 | 162 | int statePriority1 = replica1.getStatePriority(); |
163 | 163 | int statePriority2 = replica2.getStatePriority(); |
164 | 164 | if (statePriority1 == statePriority2) { |
165 | | - // If state prioritizes are the same, compare the names. |
166 | | - if (resourceName1.equals(resourceName2)) { |
167 | | - return replica1.getPartitionName().compareTo(replica2.getPartitionName()); |
| 165 | + // If state priorities are the same, try to randomize the replicas order. Otherwise, |
| 166 | + // the same replicas might always be moved in each rebalancing. This is because their |
| 167 | + // placement calculating will always happen at the critical moment while the cluster is |
| 168 | + // almost close to the expected utilization. |
| 169 | + // |
| 170 | + // Note that to ensure the algorithm is deterministic with the same inputs, do not use |
| 171 | + // Random functions here. Use hashcode based on the cluster topology information to get |
| 172 | + // a controlled randomized order is good enough. |
| 173 | + Long replicaHash1 = (long) Objects |
| 174 | + .hash(replica1.toString(), clusterModel.getAssignableNodes().keySet()); |
| 175 | + Long replicaHash2 = (long) Objects |
| 176 | + .hash(replica2.toString(), clusterModel.getAssignableNodes().keySet()); |
| 177 | + if (!replicaHash1.equals(replicaHash2)) { |
| 178 | + return replicaHash1.compareTo(replicaHash2); |
168 | 179 | } else { |
169 | | - return resourceName1.compareTo(resourceName2); |
| 180 | + // In case of hash collision, return order according to the name. |
| 181 | + return replica1.toString().compareTo(replica2.toString()); |
170 | 182 | } |
171 | 183 | } else { |
172 | 184 | // Note we shall prioritize the replica with a higher state priority, |
|
0 commit comments