Search in sources :

Example 1 with BalancerStrategy

use of org.apache.druid.server.coordinator.BalancerStrategy in project druid by druid-io.

the class BalanceSegments method balanceServers.

private Pair<Integer, Integer> balanceServers(DruidCoordinatorRuntimeParams params, List<ServerHolder> toMoveFrom, List<ServerHolder> toMoveTo, int maxSegmentsToMove) {
    if (maxSegmentsToMove <= 0) {
        log.debug("maxSegmentsToMove is 0; no balancing work can be performed.");
        return new Pair<>(0, 0);
    } else if (toMoveFrom.isEmpty()) {
        log.debug("toMoveFrom is empty; no balancing work can be performed.");
        return new Pair<>(0, 0);
    } else if (toMoveTo.isEmpty()) {
        log.debug("toMoveTo is empty; no balancing work can be peformed.");
        return new Pair<>(0, 0);
    }
    final BalancerStrategy strategy = params.getBalancerStrategy();
    final int maxIterations = 2 * maxSegmentsToMove;
    final int maxToLoad = params.getCoordinatorDynamicConfig().getMaxSegmentsInNodeLoadingQueue();
    int moved = 0, unmoved = 0;
    Iterator<BalancerSegmentHolder> segmentsToMove;
    // The pick method depends on if the operator has enabled batched segment sampling in the Coorinator dynamic config.
    if (params.getCoordinatorDynamicConfig().useBatchedSegmentSampler()) {
        segmentsToMove = strategy.pickSegmentsToMove(toMoveFrom, params.getBroadcastDatasources(), maxSegmentsToMove);
    } else {
        segmentsToMove = strategy.pickSegmentsToMove(toMoveFrom, params.getBroadcastDatasources(), params.getCoordinatorDynamicConfig().getPercentOfSegmentsToConsiderPerMove());
    }
    // noinspection ForLoopThatDoesntUseLoopVariable
    for (int iter = 0; (moved + unmoved) < maxSegmentsToMove; ++iter) {
        if (!segmentsToMove.hasNext()) {
            log.info("All servers to move segments from are empty, ending run.");
            break;
        }
        final BalancerSegmentHolder segmentToMoveHolder = segmentsToMove.next();
        // DruidCoordinatorRuntimeParams.getUsedSegments originate from SegmentsMetadataManager, i. e. that's a set of segments
        // that *should* be loaded. segmentToMoveHolder.getSegment originates from ServerInventoryView,  i. e. that may be
        // any segment that happens to be loaded on some server, even if it is not used. (Coordinator closes such
        // discrepancies eventually via UnloadUnusedSegments). Therefore the picked segmentToMoveHolder's segment may not
        // need to be balanced.
        boolean needToBalancePickedSegment = params.getUsedSegments().contains(segmentToMoveHolder.getSegment());
        if (needToBalancePickedSegment) {
            final DataSegment segmentToMove = segmentToMoveHolder.getSegment();
            final ImmutableDruidServer fromServer = segmentToMoveHolder.getFromServer();
            // we want to leave the server the segment is currently on in the list...
            // but filter out replicas that are already serving the segment, and servers with a full load queue
            final List<ServerHolder> toMoveToWithLoadQueueCapacityAndNotServingSegment = toMoveTo.stream().filter(s -> s.getServer().equals(fromServer) || (!s.isServingSegment(segmentToMove) && (maxToLoad <= 0 || s.getNumberOfSegmentsInQueue() < maxToLoad))).collect(Collectors.toList());
            if (toMoveToWithLoadQueueCapacityAndNotServingSegment.size() > 0) {
                final ServerHolder destinationHolder = strategy.findNewSegmentHomeBalancer(segmentToMove, toMoveToWithLoadQueueCapacityAndNotServingSegment);
                if (destinationHolder != null && !destinationHolder.getServer().equals(fromServer)) {
                    if (moveSegment(segmentToMoveHolder, destinationHolder.getServer(), params)) {
                        moved++;
                    } else {
                        unmoved++;
                    }
                } else {
                    log.debug("Segment [%s] is 'optimally' placed.", segmentToMove.getId());
                    unmoved++;
                }
            } else {
                log.debug("No valid movement destinations for segment [%s].", segmentToMove.getId());
                unmoved++;
            }
        }
        if (iter >= maxIterations) {
            log.info("Unable to select %d remaining candidate segments out of %d total to balance " + "after %d iterations, ending run.", (maxSegmentsToMove - moved - unmoved), maxSegmentsToMove, iter);
            break;
        }
    }
    return new Pair<>(moved, unmoved);
}
Also used : EmittingLogger(org.apache.druid.java.util.emitter.EmittingLogger) Iterator(java.util.Iterator) SortedSet(java.util.SortedSet) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) StringUtils(org.apache.druid.java.util.common.StringUtils) DruidCoordinatorRuntimeParams(org.apache.druid.server.coordinator.DruidCoordinatorRuntimeParams) DruidCoordinator(org.apache.druid.server.coordinator.DruidCoordinator) LoadPeonCallback(org.apache.druid.server.coordinator.LoadPeonCallback) HashMap(java.util.HashMap) NavigableSet(java.util.NavigableSet) CoordinatorStats(org.apache.druid.server.coordinator.CoordinatorStats) Collectors(java.util.stream.Collectors) Pair(org.apache.druid.java.util.common.Pair) ConcurrentMap(java.util.concurrent.ConcurrentMap) List(java.util.List) Lists(com.google.common.collect.Lists) BalancerStrategy(org.apache.druid.server.coordinator.BalancerStrategy) Map(java.util.Map) DataSegment(org.apache.druid.timeline.DataSegment) BalancerSegmentHolder(org.apache.druid.server.coordinator.BalancerSegmentHolder) LoadQueuePeon(org.apache.druid.server.coordinator.LoadQueuePeon) ServerHolder(org.apache.druid.server.coordinator.ServerHolder) SegmentId(org.apache.druid.timeline.SegmentId) ImmutableDruidServer(org.apache.druid.client.ImmutableDruidServer) BalancerStrategy(org.apache.druid.server.coordinator.BalancerStrategy) ServerHolder(org.apache.druid.server.coordinator.ServerHolder) BalancerSegmentHolder(org.apache.druid.server.coordinator.BalancerSegmentHolder) DataSegment(org.apache.druid.timeline.DataSegment) ImmutableDruidServer(org.apache.druid.client.ImmutableDruidServer) Pair(org.apache.druid.java.util.common.Pair)

Example 2 with BalancerStrategy

use of org.apache.druid.server.coordinator.BalancerStrategy in project druid by druid-io.

the class BalanceSegments method balanceTier.

private void balanceTier(DruidCoordinatorRuntimeParams params, String tier, SortedSet<ServerHolder> servers, CoordinatorStats stats) {
    if (params.getUsedSegments().size() == 0) {
        log.info("Metadata segments are not available. Cannot balance.");
        // suppress emit zero stats
        return;
    }
    currentlyMovingSegments.computeIfAbsent(tier, t -> new ConcurrentHashMap<>());
    if (!currentlyMovingSegments.get(tier).isEmpty()) {
        reduceLifetimes(tier);
        log.info("[%s]: Still waiting on %,d segments to be moved. Skipping balance.", tier, currentlyMovingSegments.get(tier).size());
        // suppress emit zero stats
        return;
    }
    /*
      Take as many segments from decommissioning servers as decommissioningMaxPercentOfMaxSegmentsToMove allows and find
      the best location for them on active servers. After that, balance segments within active servers pool.
     */
    Map<Boolean, List<ServerHolder>> partitions = servers.stream().collect(Collectors.partitioningBy(ServerHolder::isDecommissioning));
    final List<ServerHolder> decommissioningServers = partitions.get(true);
    final List<ServerHolder> activeServers = partitions.get(false);
    log.info("Found %d active servers, %d decommissioning servers", activeServers.size(), decommissioningServers.size());
    if ((decommissioningServers.isEmpty() && activeServers.size() <= 1) || activeServers.isEmpty()) {
        log.warn("[%s]: insufficient active servers. Cannot balance.", tier);
        // suppress emit zero stats
        return;
    }
    int numSegments = 0;
    for (ServerHolder sourceHolder : servers) {
        numSegments += sourceHolder.getServer().getNumSegments();
    }
    if (numSegments == 0) {
        log.info("No segments found. Cannot balance.");
        // suppress emit zero stats
        return;
    }
    final int maxSegmentsToMove = Math.min(params.getCoordinatorDynamicConfig().getMaxSegmentsToMove(), numSegments);
    // Prioritize moving segments from decomissioning servers.
    int decommissioningMaxPercentOfMaxSegmentsToMove = params.getCoordinatorDynamicConfig().getDecommissioningMaxPercentOfMaxSegmentsToMove();
    int maxSegmentsToMoveFromDecommissioningNodes = (int) Math.ceil(maxSegmentsToMove * (decommissioningMaxPercentOfMaxSegmentsToMove / 100.0));
    log.info("Processing %d segments for moving from decommissioning servers", maxSegmentsToMoveFromDecommissioningNodes);
    Pair<Integer, Integer> decommissioningResult = balanceServers(params, decommissioningServers, activeServers, maxSegmentsToMoveFromDecommissioningNodes);
    // After moving segments from decomissioning servers, move the remaining segments from the rest of the servers.
    int maxGeneralSegmentsToMove = maxSegmentsToMove - decommissioningResult.lhs;
    log.info("Processing %d segments for balancing between active servers", maxGeneralSegmentsToMove);
    Pair<Integer, Integer> generalResult = balanceServers(params, activeServers, activeServers, maxGeneralSegmentsToMove);
    int moved = generalResult.lhs + decommissioningResult.lhs;
    int unmoved = generalResult.rhs + decommissioningResult.rhs;
    if (unmoved == maxSegmentsToMove) {
        // Cluster should be alive and constantly adjusting
        log.info("No good moves found in tier [%s]", tier);
    }
    stats.addToTieredStat("unmovedCount", tier, unmoved);
    stats.addToTieredStat("movedCount", tier, moved);
    if (params.getCoordinatorDynamicConfig().emitBalancingStats()) {
        final BalancerStrategy strategy = params.getBalancerStrategy();
        strategy.emitStats(tier, stats, Lists.newArrayList(servers));
    }
    log.info("[%s]: Segments Moved: [%d] Segments Let Alone: [%d]", tier, moved, unmoved);
}
Also used : BalancerStrategy(org.apache.druid.server.coordinator.BalancerStrategy) ServerHolder(org.apache.druid.server.coordinator.ServerHolder) List(java.util.List)

Example 3 with BalancerStrategy

use of org.apache.druid.server.coordinator.BalancerStrategy in project druid by druid-io.

the class LoadRuleTest method setUp.

@Before
public void setUp() {
    EmittingLogger.registerEmitter(EMITTER);
    EMITTER.start();
    throttler = EasyMock.createMock(ReplicationThrottler.class);
    exec = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(1));
    balancerStrategy = new CostBalancerStrategyFactory().createBalancerStrategy(exec);
    cachingCostBalancerStrategy = new CachingCostBalancerStrategy(ClusterCostCache.builder().build(), exec);
    mockBalancerStrategy = EasyMock.createMock(BalancerStrategy.class);
}
Also used : BalancerStrategy(org.apache.druid.server.coordinator.BalancerStrategy) CachingCostBalancerStrategy(org.apache.druid.server.coordinator.CachingCostBalancerStrategy) ReplicationThrottler(org.apache.druid.server.coordinator.ReplicationThrottler) CostBalancerStrategyFactory(org.apache.druid.server.coordinator.CostBalancerStrategyFactory) CachingCostBalancerStrategy(org.apache.druid.server.coordinator.CachingCostBalancerStrategy) Before(org.junit.Before)

Aggregations

BalancerStrategy (org.apache.druid.server.coordinator.BalancerStrategy)3 List (java.util.List)2 ServerHolder (org.apache.druid.server.coordinator.ServerHolder)2 Lists (com.google.common.collect.Lists)1 HashMap (java.util.HashMap)1 Iterator (java.util.Iterator)1 Map (java.util.Map)1 NavigableSet (java.util.NavigableSet)1 SortedSet (java.util.SortedSet)1 ConcurrentHashMap (java.util.concurrent.ConcurrentHashMap)1 ConcurrentMap (java.util.concurrent.ConcurrentMap)1 Collectors (java.util.stream.Collectors)1 ImmutableDruidServer (org.apache.druid.client.ImmutableDruidServer)1 Pair (org.apache.druid.java.util.common.Pair)1 StringUtils (org.apache.druid.java.util.common.StringUtils)1 EmittingLogger (org.apache.druid.java.util.emitter.EmittingLogger)1 BalancerSegmentHolder (org.apache.druid.server.coordinator.BalancerSegmentHolder)1 CachingCostBalancerStrategy (org.apache.druid.server.coordinator.CachingCostBalancerStrategy)1 CoordinatorStats (org.apache.druid.server.coordinator.CoordinatorStats)1 CostBalancerStrategyFactory (org.apache.druid.server.coordinator.CostBalancerStrategyFactory)1