Search in sources :

Example 26 with Replica

use of com.linkedin.kafka.cruisecontrol.model.Replica in project cruise-control by linkedin.

the class ReplicaDistributionGoal method updateGoalState.

/**
 * Update goal state after one round of self-healing / rebalance.
 * @param clusterModel The state of the cluster.
 * @param excludedTopics The topics that should be excluded from the optimization proposal.
 */
@Override
protected void updateGoalState(ClusterModel clusterModel, Set<String> excludedTopics) throws OptimizationFailureException {
    // While proposals exclude the excludedTopics, the balance still considers utilization of the excludedTopic replicas.
    if (!_brokerIdsAboveBalanceUpperLimit.isEmpty()) {
        LOG.warn("Replicas count on broker ids:{} {} above the balance limit of {} after {}.", _brokerIdsAboveBalanceUpperLimit, (_brokerIdsAboveBalanceUpperLimit.size() > 1) ? "are" : "is", _balanceUpperLimit, (clusterModel.selfHealingEligibleReplicas().isEmpty()) ? "rebalance" : "self-healing");
        _brokerIdsAboveBalanceUpperLimit.clear();
        _succeeded = false;
    }
    if (!_brokerIdsUnderBalanceLowerLimit.isEmpty()) {
        LOG.warn("Replica count on broker ids:{} {} under the balance limit of {} after {}.", _brokerIdsUnderBalanceLowerLimit, (_brokerIdsUnderBalanceLowerLimit.size() > 1) ? "are" : "is", _balanceLowerLimit, (clusterModel.selfHealingEligibleReplicas().isEmpty()) ? "rebalance" : "self-healing");
        _brokerIdsUnderBalanceLowerLimit.clear();
        _succeeded = false;
    }
    // Sanity check: No self-healing eligible replica should remain at a decommissioned broker.
    for (Replica replica : clusterModel.selfHealingEligibleReplicas()) {
        if (replica.broker().isAlive()) {
            continue;
        }
        if (_selfHealingDeadBrokersOnly) {
            throw new OptimizationFailureException("Self healing failed to move the replica away from decommissioned brokers.");
        }
        _selfHealingDeadBrokersOnly = true;
        LOG.warn("Omitting resource balance limit to relocate remaining replicas from dead brokers to healthy ones.");
        return;
    }
    // No dead broker contains replica.
    _selfHealingDeadBrokersOnly = false;
    // Sanity check: No self-healing eligible replica should remain at a decommissioned broker.
    for (Replica replica : clusterModel.selfHealingEligibleReplicas()) {
        if (!replica.broker().isAlive()) {
            throw new OptimizationFailureException("Self healing failed to move the replica away from decommissioned broker.");
        }
    }
    finish();
}
Also used : OptimizationFailureException(com.linkedin.kafka.cruisecontrol.exception.OptimizationFailureException) Replica(com.linkedin.kafka.cruisecontrol.model.Replica)

Example 27 with Replica

use of com.linkedin.kafka.cruisecontrol.model.Replica in project cruise-control by linkedin.

the class ReplicaDistributionTarget method moveReplicasInSourceBrokerToEligibleBrokers.

/**
 * Move replicas residing in the given cluster and given healthy source broker having given set of topic partitions
 * to eligible brokers. Replica movements are guaranteed not to violate the requirements of optimized goals.
 *
 * @param clusterModel           The state of the cluster.
 * @param replicasInBrokerToMove Replicas to move from the given source broker.
 * @param optimizedGoals         Goals that have already been optimized. The function ensures that their requirements won't
 *                               be violated.
 * @param excludedTopics The topics that should be excluded from the optimization action.
 */
boolean moveReplicasInSourceBrokerToEligibleBrokers(ClusterModel clusterModel, SortedSet<Replica> replicasInBrokerToMove, Set<Goal> optimizedGoals, Set<String> excludedTopics) {
    // Get number of replicas to move from the local to a remote broker to achieve the distribution target.
    int numReplicasToMove = numReplicasToMove(replicasInBrokerToMove.size());
    if (numReplicasToMove == 0) {
        return true;
    }
    for (Replica replicaToMove : replicasInBrokerToMove) {
        if (excludedTopics.contains(replicaToMove.topicPartition().topic()) && replicaToMove.originalBroker().isAlive()) {
            continue;
        }
        if (moveReplicaToEligibleBroker(clusterModel, replicaToMove, optimizedGoals)) {
            numReplicasToMove--;
            // Check if any more replicas need to move.
            if (numReplicasToMove == 0) {
                break;
            }
        }
    }
    // Update consumed warm broker credits. These credits are consumed because the broker was unable to move all
    // replicas that it was supposed to move to reach a balanced state to eligible brokers.
    _consumedWarmBrokerCredits += numReplicasToMove;
    return numReplicasToMove == 0;
}
Also used : Replica(com.linkedin.kafka.cruisecontrol.model.Replica)

Example 28 with Replica

use of com.linkedin.kafka.cruisecontrol.model.Replica 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.");
    }
}
Also used : Broker(com.linkedin.kafka.cruisecontrol.model.Broker) Replica(com.linkedin.kafka.cruisecontrol.model.Replica)

Example 29 with Replica

use of com.linkedin.kafka.cruisecontrol.model.Replica in project cruise-control by linkedin.

the class ResourceDistributionGoal method sortedCandidateReplicas.

/**
 * Get the sorted replicas in the given broker whose (1) topic is not an excluded topic AND (2) do not violate the given load
 * limit in ascending or descending order. Load limit requires the replica load to be (1) above the given limit in
 * descending order, (2) below the given limit in ascending order.
 *
 * @param broker Broker whose replicas will be considered.
 * @param excludedTopics Excluded topics for which the replicas will be remove from the returned candidate replicas.
 * @param loadLimit Load limit determining the lower cutoff in descending order, upper cutoff in ascending order.
 * @param isAscending True if sort requested in ascending order, false otherwise.
 * @return Sorted replicas in the given broker whose (1) topic is not an excluded topic AND (2) do not violate the
 * given load limit in ascending or descending order.
 */
private SortedSet<Replica> sortedCandidateReplicas(Broker broker, Set<String> excludedTopics, double loadLimit, boolean isAscending) {
    SortedSet<Replica> candidateReplicas = new TreeSet<>((r1, r2) -> {
        int result = isAscending ? Double.compare(r1.load().expectedUtilizationFor(resource()), r2.load().expectedUtilizationFor(resource())) : Double.compare(r2.load().expectedUtilizationFor(resource()), r1.load().expectedUtilizationFor(resource()));
        return result == 0 ? r1.topicPartition().toString().compareTo(r2.topicPartition().toString()) : result;
    });
    // If the resource is NW_OUT, candidate replicas consider only the leaders -- i.e. only the leaders have NW_OUT load,
    // otherwise all replicas on broker are considered.
    Set<Replica> coveredReplicas = resource() == Resource.NW_OUT ? broker.leaderReplicas() : broker.replicas();
    // The given load limit determines the lower cutoff in descending order, upper cutoff in ascending order.
    if (isAscending) {
        candidateReplicas.addAll(coveredReplicas.stream().filter(r -> !shouldExclude(r, excludedTopics) && r.load().expectedUtilizationFor(resource()) < loadLimit).collect(Collectors.toSet()));
    } else {
        candidateReplicas.addAll(coveredReplicas.stream().filter(r -> !shouldExclude(r, excludedTopics) && r.load().expectedUtilizationFor(resource()) > loadLimit).collect(Collectors.toSet()));
    }
    return candidateReplicas;
}
Also used : TreeSet(java.util.TreeSet) Replica(com.linkedin.kafka.cruisecontrol.model.Replica) BalancingConstraint(com.linkedin.kafka.cruisecontrol.analyzer.BalancingConstraint)

Example 30 with Replica

use of com.linkedin.kafka.cruisecontrol.model.Replica 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();
}
Also used : Broker(com.linkedin.kafka.cruisecontrol.model.Broker) TreeSet(java.util.TreeSet) Replica(com.linkedin.kafka.cruisecontrol.model.Replica)

Aggregations

Replica (com.linkedin.kafka.cruisecontrol.model.Replica)40 Broker (com.linkedin.kafka.cruisecontrol.model.Broker)26 BalancingConstraint (com.linkedin.kafka.cruisecontrol.analyzer.BalancingConstraint)13 OptimizationFailureException (com.linkedin.kafka.cruisecontrol.exception.OptimizationFailureException)12 ClusterModel (com.linkedin.kafka.cruisecontrol.model.ClusterModel)9 HashSet (java.util.HashSet)9 TreeSet (java.util.TreeSet)8 Resource (com.linkedin.kafka.cruisecontrol.common.Resource)7 ActionAcceptance (com.linkedin.kafka.cruisecontrol.analyzer.ActionAcceptance)6 ActionType (com.linkedin.kafka.cruisecontrol.analyzer.ActionType)6 BalancingAction (com.linkedin.kafka.cruisecontrol.analyzer.BalancingAction)6 ArrayList (java.util.ArrayList)6 List (java.util.List)6 ACCEPT (com.linkedin.kafka.cruisecontrol.analyzer.ActionAcceptance.ACCEPT)5 REPLICA_REJECT (com.linkedin.kafka.cruisecontrol.analyzer.ActionAcceptance.REPLICA_REJECT)5 ClusterModelStats (com.linkedin.kafka.cruisecontrol.model.ClusterModelStats)5 ModelCompletenessRequirements (com.linkedin.kafka.cruisecontrol.monitor.ModelCompletenessRequirements)5 Set (java.util.Set)5 SortedSet (java.util.SortedSet)5 Collectors (java.util.stream.Collectors)5