Search in sources :

Example 1 with ResourceQuota

use of org.apache.pulsar.common.policies.data.ResourceQuota in project incubator-pulsar by apache.

the class ModularLoadManagerImpl method getBundleDataOrDefault.

// Attempt to local the data for the given bundle in ZooKeeper.
// If it cannot be found, return the default bundle data.
private BundleData getBundleDataOrDefault(final String bundle) {
    BundleData bundleData = null;
    try {
        final String bundleZPath = getBundleDataZooKeeperPath(bundle);
        final String quotaZPath = String.format("%s/%s", RESOURCE_QUOTA_ZPATH, bundle);
        if (zkClient.exists(bundleZPath, null) != null) {
            bundleData = readJson(zkClient.getData(bundleZPath, null, null), BundleData.class);
        } else if (zkClient.exists(quotaZPath, null) != null) {
            final ResourceQuota quota = readJson(zkClient.getData(quotaZPath, null, null), ResourceQuota.class);
            bundleData = new BundleData(NUM_SHORT_SAMPLES, NUM_LONG_SAMPLES);
            // Initialize from existing resource quotas if new API ZNodes do not exist.
            final TimeAverageMessageData shortTermData = bundleData.getShortTermData();
            final TimeAverageMessageData longTermData = bundleData.getLongTermData();
            shortTermData.setMsgRateIn(quota.getMsgRateIn());
            shortTermData.setMsgRateOut(quota.getMsgRateOut());
            shortTermData.setMsgThroughputIn(quota.getBandwidthIn());
            shortTermData.setMsgThroughputOut(quota.getBandwidthOut());
            longTermData.setMsgRateIn(quota.getMsgRateIn());
            longTermData.setMsgRateOut(quota.getMsgRateOut());
            longTermData.setMsgThroughputIn(quota.getBandwidthIn());
            longTermData.setMsgThroughputOut(quota.getBandwidthOut());
            // Assume ample history.
            shortTermData.setNumSamples(NUM_SHORT_SAMPLES);
            longTermData.setNumSamples(NUM_LONG_SAMPLES);
        }
    } catch (Exception e) {
        log.warn("Error when trying to find bundle {} on zookeeper: {}", bundle, e);
    }
    if (bundleData == null) {
        bundleData = new BundleData(NUM_SHORT_SAMPLES, NUM_LONG_SAMPLES, defaultStats);
    }
    return bundleData;
}
Also used : ResourceQuota(org.apache.pulsar.common.policies.data.ResourceQuota) TimeAverageMessageData(org.apache.pulsar.broker.TimeAverageMessageData) BundleData(org.apache.pulsar.broker.BundleData) BrokerFilterException(org.apache.pulsar.broker.loadbalance.BrokerFilterException) KeeperException(org.apache.zookeeper.KeeperException) IOException(java.io.IOException) NoNodeException(org.apache.zookeeper.KeeperException.NoNodeException) PulsarServerException(org.apache.pulsar.broker.PulsarServerException)

Example 2 with ResourceQuota

use of org.apache.pulsar.common.policies.data.ResourceQuota in project incubator-pulsar by apache.

the class SimpleLoadManagerImpl method timeSmoothQuota.

private ResourceQuota timeSmoothQuota(ResourceQuota oldQuota, double msgRateIn, double msgRateOut, double bandwidthIn, double bandwidthOut, double memory, long timePast) {
    if (oldQuota.getDynamic()) {
        ResourceQuota newQuota = new ResourceQuota();
        newQuota.setMsgRateIn(timeSmoothValue(oldQuota.getMsgRateIn(), msgRateIn, RESOURCE_QUOTA_MIN_MSGRATE_IN, RESOURCE_QUOTA_MAX_MSGRATE_IN, timePast));
        newQuota.setMsgRateOut(timeSmoothValue(oldQuota.getMsgRateOut(), msgRateOut, RESOURCE_QUOTA_MIN_MSGRATE_OUT, RESOURCE_QUOTA_MAX_MSGRATE_OUT, timePast));
        newQuota.setBandwidthIn(timeSmoothValue(oldQuota.getBandwidthIn(), bandwidthIn, RESOURCE_QUOTA_MIN_BANDWIDTH_IN, RESOURCE_QUOTA_MAX_BANDWIDTH_IN, timePast));
        newQuota.setBandwidthOut(timeSmoothValue(oldQuota.getBandwidthOut(), bandwidthOut, RESOURCE_QUOTA_MIN_BANDWIDTH_OUT, RESOURCE_QUOTA_MAX_BANDWIDTH_OUT, timePast));
        newQuota.setMemory(timeSmoothValue(oldQuota.getMemory(), memory, RESOURCE_QUOTA_MIN_MEMORY, RESOURCE_QUOTA_MAX_MEMORY, timePast));
        return newQuota;
    } else {
        return oldQuota;
    }
}
Also used : ResourceQuota(org.apache.pulsar.common.policies.data.ResourceQuota)

Example 3 with ResourceQuota

use of org.apache.pulsar.common.policies.data.ResourceQuota in project incubator-pulsar by apache.

the class SimpleLoadManagerImpl method updateRealtimeResourceQuota.

private synchronized void updateRealtimeResourceQuota() {
    long memObjectGroupSize = 500;
    if (!currentLoadReports.isEmpty()) {
        long totalBundles = 0;
        long totalMemGroups = 0;
        double totalMsgRateIn = 0.0;
        double totalMsgRateOut = 0.0;
        double totalMsgRate = 0.0;
        double totalCpuUsage = 0.0;
        double totalMemoryUsage = 0.0;
        double totalBandwidthIn = 0.0;
        double totalBandwidthOut = 0.0;
        long loadReportTimestamp = -1;
        // update resource factors
        for (Map.Entry<ResourceUnit, LoadReport> entry : currentLoadReports.entrySet()) {
            LoadReport loadReport = entry.getValue();
            if (loadReport.getTimestamp() > loadReportTimestamp) {
                loadReportTimestamp = loadReport.getTimestamp();
            }
            Map<String, NamespaceBundleStats> bundleStats = loadReport.getBundleStats();
            if (bundleStats == null) {
                continue;
            }
            for (Map.Entry<String, NamespaceBundleStats> statsEntry : bundleStats.entrySet()) {
                totalBundles++;
                NamespaceBundleStats stats = statsEntry.getValue();
                totalMemGroups += (1 + (stats.topics + stats.producerCount + stats.consumerCount) / memObjectGroupSize);
                totalBandwidthIn += stats.msgThroughputIn;
                totalBandwidthOut += stats.msgThroughputOut;
            }
            SystemResourceUsage resUsage = loadReport.getSystemResourceUsage();
            totalMsgRateIn += loadReport.getMsgRateIn();
            totalMsgRateOut += loadReport.getMsgRateOut();
            totalCpuUsage = totalCpuUsage + resUsage.getCpu().usage;
            totalMemoryUsage = totalMemoryUsage + resUsage.getMemory().usage;
        }
        totalMsgRate = totalMsgRateIn + totalMsgRateOut;
        long timePast = loadReportTimestamp - this.lastResourceQuotaUpdateTimestamp;
        this.lastResourceQuotaUpdateTimestamp = loadReportTimestamp;
        if (totalMsgRate > 1000 && totalMemGroups > 30) {
            this.realtimeCpuLoadFactor = timeSmoothValue(this.realtimeCpuLoadFactor, totalCpuUsage / totalMsgRate, RESOURCE_QUOTA_MIN_CPU_FACTOR, RESOURCE_QUOTA_MAX_CPU_FACTOR, timePast);
            this.realtimeMemoryLoadFactor = timeSmoothValue(this.realtimeMemoryLoadFactor, totalMemoryUsage / totalMemGroups, RESOURCE_QUOTA_MIN_MEM_FACTOR, RESOURCE_QUOTA_MAX_MEM_FACTOR, timePast);
        }
        // calculate average bundle
        if (totalBundles > 30 && this.realtimeAvgResourceQuota.getDynamic()) {
            ResourceQuota oldQuota = this.realtimeAvgResourceQuota;
            ResourceQuota newQuota = timeSmoothQuota(oldQuota, totalMsgRateIn / totalBundles, totalMsgRateOut / totalBundles, totalBandwidthIn / totalBundles, totalBandwidthOut / totalBundles, totalMemoryUsage / totalBundles, timePast);
            this.realtimeAvgResourceQuota = newQuota;
        }
        // update realtime quota for each bundle
        Map<String, ResourceQuota> newQuotas = new HashMap<>();
        for (Map.Entry<ResourceUnit, LoadReport> entry : currentLoadReports.entrySet()) {
            ResourceUnit resourceUnit = entry.getKey();
            LoadReport loadReport = entry.getValue();
            Map<String, NamespaceBundleStats> bundleStats = loadReport.getBundleStats();
            if (bundleStats == null) {
                continue;
            }
            for (Map.Entry<String, NamespaceBundleStats> statsEntry : bundleStats.entrySet()) {
                String bundle = statsEntry.getKey();
                NamespaceBundleStats stats = statsEntry.getValue();
                long memGroupCount = (1 + (stats.topics + stats.producerCount + stats.consumerCount) / memObjectGroupSize);
                double newMemoryQuota = memGroupCount * this.realtimeMemoryLoadFactor;
                ResourceQuota oldQuota = getResourceQuota(bundle);
                ResourceQuota newQuota = timeSmoothQuota(oldQuota, stats.msgRateIn, stats.msgRateOut, stats.msgThroughputIn, stats.msgThroughputOut, newMemoryQuota, timePast);
                newQuotas.put(bundle, newQuota);
            }
        }
        this.realtimeResourceQuotas.set(newQuotas);
    }
}
Also used : HashMap(java.util.HashMap) SystemResourceUsage(org.apache.pulsar.policies.data.loadbalancer.SystemResourceUsage) ResourceUnit(org.apache.pulsar.broker.loadbalance.ResourceUnit) NamespaceBundleStats(org.apache.pulsar.policies.data.loadbalancer.NamespaceBundleStats) ResourceQuota(org.apache.pulsar.common.policies.data.ResourceQuota) LoadReport(org.apache.pulsar.policies.data.loadbalancer.LoadReport) Map(java.util.Map) HashMap(java.util.HashMap) TreeMap(java.util.TreeMap)

Example 4 with ResourceQuota

use of org.apache.pulsar.common.policies.data.ResourceQuota in project incubator-pulsar by apache.

the class SimpleLoadManagerImpl method findBrokerForPlacement.

/**
 * Assign owner for specified ServiceUnit from the given candidates, following the the principles: 1) Optimum
 * distribution: fill up one broker till its load reaches optimum level (defined by underload threshold) before pull
 * another idle broker in; 2) Even distribution: once all brokers' load are above optimum level, maintain all
 * brokers to have even load; 3) Set the underload threshold to small value (like 1) for pure even distribution, and
 * high value (like 80) for pure optimum distribution;
 *
 * Strategy to select broker: 1) The first choice is the least loaded broker which is underload but not idle; 2) The
 * second choice is idle broker (if there is any); 3) Othewise simply select the least loaded broker if it is NOT
 * overloaded; 4) If all brokers are overloaded, select the broker with maximum available capacity (considering
 * brokers could have different hardware configuration, this usually means to select the broker with more hardware
 * resource);
 *
 * Broker's load level: 1) Load ranking (triggered by LoadReport update) estimate the load level according to the
 * resourse usage and namespace bundles already loaded by each broker; 2) When leader broker decide the owner for a
 * new namespace bundle, it may take time for the real owner to actually load the bundle and refresh LoadReport,
 * leader broker will store the bundle in a list called preAllocatedBundles, and the quota of all
 * preAllocatedBundles in preAllocatedQuotas, and re-estimate the broker's load level by putting the
 * preAllocatedQuota into calculation; 3) Everything (preAllocatedBundles and preAllocatedQuotas) will get reset in
 * load ranking.
 */
private synchronized ResourceUnit findBrokerForPlacement(Multimap<Long, ResourceUnit> candidates, ServiceUnitId serviceUnit) {
    long underloadThreshold = this.getLoadBalancerBrokerUnderloadedThresholdPercentage();
    long overloadThreshold = this.getLoadBalancerBrokerOverloadedThresholdPercentage();
    ResourceQuota defaultQuota = pulsar.getLocalZkCacheService().getResourceQuotaCache().getDefaultQuota();
    double minLoadPercentage = 101.0;
    long maxAvailability = -1;
    ResourceUnit idleRU = null;
    ResourceUnit maxAvailableRU = null;
    ResourceUnit randomRU = null;
    ResourceUnit selectedRU = null;
    ResourceUnitRanking selectedRanking = null;
    String serviceUnitId = serviceUnit.toString();
    // If the ranking is expected to be in the range [0,100] (which is the case for LOADBALANCER_STRATEGY_LLS),
    // the ranks are bounded. Otherwise (as is the case in LOADBALANCER_STRATEGY_LEAST_MSG, the ranks are simply
    // the total message rate which is in the range [0,Infinity) so they are unbounded. The
    // "boundedness" affects how two ranks are compared to see which one is better
    boolean unboundedRanks = getLoadBalancerPlacementStrategy().equals(LOADBALANCER_STRATEGY_LEAST_MSG);
    long randomBrokerIndex = (candidates.size() > 0) ? (this.brokerRotationCursor % candidates.size()) : 0;
    // find the least loaded & not-idle broker
    for (Map.Entry<Long, ResourceUnit> candidateOwner : candidates.entries()) {
        ResourceUnit candidate = candidateOwner.getValue();
        randomBrokerIndex--;
        // skip broker which is not ranked. this should never happen except in unit test
        if (!resourceUnitRankings.containsKey(candidate)) {
            continue;
        }
        String resourceUnitId = candidate.getResourceId();
        ResourceUnitRanking ranking = resourceUnitRankings.get(candidate);
        // check if this ServiceUnit is already loaded
        if (ranking.isServiceUnitLoaded(serviceUnitId)) {
            ranking.removeLoadedServiceUnit(serviceUnitId, this.getResourceQuota(serviceUnitId));
        }
        // record a random broker
        if (randomBrokerIndex < 0 && randomRU == null) {
            randomRU = candidate;
        }
        // check the available capacity
        double loadPercentage = ranking.getEstimatedLoadPercentage();
        double availablePercentage = Math.max(0, (100 - loadPercentage) / 100);
        long availability = (long) (ranking.estimateMaxCapacity(defaultQuota) * availablePercentage);
        if (availability > maxAvailability) {
            maxAvailability = availability;
            maxAvailableRU = candidate;
        }
        // check the load percentage
        if (ranking.isIdle()) {
            if (idleRU == null) {
                idleRU = candidate;
            }
        } else {
            if (selectedRU == null) {
                selectedRU = candidate;
                selectedRanking = ranking;
                minLoadPercentage = loadPercentage;
            } else {
                if ((unboundedRanks ? ranking.compareMessageRateTo(selectedRanking) : ranking.compareTo(selectedRanking)) < 0) {
                    minLoadPercentage = loadPercentage;
                    selectedRU = candidate;
                    selectedRanking = ranking;
                }
            }
        }
    }
    if ((minLoadPercentage > underloadThreshold && idleRU != null) || selectedRU == null) {
        // assigned to idle broker is the least loaded broker already have optimum load (which means NOT
        // underloaded), or all brokers are idle
        selectedRU = idleRU;
    } else if (minLoadPercentage >= 100.0 && randomRU != null && !unboundedRanks) {
        // all brokers are full, assign to a random one
        selectedRU = randomRU;
    } else if (minLoadPercentage > overloadThreshold && !unboundedRanks) {
        // assign to the broker with maximum available capacity if all brokers are overloaded
        selectedRU = maxAvailableRU;
    }
    // re-calculate load level for selected broker
    if (selectedRU != null) {
        this.brokerRotationCursor = (this.brokerRotationCursor + 1) % 1000000;
        ResourceUnitRanking ranking = resourceUnitRankings.get(selectedRU);
        String loadPercentageDesc = ranking.getEstimatedLoadPercentageString();
        log.info("Assign {} to {} with ({}).", serviceUnitId, selectedRU.getResourceId(), loadPercentageDesc);
        if (!ranking.isServiceUnitPreAllocated(serviceUnitId)) {
            final String namespaceName = LoadManagerShared.getNamespaceNameFromBundleName(serviceUnitId);
            final String bundleRange = LoadManagerShared.getBundleRangeFromBundleName(serviceUnitId);
            ResourceQuota quota = this.getResourceQuota(serviceUnitId);
            // Add preallocated bundle range so incoming bundles from the same namespace are not assigned to the
            // same broker.
            brokerToNamespaceToBundleRange.computeIfAbsent(selectedRU.getResourceId().replace("http://", ""), k -> new HashMap<>()).computeIfAbsent(namespaceName, k -> new HashSet<>()).add(bundleRange);
            ranking.addPreAllocatedServiceUnit(serviceUnitId, quota);
            resourceUnitRankings.put(selectedRU, ranking);
        }
    }
    return selectedRU;
}
Also used : CreateMode(org.apache.zookeeper.CreateMode) Metrics(org.apache.pulsar.common.stats.Metrics) LoadingCache(com.google.common.cache.LoadingCache) DefaultThreadFactory(io.netty.util.concurrent.DefaultThreadFactory) Ids(org.apache.zookeeper.ZooDefs.Ids) ObjectMapperFactory(org.apache.pulsar.common.util.ObjectMapperFactory) LoggerFactory(org.slf4j.LoggerFactory) LoadManager(org.apache.pulsar.broker.loadbalance.LoadManager) Stat(org.apache.zookeeper.data.Stat) SystemResourceUsage(org.apache.pulsar.policies.data.loadbalancer.SystemResourceUsage) TreeMultimap(com.google.common.collect.TreeMultimap) Map(java.util.Map) ZooKeeperDataCache(org.apache.pulsar.zookeeper.ZooKeeperDataCache) NamespaceName(org.apache.pulsar.common.naming.NamespaceName) AdminResource.jsonMapper(org.apache.pulsar.broker.admin.AdminResource.jsonMapper) BrokerHostUsage(org.apache.pulsar.broker.loadbalance.BrokerHostUsage) Set(java.util.Set) ZooKeeperChildrenCache(org.apache.pulsar.zookeeper.ZooKeeperChildrenCache) ZooKeeperCacheListener(org.apache.pulsar.zookeeper.ZooKeeperCacheListener) LoadReport(org.apache.pulsar.policies.data.loadbalancer.LoadReport) Executors(java.util.concurrent.Executors) ZkUtils(org.apache.bookkeeper.util.ZkUtils) Sets(com.google.common.collect.Sets) CacheLoader(com.google.common.cache.CacheLoader) List(java.util.List) ServiceUnitId(org.apache.pulsar.common.naming.ServiceUnitId) Optional(java.util.Optional) NamespaceBundleStats(org.apache.pulsar.policies.data.loadbalancer.NamespaceBundleStats) CacheBuilder(com.google.common.cache.CacheBuilder) LocalDateTime(java.time.LocalDateTime) HashMap(java.util.HashMap) ResourceUnit(org.apache.pulsar.broker.loadbalance.ResourceUnit) LOAD_REPORT_UPDATE_MIMIMUM_INTERVAL(org.apache.pulsar.broker.loadbalance.impl.LoadManagerShared.LOAD_REPORT_UPDATE_MIMIMUM_INTERVAL) Multimap(com.google.common.collect.Multimap) AtomicReference(java.util.concurrent.atomic.AtomicReference) StringUtils.isNotEmpty(org.apache.commons.lang3.StringUtils.isNotEmpty) ArrayList(java.util.ArrayList) HashSet(java.util.HashSet) Lists(com.google.common.collect.Lists) ScheduledExecutorService(java.util.concurrent.ScheduledExecutorService) Charsets(com.google.common.base.Charsets) ResourceQuota(org.apache.pulsar.common.policies.data.ResourceQuota) Logger(org.slf4j.Logger) Iterator(java.util.Iterator) KeeperException(org.apache.zookeeper.KeeperException) SystemUtils(org.apache.commons.lang3.SystemUtils) ServiceConfiguration(org.apache.pulsar.broker.ServiceConfiguration) BrokerTopicLoadingPredicate(org.apache.pulsar.broker.loadbalance.impl.LoadManagerShared.BrokerTopicLoadingPredicate) IOException(java.io.IOException) PulsarService(org.apache.pulsar.broker.PulsarService) Maps(com.google.common.collect.Maps) TimeUnit(java.util.concurrent.TimeUnit) PlacementStrategy(org.apache.pulsar.broker.loadbalance.PlacementStrategy) ResourceType(org.apache.pulsar.policies.data.loadbalancer.SystemResourceUsage.ResourceType) TreeMap(java.util.TreeMap) PulsarServerException(org.apache.pulsar.broker.PulsarServerException) Deserializer(org.apache.pulsar.zookeeper.ZooKeeperCache.Deserializer) ResourceUnitRanking(org.apache.pulsar.policies.data.loadbalancer.ResourceUnitRanking) Collections(java.util.Collections) ResourceUnit(org.apache.pulsar.broker.loadbalance.ResourceUnit) ResourceQuota(org.apache.pulsar.common.policies.data.ResourceQuota) ResourceUnitRanking(org.apache.pulsar.policies.data.loadbalancer.ResourceUnitRanking) Map(java.util.Map) HashMap(java.util.HashMap) TreeMap(java.util.TreeMap) HashSet(java.util.HashSet)

Example 5 with ResourceQuota

use of org.apache.pulsar.common.policies.data.ResourceQuota in project incubator-pulsar by apache.

the class SimpleLoadManagerImpl method getTotalAllocatedQuota.

/**
 * Get the sum of allocated resource for the list of namespace bundles
 */
private ResourceQuota getTotalAllocatedQuota(Set<String> bundles) {
    ResourceQuota totalQuota = new ResourceQuota();
    for (String bundle : bundles) {
        ResourceQuota quota = this.getResourceQuota(bundle);
        totalQuota.add(quota);
    }
    return totalQuota;
}
Also used : ResourceQuota(org.apache.pulsar.common.policies.data.ResourceQuota)

Aggregations

ResourceQuota (org.apache.pulsar.common.policies.data.ResourceQuota)24 Test (org.testng.annotations.Test)10 HashMap (java.util.HashMap)9 Map (java.util.Map)9 TreeMap (java.util.TreeMap)6 KeeperException (org.apache.zookeeper.KeeperException)6 LoadReport (org.apache.pulsar.policies.data.loadbalancer.LoadReport)5 SystemResourceUsage (org.apache.pulsar.policies.data.loadbalancer.SystemResourceUsage)5 PulsarServerException (org.apache.pulsar.broker.PulsarServerException)4 ResourceUnit (org.apache.pulsar.broker.loadbalance.ResourceUnit)4 IOException (java.io.IOException)3 ArrayList (java.util.ArrayList)3 HashSet (java.util.HashSet)3 AtomicReference (java.util.concurrent.atomic.AtomicReference)3 BundleData (org.apache.pulsar.broker.BundleData)3 NamespaceBundleStats (org.apache.pulsar.policies.data.loadbalancer.NamespaceBundleStats)3 ResourceUnitRanking (org.apache.pulsar.policies.data.loadbalancer.ResourceUnitRanking)3 ParameterException (com.beust.jcommander.ParameterException)2 Set (java.util.Set)2 Future (java.util.concurrent.Future)2