Search in sources :

Example 1 with LoadReport

use of org.apache.pulsar.policies.data.loadbalancer.LoadReport in project incubator-pulsar by apache.

the class SimpleLoadManagerImpl method updateRanking.

private void updateRanking() {
    try {
        synchronized (currentLoadReports) {
            currentLoadReports.clear();
            Set<String> activeBrokers = availableActiveBrokers.get();
            for (String broker : activeBrokers) {
                try {
                    String key = String.format("%s/%s", LOADBALANCE_BROKERS_ROOT, broker);
                    LoadReport lr = loadReportCacheZk.get(key).orElseThrow(() -> new KeeperException.NoNodeException());
                    ResourceUnit ru = new SimpleResourceUnit(String.format("http://%s", lr.getName()), fromLoadReport(lr));
                    this.currentLoadReports.put(ru, lr);
                } catch (Exception e) {
                    log.warn("Error reading load report from Cache for broker - [{}], [{}]", broker, e);
                }
            }
            updateRealtimeResourceQuota();
            doLoadRanking();
        }
    } catch (Exception e) {
        log.warn("Error reading active brokers list from zookeeper while re-ranking load reports [{}]", e);
    }
}
Also used : ResourceUnit(org.apache.pulsar.broker.loadbalance.ResourceUnit) LoadReport(org.apache.pulsar.policies.data.loadbalancer.LoadReport) KeeperException(org.apache.zookeeper.KeeperException) KeeperException(org.apache.zookeeper.KeeperException) IOException(java.io.IOException) PulsarServerException(org.apache.pulsar.broker.PulsarServerException)

Example 2 with LoadReport

use of org.apache.pulsar.policies.data.loadbalancer.LoadReport 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 3 with LoadReport

use of org.apache.pulsar.policies.data.loadbalancer.LoadReport 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 4 with LoadReport

use of org.apache.pulsar.policies.data.loadbalancer.LoadReport in project incubator-pulsar by apache.

the class SimpleLoadManagerImpl method generateLoadReportForcefully.

private LoadReport generateLoadReportForcefully() throws Exception {
    synchronized (bundleGainsCache) {
        try {
            LoadReport loadReport = new LoadReport(pulsar.getWebServiceAddress(), pulsar.getWebServiceAddressTls(), pulsar.getBrokerServiceUrl(), pulsar.getBrokerServiceUrlTls());
            loadReport.setNonPersistentTopicsEnabled(pulsar.getConfiguration().isEnableNonPersistentTopics());
            loadReport.setPersistentTopicsEnabled(pulsar.getConfiguration().isEnablePersistentTopics());
            loadReport.setName(String.format("%s:%s", pulsar.getAdvertisedAddress(), pulsar.getConfiguration().getWebServicePort()));
            loadReport.setBrokerVersionString(pulsar.getBrokerVersion());
            SystemResourceUsage systemResourceUsage = this.getSystemResourceUsage();
            loadReport.setOverLoaded(isAboveLoadLevel(systemResourceUsage, this.getLoadBalancerBrokerOverloadedThresholdPercentage()));
            loadReport.setUnderLoaded(isBelowLoadLevel(systemResourceUsage, this.getLoadBalancerBrokerUnderloadedThresholdPercentage()));
            loadReport.setSystemResourceUsage(systemResourceUsage);
            loadReport.setBundleStats(pulsar.getBrokerService().getBundleStats());
            loadReport.setTimestamp(System.currentTimeMillis());
            final Set<String> oldBundles = lastLoadReport.getBundles();
            final Set<String> newBundles = loadReport.getBundles();
            bundleGainsCache.clear();
            bundleLossesCache.clear();
            for (String oldBundle : oldBundles) {
                if (!newBundles.contains(oldBundle)) {
                    bundleLossesCache.add(oldBundle);
                }
            }
            for (String newBundle : newBundles) {
                if (!oldBundles.contains(newBundle)) {
                    bundleGainsCache.add(newBundle);
                }
            }
            loadReport.setBundleGains(bundleGainsCache);
            loadReport.setBundleLosses(bundleLossesCache);
            final ResourceQuota allocatedQuota = getTotalAllocatedQuota(newBundles);
            loadReport.setAllocatedCPU((allocatedQuota.getMsgRateIn() + allocatedQuota.getMsgRateOut()) * realtimeCpuLoadFactor);
            loadReport.setAllocatedMemory(allocatedQuota.getMemory());
            loadReport.setAllocatedBandwidthIn(allocatedQuota.getBandwidthIn());
            loadReport.setAllocatedBandwidthOut(allocatedQuota.getBandwidthOut());
            loadReport.setAllocatedMsgRateIn(allocatedQuota.getMsgRateIn());
            loadReport.setAllocatedMsgRateOut(allocatedQuota.getMsgRateOut());
            final ResourceUnit resourceUnit = new SimpleResourceUnit(String.format("http://%s", loadReport.getName()), fromLoadReport(loadReport));
            Set<String> preAllocatedBundles;
            if (resourceUnitRankings.containsKey(resourceUnit)) {
                preAllocatedBundles = resourceUnitRankings.get(resourceUnit).getPreAllocatedBundles();
                preAllocatedBundles.removeAll(newBundles);
            } else {
                preAllocatedBundles = new HashSet<>();
            }
            final ResourceQuota preAllocatedQuota = getTotalAllocatedQuota(preAllocatedBundles);
            loadReport.setPreAllocatedCPU((preAllocatedQuota.getMsgRateIn() + preAllocatedQuota.getMsgRateOut()) * realtimeCpuLoadFactor);
            loadReport.setPreAllocatedMemory(preAllocatedQuota.getMemory());
            loadReport.setPreAllocatedBandwidthIn(preAllocatedQuota.getBandwidthIn());
            loadReport.setPreAllocatedBandwidthOut(preAllocatedQuota.getBandwidthOut());
            loadReport.setPreAllocatedMsgRateIn(preAllocatedQuota.getMsgRateIn());
            loadReport.setPreAllocatedMsgRateOut(preAllocatedQuota.getMsgRateOut());
            return loadReport;
        } catch (Exception e) {
            log.error("[{}] Failed to generate LoadReport for broker, reason [{}]", e.getMessage(), e);
            throw e;
        }
    }
}
Also used : ResourceUnit(org.apache.pulsar.broker.loadbalance.ResourceUnit) ResourceQuota(org.apache.pulsar.common.policies.data.ResourceQuota) LoadReport(org.apache.pulsar.policies.data.loadbalancer.LoadReport) SystemResourceUsage(org.apache.pulsar.policies.data.loadbalancer.SystemResourceUsage) KeeperException(org.apache.zookeeper.KeeperException) IOException(java.io.IOException) PulsarServerException(org.apache.pulsar.broker.PulsarServerException)

Example 5 with LoadReport

use of org.apache.pulsar.policies.data.loadbalancer.LoadReport in project incubator-pulsar by apache.

the class SimpleLoadManagerImpl method writeLoadReportOnZookeeper.

@Override
public void writeLoadReportOnZookeeper() throws Exception {
    // update average JVM heap usage to average value of the last 120 seconds
    long realtimeJvmHeapUsage = getRealtimeJvmHeapUsageMBytes();
    if (this.avgJvmHeapUsageMBytes <= 0) {
        this.avgJvmHeapUsageMBytes = realtimeJvmHeapUsage;
    } else {
        long weight = Math.max(1, TimeUnit.SECONDS.toMillis(120) / LOAD_REPORT_UPDATE_MIMIMUM_INTERVAL);
        this.avgJvmHeapUsageMBytes = ((weight - 1) * this.avgJvmHeapUsageMBytes + realtimeJvmHeapUsage) / weight;
    }
    // Update LoadReport in below situations:
    // 1) This is the first time to update LoadReport
    // 2) The last LoadReport is 5 minutes ago
    // 3) There is more than 10% change on number of bundles assigned comparing with broker's maximum capacity
    // 4) There is more than 10% change on resource usage comparing with broker's resource limit
    boolean needUpdate = false;
    if (lastLoadReport == null || this.forceLoadReportUpdate == true) {
        needUpdate = true;
        this.forceLoadReportUpdate = false;
    } else {
        long timestampNow = System.currentTimeMillis();
        long timeElapsedSinceLastReport = timestampNow - lastLoadReport.getTimestamp();
        int maxUpdateIntervalInMinutes = pulsar.getConfiguration().getLoadBalancerReportUpdateMaxIntervalMinutes();
        if (timeElapsedSinceLastReport > TimeUnit.MINUTES.toMillis(maxUpdateIntervalInMinutes)) {
            needUpdate = true;
        } else if (timeElapsedSinceLastReport > LOAD_REPORT_UPDATE_MIMIMUM_INTERVAL) {
            // check number of bundles assigned, comparing with last LoadReport
            long oldBundleCount = lastLoadReport.getNumBundles();
            long newBundleCount = pulsar.getBrokerService().getNumberOfNamespaceBundles();
            long bundleCountChange = Math.abs(oldBundleCount - newBundleCount);
            long maxCapacity = ResourceUnitRanking.calculateBrokerMaxCapacity(lastLoadReport.getSystemResourceUsage(), pulsar.getLocalZkCacheService().getResourceQuotaCache().getDefaultQuota());
            double bundlePercentageChange = (maxCapacity > 0) ? (bundleCountChange * 100 / maxCapacity) : 0;
            if (newBundleCount != oldBundleCount) {
                needUpdate = true;
            }
            // check resource usage comparing with last LoadReport
            if (!needUpdate && timestampNow - this.lastResourceUsageTimestamp > TimeUnit.MINUTES.toMillis(pulsar.getConfiguration().getLoadBalancerHostUsageCheckIntervalMinutes())) {
                SystemResourceUsage oldUsage = lastLoadReport.getSystemResourceUsage();
                SystemResourceUsage newUsage = this.getSystemResourceUsage();
                this.lastResourceUsageTimestamp = timestampNow;
                // calculate percentage of change
                double cpuChange = (newUsage.cpu.limit > 0) ? ((newUsage.cpu.usage - oldUsage.cpu.usage) * 100 / newUsage.cpu.limit) : 0;
                double memChange = (newUsage.memory.limit > 0) ? ((newUsage.memory.usage - oldUsage.memory.usage) * 100 / newUsage.memory.limit) : 0;
                double directMemChange = (newUsage.directMemory.limit > 0) ? ((newUsage.directMemory.usage - oldUsage.directMemory.usage) * 100 / newUsage.directMemory.limit) : 0;
                double bandwidthOutChange = (newUsage.bandwidthOut.limit > 0) ? ((newUsage.bandwidthOut.usage - oldUsage.bandwidthOut.usage) * 100 / newUsage.bandwidthOut.limit) : 0;
                double bandwidthInChange = (newUsage.bandwidthIn.limit > 0) ? ((newUsage.bandwidthIn.usage - oldUsage.bandwidthIn.usage) * 100 / newUsage.bandwidthIn.limit) : 0;
                long resourceChange = (long) Math.min(100.0, Math.max(Math.abs(cpuChange), Math.max(Math.abs(directMemChange), Math.max(Math.abs(memChange), Math.max(Math.abs(bandwidthOutChange), Math.abs(bandwidthInChange))))));
                if (resourceChange > pulsar.getConfiguration().getLoadBalancerReportUpdateThresholdPercentage()) {
                    needUpdate = true;
                    log.info("LoadReport update triggered by change on resource usage, detal ({}).", String.format("cpu: %.1f%%, mem: %.1f%%, directMemory: %.1f%%, bandwidthIn: %.1f%%, bandwidthOut: %.1f%%)", cpuChange, memChange, directMemChange, bandwidthInChange, bandwidthOutChange));
                }
            }
        }
    }
    if (needUpdate) {
        LoadReport lr = generateLoadReportForcefully();
        pulsar.getZkClient().setData(brokerZnodePath, ObjectMapperFactory.getThreadLocal().writeValueAsBytes(lr), -1);
        this.lastLoadReport = lr;
        this.lastResourceUsageTimestamp = lr.getTimestamp();
        // split-bundle if requires
        doNamespaceBundleSplit();
    }
}
Also used : LoadReport(org.apache.pulsar.policies.data.loadbalancer.LoadReport) SystemResourceUsage(org.apache.pulsar.policies.data.loadbalancer.SystemResourceUsage)

Aggregations

LoadReport (org.apache.pulsar.policies.data.loadbalancer.LoadReport)26 Test (org.testng.annotations.Test)12 HashMap (java.util.HashMap)11 TreeMap (java.util.TreeMap)11 SystemResourceUsage (org.apache.pulsar.policies.data.loadbalancer.SystemResourceUsage)11 Map (java.util.Map)10 KeeperException (org.apache.zookeeper.KeeperException)10 ResourceUnit (org.apache.pulsar.broker.loadbalance.ResourceUnit)7 IOException (java.io.IOException)6 Set (java.util.Set)6 NamespaceBundleStats (org.apache.pulsar.policies.data.loadbalancer.NamespaceBundleStats)6 HashSet (java.util.HashSet)5 PulsarServerException (org.apache.pulsar.broker.PulsarServerException)5 ResourceQuota (org.apache.pulsar.common.policies.data.ResourceQuota)5 ResourceUsage (org.apache.pulsar.policies.data.loadbalancer.ResourceUsage)5 Field (java.lang.reflect.Field)4 LocalBrokerData (org.apache.pulsar.policies.data.loadbalancer.LocalBrokerData)4 JsonProcessingException (com.fasterxml.jackson.core.JsonProcessingException)3 SimpleResourceUnit (org.apache.pulsar.broker.loadbalance.impl.SimpleResourceUnit)3 TopicName (org.apache.pulsar.common.naming.TopicName)3