Search in sources :

Example 11 with ResourceUnit

use of org.apache.pulsar.broker.loadbalance.ResourceUnit in project incubator-pulsar by apache.

the class SimpleLoadManagerImpl method doLoadRanking.

/**
 * Rank brokers by available capacity, or load percentage, based on placement strategy:
 *
 * - Available capacity for weighted random selection (weightedRandomSelection): ranks ResourceUnits units based on
 * estimation of their capacity which is basically how many bundles each ResourceUnit is able can handle with its
 * available resources (CPU, memory, network, etc);
 *
 * - Load percentage for least loaded server (leastLoadedServer): ranks ResourceUnits units based on estimation of
 * their load percentage which is basically how many percent of resource is allocated which is
 * max(resource_actually_used, resource_quota)
 *
 * If we fail to collect the Load Reports OR fail to process them for the first time, it means the leader does not
 * have enough information to make a decision so we set it to ready when we collect and process the load reports
 * successfully the first time.
 */
private synchronized void doLoadRanking() {
    ResourceUnitRanking.setCpuUsageByMsgRate(this.realtimeCpuLoadFactor);
    String hostname = pulsar.getAdvertisedAddress();
    String strategy = this.getLoadBalancerPlacementStrategy();
    log.info("doLoadRanking - load balancing strategy: {}", strategy);
    if (!currentLoadReports.isEmpty()) {
        Map<Long, Set<ResourceUnit>> newSortedRankings = Maps.newTreeMap();
        Map<ResourceUnit, ResourceUnitRanking> newResourceUnitRankings = new HashMap<>();
        for (Map.Entry<ResourceUnit, LoadReport> entry : currentLoadReports.entrySet()) {
            ResourceUnit resourceUnit = entry.getKey();
            LoadReport loadReport = entry.getValue();
            // calculate rankings
            Set<String> loadedBundles = loadReport.getBundles();
            Set<String> preAllocatedBundles = null;
            if (resourceUnitRankings.containsKey(resourceUnit)) {
                preAllocatedBundles = resourceUnitRankings.get(resourceUnit).getPreAllocatedBundles();
                preAllocatedBundles.removeAll(loadedBundles);
            } else {
                preAllocatedBundles = new HashSet<>();
            }
            ResourceQuota allocatedQuota = getTotalAllocatedQuota(loadedBundles);
            ResourceQuota preAllocatedQuota = getTotalAllocatedQuota(preAllocatedBundles);
            ResourceUnitRanking ranking = new ResourceUnitRanking(loadReport.getSystemResourceUsage(), loadedBundles, allocatedQuota, preAllocatedBundles, preAllocatedQuota);
            newResourceUnitRankings.put(resourceUnit, ranking);
            // generated sorted ranking
            double loadPercentage = ranking.getEstimatedLoadPercentage();
            long maxCapacity = ranking.estimateMaxCapacity(pulsar.getLocalZkCacheService().getResourceQuotaCache().getDefaultQuota());
            long finalRank = 0;
            if (strategy.equals(LOADBALANCER_STRATEGY_LLS)) {
                finalRank = (long) loadPercentage;
            } else if (strategy.equals(LOADBALANCER_STRATEGY_LEAST_MSG)) {
                finalRank = (long) ranking.getEstimatedMessageRate();
            } else {
                double idleRatio = (100 - loadPercentage) / 100;
                finalRank = (long) (maxCapacity * idleRatio * idleRatio);
            }
            if (!newSortedRankings.containsKey(finalRank)) {
                newSortedRankings.put(finalRank, new HashSet<ResourceUnit>());
            }
            newSortedRankings.get(finalRank).add(entry.getKey());
            if (log.isDebugEnabled()) {
                log.debug("Added Resource Unit [{}] with Rank [{}]", entry.getKey().getResourceId(), finalRank);
            }
            // update metrics
            if (resourceUnit.getResourceId().contains(hostname)) {
                updateLoadBalancingMetrics(hostname, finalRank, ranking);
            }
        }
        updateBrokerToNamespaceToBundle();
        this.sortedRankings.set(newSortedRankings);
        this.resourceUnitRankings = newResourceUnitRankings;
    } else {
        log.info("Leader broker[{}] No ResourceUnits to rank this run, Using Old Ranking", pulsar.getWebServiceAddress());
    }
}
Also used : Set(java.util.Set) HashSet(java.util.HashSet) HashMap(java.util.HashMap) ResourceUnit(org.apache.pulsar.broker.loadbalance.ResourceUnit) ResourceQuota(org.apache.pulsar.common.policies.data.ResourceQuota) LoadReport(org.apache.pulsar.policies.data.loadbalancer.LoadReport) ResourceUnitRanking(org.apache.pulsar.policies.data.loadbalancer.ResourceUnitRanking) Map(java.util.Map) HashMap(java.util.HashMap) TreeMap(java.util.TreeMap)

Example 12 with ResourceUnit

use of org.apache.pulsar.broker.loadbalance.ResourceUnit in project incubator-pulsar by apache.

the class SimpleLoadManagerImpl method doLoadShedding.

@Override
public void doLoadShedding() {
    long overloadThreshold = this.getLoadBalancerBrokerOverloadedThresholdPercentage();
    long comfortLoadLevel = this.getLoadBalancerBrokerComfortLoadThresholdPercentage();
    log.info("Running load shedding task as leader broker, overload threshold {}, comfort loadlevel {}", overloadThreshold, comfortLoadLevel);
    // overloadedRU --> bundleName
    Map<ResourceUnit, String> namespaceBundlesToBeUnloaded = new HashMap<>();
    synchronized (currentLoadReports) {
        for (Map.Entry<ResourceUnit, LoadReport> entry : currentLoadReports.entrySet()) {
            ResourceUnit overloadedRU = entry.getKey();
            LoadReport lr = entry.getValue();
            if (isAboveLoadLevel(lr.getSystemResourceUsage(), overloadThreshold)) {
                ResourceType bottleneckResourceType = lr.getBottleneckResourceType();
                Map<String, NamespaceBundleStats> bundleStats = lr.getSortedBundleStats(bottleneckResourceType);
                if (bundleStats == null) {
                    log.warn("Null bundle stats for bundle {}", lr.getName());
                    continue;
                }
                // 1. owns only one namespace
                if (bundleStats.size() == 1) {
                    // can't unload one namespace, just issue a warning message
                    String bundleName = lr.getBundleStats().keySet().iterator().next();
                    log.warn("HIGH USAGE WARNING : Sole namespace bundle {} is overloading broker {}. " + "No Load Shedding will be done on this broker", bundleName, overloadedRU.getResourceId());
                    continue;
                }
                for (Map.Entry<String, NamespaceBundleStats> bundleStat : bundleStats.entrySet()) {
                    String bundleName = bundleStat.getKey();
                    NamespaceBundleStats stats = bundleStat.getValue();
                    // We need at least one underloaded RU from list of candidates that can host this bundle
                    if (isBrokerAvailableForRebalancing(bundleStat.getKey(), comfortLoadLevel)) {
                        log.info("Namespace bundle {} will be unloaded from overloaded broker {}, bundle stats (topics: {}, producers {}, " + "consumers {}, bandwidthIn {}, bandwidthOut {})", bundleName, overloadedRU.getResourceId(), stats.topics, stats.producerCount, stats.consumerCount, stats.msgThroughputIn, stats.msgThroughputOut);
                        namespaceBundlesToBeUnloaded.put(overloadedRU, bundleName);
                    } else {
                        log.info("Unable to shed load from broker {}, no brokers with enough capacity available " + "for re-balancing {}", overloadedRU.getResourceId(), bundleName);
                    }
                    break;
                }
            }
        }
    }
    unloadNamespacesFromOverLoadedBrokers(namespaceBundlesToBeUnloaded);
}
Also used : ResourceUnit(org.apache.pulsar.broker.loadbalance.ResourceUnit) NamespaceBundleStats(org.apache.pulsar.policies.data.loadbalancer.NamespaceBundleStats) HashMap(java.util.HashMap) LoadReport(org.apache.pulsar.policies.data.loadbalancer.LoadReport) ResourceType(org.apache.pulsar.policies.data.loadbalancer.SystemResourceUsage.ResourceType) Map(java.util.Map) HashMap(java.util.HashMap) TreeMap(java.util.TreeMap)

Example 13 with ResourceUnit

use of org.apache.pulsar.broker.loadbalance.ResourceUnit in project incubator-pulsar by apache.

the class SimpleLoadManagerImpl method getFinalCandidates.

private Multimap<Long, ResourceUnit> getFinalCandidates(ServiceUnitId serviceUnit, Map<Long, Set<ResourceUnit>> availableBrokers) {
    synchronized (brokerCandidateCache) {
        final Multimap<Long, ResourceUnit> result = TreeMultimap.create();
        availableBrokersCache.clear();
        for (final Set<ResourceUnit> resourceUnits : availableBrokers.values()) {
            for (final ResourceUnit resourceUnit : resourceUnits) {
                availableBrokersCache.add(resourceUnit.getResourceId().replace("http://", ""));
            }
        }
        brokerCandidateCache.clear();
        try {
            LoadManagerShared.applyNamespacePolicies(serviceUnit, policies, brokerCandidateCache, availableBrokersCache, brokerTopicLoadingPredicate);
        } catch (Exception e) {
            log.warn("Error when trying to apply policies: {}", e);
            for (final Map.Entry<Long, Set<ResourceUnit>> entry : availableBrokers.entrySet()) {
                result.putAll(entry.getKey(), entry.getValue());
            }
            return result;
        }
        // As long as there is at least one broker left, this will always leave brokerCandidateCache non-empty.
        LoadManagerShared.removeMostServicingBrokersForNamespace(serviceUnit.toString(), brokerCandidateCache, brokerToNamespaceToBundleRange);
        // After LoadManagerShared is finished applying the filter, put the results back into a multimap.
        for (final Map.Entry<Long, Set<ResourceUnit>> entry : availableBrokers.entrySet()) {
            final Long rank = entry.getKey();
            final Set<ResourceUnit> resourceUnits = entry.getValue();
            for (final ResourceUnit resourceUnit : resourceUnits) {
                if (brokerCandidateCache.contains(resourceUnit.getResourceId().replace("http://", ""))) {
                    result.put(rank, resourceUnit);
                }
            }
        }
        return result;
    }
}
Also used : ResourceUnit(org.apache.pulsar.broker.loadbalance.ResourceUnit) Set(java.util.Set) HashSet(java.util.HashSet) Map(java.util.Map) HashMap(java.util.HashMap) TreeMap(java.util.TreeMap) KeeperException(org.apache.zookeeper.KeeperException) IOException(java.io.IOException) PulsarServerException(org.apache.pulsar.broker.PulsarServerException)

Example 14 with ResourceUnit

use of org.apache.pulsar.broker.loadbalance.ResourceUnit in project incubator-pulsar by apache.

the class SimpleLoadManagerImpl method isBrokerAvailableForRebalancing.

// todo: changeme: this can be optimized, we don't have to iterate through everytime
private boolean isBrokerAvailableForRebalancing(String bundleName, long maxLoadLevel) {
    NamespaceName namespaceName = NamespaceName.get(LoadManagerShared.getNamespaceNameFromBundleName(bundleName));
    Map<Long, Set<ResourceUnit>> availableBrokers = sortedRankings.get();
    // this does not have "http://" in front, hacky but no time to pretty up
    Multimap<Long, ResourceUnit> brokers = getFinalCandidates(namespaceName, availableBrokers);
    for (Object broker : brokers.values()) {
        ResourceUnit underloadedRU = (ResourceUnit) broker;
        LoadReport currentLoadReport = currentLoadReports.get(underloadedRU);
        if (isBelowLoadLevel(currentLoadReport.getSystemResourceUsage(), maxLoadLevel)) {
            return true;
        }
    }
    return false;
}
Also used : ResourceUnit(org.apache.pulsar.broker.loadbalance.ResourceUnit) NamespaceName(org.apache.pulsar.common.naming.NamespaceName) Set(java.util.Set) HashSet(java.util.HashSet) LoadReport(org.apache.pulsar.policies.data.loadbalancer.LoadReport)

Example 15 with ResourceUnit

use of org.apache.pulsar.broker.loadbalance.ResourceUnit in project incubator-pulsar by apache.

the class WRRPlacementStrategy method findBrokerForPlacement.

/**
 * <code>
 * Function : getByWeightedRoundRobin
 *            returns ResourceUnit selected by WRR algorithm based on available resource on RU
 * ^
 * |
 * |
 * |
 * |                |                        |                                |     |
 * |                |                        |                                |     |
 * |   Broker 2     |       Broker 3         |         Broker 1               |  B4 |
 * |                |                        |                                |     |
 * +----------------+------------------------+--------------------------------+--------->
 * 0                20                       50                               90    100
 *
 * This is weighted Round robin, we calculate weight based on availability of resources;
 * total availability is taken as a full range then each broker is given range based on
 *  its resource availability, if the number generated within total range happens to be in
 * broker's range, that broker is selected
 * </code>
 */
public ResourceUnit findBrokerForPlacement(Multimap<Long, ResourceUnit> finalCandidates) {
    if (finalCandidates.isEmpty()) {
        return null;
    }
    log.debug("Total Final Candidates selected - [{}]", finalCandidates.size());
    int totalAvailability = 0;
    for (Map.Entry<Long, ResourceUnit> candidateOwner : finalCandidates.entries()) {
        totalAvailability += candidateOwner.getKey().intValue();
    }
    ResourceUnit selectedRU = null;
    if (totalAvailability <= 0) {
        // for now, pick anyone and return that one, because when we don't have ranking we put O for each broker
        return Iterables.get(finalCandidates.get(0L), rand.nextInt(finalCandidates.size()));
    }
    int weightedSelector = rand.nextInt(totalAvailability);
    log.debug("Generated Weighted Selector Number - [{}] ", weightedSelector);
    int weightRangeSoFar = 0;
    for (Map.Entry<Long, ResourceUnit> candidateOwner : finalCandidates.entries()) {
        weightRangeSoFar += candidateOwner.getKey();
        if (weightedSelector < weightRangeSoFar) {
            selectedRU = candidateOwner.getValue();
            log.debug(" Weighted Round Robin Selected RU - [{}]", candidateOwner.getValue().getResourceId());
            break;
        }
    }
    return selectedRU;
}
Also used : ResourceUnit(org.apache.pulsar.broker.loadbalance.ResourceUnit) Map(java.util.Map)

Aggregations

ResourceUnit (org.apache.pulsar.broker.loadbalance.ResourceUnit)15 Map (java.util.Map)10 HashMap (java.util.HashMap)9 IOException (java.io.IOException)8 LoadReport (org.apache.pulsar.policies.data.loadbalancer.LoadReport)8 Set (java.util.Set)7 TreeMap (java.util.TreeMap)7 AtomicReference (java.util.concurrent.atomic.AtomicReference)6 HashSet (java.util.HashSet)5 PulsarServerException (org.apache.pulsar.broker.PulsarServerException)5 KeeperException (org.apache.zookeeper.KeeperException)5 Lists (com.google.common.collect.Lists)4 Sets (com.google.common.collect.Sets)4 Field (java.lang.reflect.Field)4 Optional (java.util.Optional)4 TimeUnit (java.util.concurrent.TimeUnit)4 LoadManager (org.apache.pulsar.broker.loadbalance.LoadManager)4 NamespaceBundle (org.apache.pulsar.common.naming.NamespaceBundle)4 ResourceQuota (org.apache.pulsar.common.policies.data.ResourceQuota)4 SystemResourceUsage (org.apache.pulsar.policies.data.loadbalancer.SystemResourceUsage)4