use of com.linkedin.kafka.cruisecontrol.model.Broker in project cruise-control by linkedin.
the class ReplicaDistributionGoal method actionAcceptance.
/**
* Check whether the given action is acceptable by this goal. An action is acceptable if the number of replicas at
* (1) the source broker does not go under the allowed limit.
* (2) the destination broker does not go over the allowed limit.
*
* @param action Action to be checked for acceptance.
* @param clusterModel The state of the cluster.
* @return {@link ActionAcceptance#ACCEPT} if the action is acceptable by this goal,
* {@link ActionAcceptance#REPLICA_REJECT} otherwise.
*/
@Override
public ActionAcceptance actionAcceptance(BalancingAction action, ClusterModel clusterModel) {
switch(action.balancingAction()) {
case REPLICA_SWAP:
case LEADERSHIP_MOVEMENT:
return ACCEPT;
case REPLICA_MOVEMENT:
Broker sourceBroker = clusterModel.broker(action.sourceBrokerId());
Broker destinationBroker = clusterModel.broker(action.destinationBrokerId());
// Check that destination and source would not become unbalanced.
return (isReplicaCountUnderBalanceUpperLimitAfterChange(destinationBroker, ADD) && isReplicaCountAboveBalanceLowerLimitAfterChange(sourceBroker, REMOVE)) ? ACCEPT : REPLICA_REJECT;
default:
throw new IllegalArgumentException("Unsupported balancing action " + action.balancingAction() + " is provided.");
}
}
use of com.linkedin.kafka.cruisecontrol.model.Broker in project cruise-control by linkedin.
the class ReplicaDistributionGoal method selfSatisfied.
/**
* Check if requirements of this goal are not violated if this proposal is applied to the given cluster state,
* false otherwise.
*
* @param clusterModel The state of the cluster.
* @param action Proposal containing information about
* @return True if requirements of this goal are not violated if this proposal is applied to the given cluster state,
* false otherwise.
*/
@Override
protected boolean selfSatisfied(ClusterModel clusterModel, BalancingAction action) {
Broker destinationBroker = clusterModel.broker(action.destinationBrokerId());
Broker sourceBroker = clusterModel.broker(action.sourceBrokerId());
// If the source broker is dead and currently self healing dead brokers only, then the proposal must be executed.
if (!sourceBroker.isAlive() && _selfHealingDeadBrokersOnly) {
return true;
}
// Check that destination and source would not become unbalanced.
return isReplicaCountUnderBalanceUpperLimitAfterChange(destinationBroker, ADD) && isReplicaCountAboveBalanceLowerLimitAfterChange(sourceBroker, REMOVE);
}
use of com.linkedin.kafka.cruisecontrol.model.Broker in project cruise-control by linkedin.
the class ReplicaDistributionTarget method isEligibleForReplica.
private boolean isEligibleForReplica(ClusterModel clusterModel, Replica replica, int candidateBrokerId) {
Set<Broker> newBrokers = clusterModel.newBrokers();
Broker candidateBroker = clusterModel.broker(candidateBrokerId);
return newBrokers.isEmpty() || candidateBroker.isNew() || replica.originalBroker() == candidateBroker;
}
use of com.linkedin.kafka.cruisecontrol.model.Broker in project cruise-control by linkedin.
the class ResourceDistributionGoal method selfSatisfied.
/**
* Check if requirements of this goal are not violated if this action is applied to the given cluster state,
* false otherwise. An action is acceptable if: (1) destination broker utilization for the given resource is less
* than the source broker utilization. (2) movement is acceptable (i.e. under the broker balance limit for balanced
* resources) for already balanced resources. Already balanced resources are the ones that have gone through the
* "resource distribution" process specified in this goal.
*
* @param clusterModel The state of the cluster.
* @param action Action containing information about potential modification to the given cluster model.
* @return True if requirements of this goal are not violated if this action is applied to the given cluster state,
* false otherwise.
*/
@Override
protected boolean selfSatisfied(ClusterModel clusterModel, BalancingAction action) {
Broker destinationBroker = clusterModel.broker(action.destinationBrokerId());
Replica sourceReplica = clusterModel.broker(action.sourceBrokerId()).replica(action.topicPartition());
// must be executed.
if (!sourceReplica.broker().isAlive() && _selfHealingDeadBrokersOnly) {
return action.balancingAction() != REPLICA_SWAP;
}
switch(action.balancingAction()) {
case REPLICA_SWAP:
Replica destinationReplica = destinationBroker.replica(action.destinationTopicPartition());
double sourceUtilizationDelta = destinationReplica.load().expectedUtilizationFor(resource()) - sourceReplica.load().expectedUtilizationFor(resource());
return sourceUtilizationDelta != 0 && !isSwapViolatingLimit(sourceReplica, destinationReplica);
case REPLICA_MOVEMENT:
case LEADERSHIP_MOVEMENT:
// Check that current destination would not become more unbalanced.
return isLoadUnderBalanceUpperLimitAfterChange(sourceReplica.load(), destinationBroker, ADD) && isLoadAboveBalanceLowerLimitAfterChange(sourceReplica.load(), sourceReplica.broker(), REMOVE);
default:
throw new IllegalArgumentException("Unsupported balancing action " + action.balancingAction() + " is provided.");
}
}
use of com.linkedin.kafka.cruisecontrol.model.Broker in project cruise-control by linkedin.
the class ResourceDistributionGoal method rebalanceByMovingLoadOut.
private boolean rebalanceByMovingLoadOut(Broker broker, ClusterModel clusterModel, Set<Goal> optimizedGoals, ActionType actionType, Set<String> excludedTopics) {
// Get the eligible brokers.
SortedSet<Broker> candidateBrokers = new TreeSet<>(Comparator.comparingDouble(this::utilizationPercentage).thenComparingInt(Broker::id));
if (_selfHealingDeadBrokersOnly) {
candidateBrokers.addAll(clusterModel.healthyBrokers());
} else {
candidateBrokers.addAll(clusterModel.healthyBrokersUnderThreshold(resource(), _balanceUpperThreshold));
}
// Get the replicas to rebalance.
List<Replica> replicasToMove;
if (actionType == LEADERSHIP_MOVEMENT) {
// Only take leader replicas to move leaders.
replicasToMove = new ArrayList<>(broker.leaderReplicas());
replicasToMove.sort((r1, r2) -> Double.compare(r2.load().expectedUtilizationFor(resource()), r1.load().expectedUtilizationFor(resource())));
} else {
// Take all replicas for replica movements.
replicasToMove = broker.sortedReplicas(resource());
}
// Now let's move things around.
for (Replica replica : replicasToMove) {
if (shouldExclude(replica, excludedTopics)) {
continue;
}
// It does not make sense to move a replica without utilization from a live broker.
if (replica.load().expectedUtilizationFor(resource()) == 0.0 && broker.isAlive()) {
break;
}
// An optimization for leader movements.
SortedSet<Broker> eligibleBrokers;
if (actionType == LEADERSHIP_MOVEMENT) {
eligibleBrokers = new TreeSet<>(Comparator.comparingDouble(this::utilizationPercentage).thenComparingInt(Broker::id));
clusterModel.partition(replica.topicPartition()).followerBrokers().forEach(b -> {
if (candidateBrokers.contains(b)) {
eligibleBrokers.add(b);
}
});
} else {
eligibleBrokers = candidateBrokers;
}
Broker b = maybeApplyBalancingAction(clusterModel, replica, eligibleBrokers, actionType, optimizedGoals);
// Only check if we successfully moved something.
if (b != null) {
if (isLoadUnderBalanceUpperLimit(broker)) {
return false;
}
// Remove and reinsert the broker so the order is correct.
candidateBrokers.remove(b);
if (utilizationPercentage(b) < _balanceUpperThreshold) {
candidateBrokers.add(b);
}
}
}
// we consider it as not over limit.
return !broker.replicas().isEmpty();
}
Aggregations