use of com.linkedin.kafka.cruisecontrol.model.Disk in project cruise-control by linkedin.
the class AbstractGoal method maybeMoveReplicaBetweenDisks.
/**
* Attempt to move replica between disks of the same broker. The application considers the candidate disks as the potential
* destination disk for replica movement. If the movement attempt succeeds, the function returns the destination disk,
* otherwise the function returns null.
*
* @param clusterModel The state of the cluster.
* @param replica Replica to be moved.
* @param candidateDisks Candidate disks as the potential destination for replica movement.
* @param optimizedGoals Optimized goals.
* @return The destination disk if the movement attempt succeeds, null otherwise.
*/
protected Disk maybeMoveReplicaBetweenDisks(ClusterModel clusterModel, Replica replica, Collection<Disk> candidateDisks, Set<Goal> optimizedGoals) {
for (Disk disk : candidateDisks) {
BalancingAction proposal = new BalancingAction(replica.topicPartition(), replica.disk(), disk, ActionType.INTRA_BROKER_REPLICA_MOVEMENT);
if (!legitMoveBetweenDisks(replica, disk, ActionType.INTRA_BROKER_REPLICA_MOVEMENT)) {
LOG.trace("Replica move to disk is not legit for {}.", proposal);
continue;
}
if (!selfSatisfied(clusterModel, proposal)) {
LOG.trace("Unable to self-satisfy proposal {}.", proposal);
continue;
}
ActionAcceptance acceptance = AnalyzerUtils.isProposalAcceptableForOptimizedGoals(optimizedGoals, proposal, clusterModel);
LOG.trace("Trying to apply legit and self-satisfied action {}, actionAcceptance = {}", proposal, acceptance);
if (acceptance == ACCEPT) {
clusterModel.relocateReplica(replica.topicPartition(), replica.broker().id(), disk.logDir());
return disk;
}
}
return null;
}
use of com.linkedin.kafka.cruisecontrol.model.Disk in project cruise-control by linkedin.
the class GoalUtils method averageDiskUtilizationPercentage.
/**
* Get the latest average utilization percentage of all the alive disks on the broker.
*
* @param broker Broker for which the average disk utilization percentage has been queried.
* @return Latest average utilization percentage of all the alive disks on the broker.
*/
public static double averageDiskUtilizationPercentage(Broker broker) {
double totalAliveDiskCapacity = 0;
double totalAliveDiskUtilization = 0;
for (Disk disk : broker.disks()) {
if (disk.isAlive()) {
totalAliveDiskCapacity += disk.capacity();
totalAliveDiskUtilization += disk.utilization();
}
}
return totalAliveDiskCapacity > 0 ? totalAliveDiskUtilization / totalAliveDiskCapacity : DEAD_BROKER_UTILIZATION;
}
use of com.linkedin.kafka.cruisecontrol.model.Disk in project cruise-control by linkedin.
the class IntraBrokerDiskCapacityGoal method selfSatisfied.
@Override
protected boolean selfSatisfied(ClusterModel clusterModel, BalancingAction action) {
Replica sourceReplica = clusterModel.broker(action.sourceBrokerId()).replica(action.topicPartition());
Disk destinationDisk = clusterModel.broker(action.destinationBrokerId()).disk(action.destinationBrokerLogdir());
return sourceReplica.load().expectedUtilizationFor(RESOURCE) > 0 && isMovementAcceptableForCapacity(sourceReplica, destinationDisk);
}
use of com.linkedin.kafka.cruisecontrol.model.Disk in project cruise-control by linkedin.
the class IntraBrokerDiskCapacityGoal method actionAcceptance.
/**
* Check whether the given action is acceptable by this goal. An action is acceptable by a goal if it satisfies
* requirements of the goal. For this goal:
* ## Leadership Movement: always accept.
* ## Replica Movement/Swap: accept if action will not make disk load exceed disk capacity 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) {
// Currently disk-granularity goals do not work with broker-granularity goals.
if (action.sourceBrokerLogdir() == null || action.destinationBrokerLogdir() == null) {
throw new IllegalArgumentException(this.getClass().getSimpleName() + " does not support balancing action not " + "specifying logdir.");
}
Replica sourceReplica = clusterModel.broker(action.sourceBrokerId()).replica(action.topicPartition());
Disk destinationDisk = clusterModel.broker(action.destinationBrokerId()).disk(action.destinationBrokerLogdir());
switch(action.balancingAction()) {
case INTRA_BROKER_REPLICA_SWAP:
Replica destinationReplica = clusterModel.broker(action.destinationBrokerId()).replica(action.destinationTopicPartition());
return isSwapAcceptableForCapacity(sourceReplica, destinationReplica) ? ACCEPT : REPLICA_REJECT;
case INTRA_BROKER_REPLICA_MOVEMENT:
return isMovementAcceptableForCapacity(sourceReplica, destinationDisk) ? ACCEPT : REPLICA_REJECT;
case LEADERSHIP_MOVEMENT:
return ACCEPT;
default:
throw new IllegalArgumentException("Unsupported balancing action " + action.balancingAction() + " is provided.");
}
}
use of com.linkedin.kafka.cruisecontrol.model.Disk in project cruise-control by linkedin.
the class IntraBrokerDiskCapacityGoal method rebalanceForBroker.
/**
* Perform optimization via replica movement cross disks on broker to ensure balance: The load on each alive disk
* is under the disk's the capacity limit.
* Note the optimization from this goal cannot be applied to offline replicas because Kafka does not support moving
* replicas on bad disks to good disks within the same broker.
*
* @param broker Broker to be balanced.
* @param clusterModel The state of the cluster.
* @param optimizedGoals Optimized goals.
* @param optimizationOptions Options to take into account during optimization.
*/
@Override
protected void rebalanceForBroker(Broker broker, ClusterModel clusterModel, Set<Goal> optimizedGoals, OptimizationOptions optimizationOptions) {
LOG.debug("balancing broker {}, optimized goals = {}.", broker, optimizedGoals);
// Get alive disk over capacity limit.
List<Disk> disksOverUtilized = broker.disks().stream().filter(Disk::isAlive).filter(this::isUtilizationOverLimit).collect(Collectors.toList());
if (disksOverUtilized.isEmpty()) {
return;
}
List<Disk> candidateDisks = new ArrayList<>(broker.disks());
candidateDisks.removeAll(disksOverUtilized);
candidateDisks.sort(new Comparator<Disk>() {
@Override
public int compare(Disk disk1, Disk disk2) {
double allowanceForDisk1 = disk1.capacity() * _balancingConstraint.capacityThreshold(RESOURCE) - disk1.utilization();
double allowanceForDisk2 = disk2.capacity() * _balancingConstraint.capacityThreshold(RESOURCE) - disk2.utilization();
return ((Double) (allowanceForDisk2 - allowanceForDisk1)).intValue();
}
});
for (Disk disk : disksOverUtilized) {
for (Replica replica : disk.trackedSortedReplicas(replicaSortName(this, true, false)).sortedReplicas(true)) {
Disk d = maybeMoveReplicaBetweenDisks(clusterModel, replica, candidateDisks, optimizedGoals);
if (d == null) {
LOG.debug("Failed to move replica {} to any disk {} in broker {}", replica, candidateDisks, replica.broker());
}
if (!isUtilizationOverLimit(disk)) {
break;
}
}
}
}
Aggregations