Search in sources :

Example 16 with LoadReport

use of com.yahoo.pulsar.common.policies.data.loadbalancer.LoadReport in project pulsar by yahoo.

the class LoadBalancerTest method testLoadReportsWrittenOnZK.

/*
     * tests that load manager creates its node and writes the initial load report a /loadbalance/brokers tests that
     * those load reports can be deserialized and are in valid format tests if the rankings are populated from the load
     * reports are not, both broker will have zero rank
     */
@Test
public void testLoadReportsWrittenOnZK() throws Exception {
    ZooKeeper zkc = bkEnsemble.getZkClient();
    try {
        for (int i = 0; i < BROKER_COUNT; i++) {
            String znodePath = String.format("%s/%s", SimpleLoadManagerImpl.LOADBALANCE_BROKERS_ROOT, lookupAddresses[i]);
            byte[] loadReportData = zkc.getData(znodePath, false, null);
            assert (loadReportData.length > 0);
            log.info("LoadReport {}, {}", lookupAddresses[i], new String(loadReportData));
            LoadReport loadReport = objectMapper.readValue(loadReportData, LoadReport.class);
            assert (loadReport.getName().equals(lookupAddresses[i]));
            assertTrue(loadReport.isUnderLoaded());
            assertFalse(loadReport.isOverLoaded());
            // Check Initial Ranking is populated in both the brokers
            Field ranking = ((SimpleLoadManagerImpl) pulsarServices[i].getLoadManager()).getClass().getDeclaredField("sortedRankings");
            ranking.setAccessible(true);
            AtomicReference<Map<Long, Set<ResourceUnit>>> sortedRanking = (AtomicReference<Map<Long, Set<ResourceUnit>>>) ranking.get(pulsarServices[i].getLoadManager());
            printSortedRanking(sortedRanking);
            // all brokers have same rank to it would be 0 --> set-of-all-the-brokers
            int brokerCount = 0;
            for (Map.Entry<Long, Set<ResourceUnit>> entry : sortedRanking.get().entrySet()) {
                brokerCount += entry.getValue().size();
            }
            assertEquals(brokerCount, BROKER_COUNT);
            DestinationName fqdn = DestinationName.get("persistent://pulsar/use/primary-ns/test-topic");
            ResourceUnit found = pulsarServices[i].getLoadManager().getLeastLoaded(pulsarServices[i].getNamespaceService().getBundle(fqdn));
            assertTrue(found != null);
        }
    } catch (InterruptedException | KeeperException e) {
        fail("Unable to read the data from Zookeeper - [{}]", e);
    }
}
Also used : Set(java.util.Set) HashSet(java.util.HashSet) AtomicReference(java.util.concurrent.atomic.AtomicReference) SimpleResourceUnit(com.yahoo.pulsar.broker.loadbalance.impl.SimpleResourceUnit) Field(java.lang.reflect.Field) ZooKeeper(org.apache.zookeeper.ZooKeeper) LoadReport(com.yahoo.pulsar.common.policies.data.loadbalancer.LoadReport) DestinationName(com.yahoo.pulsar.common.naming.DestinationName) Map(java.util.Map) HashMap(java.util.HashMap) TreeMap(java.util.TreeMap) KeeperException(org.apache.zookeeper.KeeperException) Test(org.testng.annotations.Test)

Example 17 with LoadReport

use of com.yahoo.pulsar.common.policies.data.loadbalancer.LoadReport in project pulsar by yahoo.

the class SimpleLoadManagerImpl method start.

@Override
public void start() throws PulsarServerException {
    try {
        // Register the brokers in zk list
        ServiceConfiguration conf = pulsar.getConfiguration();
        if (pulsar.getZkClient().exists(LOADBALANCE_BROKERS_ROOT, false) == null) {
            try {
                ZkUtils.createFullPathOptimistic(pulsar.getZkClient(), LOADBALANCE_BROKERS_ROOT, new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
            } catch (KeeperException.NodeExistsException e) {
            // ignore the exception, node might be present already
            }
        }
        String lookupServiceAddress = pulsar.getAdvertisedAddress() + ":" + conf.getWebServicePort();
        brokerZnodePath = LOADBALANCE_BROKERS_ROOT + "/" + lookupServiceAddress;
        LoadReport loadReport = null;
        try {
            loadReport = generateLoadReport();
            this.lastResourceUsageTimestamp = loadReport.getTimestamp();
        } catch (Exception e) {
            log.warn("Unable to get load report to write it on zookeeper [{}]", e);
        }
        String loadReportJson = "";
        if (loadReport != null) {
            loadReportJson = ObjectMapperFactory.getThreadLocal().writeValueAsString(loadReport);
        }
        try {
            ZkUtils.createFullPathOptimistic(pulsar.getZkClient(), brokerZnodePath, loadReportJson.getBytes(Charsets.UTF_8), Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
        } catch (Exception e) {
            // Catching excption here to print the right error message
            log.error("Unable to create znode - [{}] for load balance on zookeeper ", brokerZnodePath, e);
            throw e;
        }
        // first time, populate the broker ranking
        updateRanking();
        log.info("Created broker ephemeral node on {}", brokerZnodePath);
        // load default resource quota
        this.realtimeAvgResourceQuota = pulsar.getLocalZkCacheService().getResourceQuotaCache().getDefaultQuota();
        this.lastResourceQuotaUpdateTimestamp = System.currentTimeMillis();
        this.realtimeCpuLoadFactor = getDynamicConfigurationDouble(LOADBALANCER_DYNAMIC_SETTING_LOAD_FACTOR_CPU_ZPATH, SETTING_NAME_LOAD_FACTOR_CPU, this.realtimeCpuLoadFactor);
        this.realtimeMemoryLoadFactor = getDynamicConfigurationDouble(LOADBALANCER_DYNAMIC_SETTING_LOAD_FACTOR_MEM_ZPATH, SETTING_NAME_LOAD_FACTOR_MEM, this.realtimeMemoryLoadFactor);
    } catch (Exception e) {
        log.error("Unable to create znode - [{}] for load balance on zookeeper ", brokerZnodePath, e);
        throw new PulsarServerException(e);
    }
}
Also used : PulsarServerException(com.yahoo.pulsar.broker.PulsarServerException) ServiceConfiguration(com.yahoo.pulsar.broker.ServiceConfiguration) LoadReport(com.yahoo.pulsar.common.policies.data.loadbalancer.LoadReport) KeeperException(org.apache.zookeeper.KeeperException) KeeperException(org.apache.zookeeper.KeeperException) MalformedURLException(java.net.MalformedURLException) IOException(java.io.IOException) PulsarServerException(com.yahoo.pulsar.broker.PulsarServerException)

Example 18 with LoadReport

use of com.yahoo.pulsar.common.policies.data.loadbalancer.LoadReport in project pulsar by yahoo.

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 || bundlePercentageChange > pulsar.getConfiguration().getLoadBalancerReportUpdateThresholdPercentage()) {
                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 = generateLoadReport();
        pulsar.getZkClient().setData(brokerZnodePath, ObjectMapperFactory.getThreadLocal().writeValueAsBytes(lr), -1);
        this.lastLoadReport = lr;
        this.lastResourceUsageTimestamp = lr.getTimestamp();
        // split-bundle if requires
        doNamespaceBundleSplit();
    }
}
Also used : LoadReport(com.yahoo.pulsar.common.policies.data.loadbalancer.LoadReport) SystemResourceUsage(com.yahoo.pulsar.common.policies.data.loadbalancer.SystemResourceUsage)

Example 19 with LoadReport

use of com.yahoo.pulsar.common.policies.data.loadbalancer.LoadReport in project pulsar by yahoo.

the class AdminTest method brokerStats.

@Test
void brokerStats() throws Exception {
    doReturn("client-id").when(brokerStats).clientAppId();
    Collection<Metrics> metrics = brokerStats.getMetrics();
    assertNotNull(metrics);
    LoadReport loadReport = brokerStats.getLoadReport();
    assertNotNull(loadReport);
    assertEquals(loadReport.isOverLoaded(), false);
    Collection<Metrics> mBeans = brokerStats.getMBeans();
    assertTrue(!mBeans.isEmpty());
    AllocatorStats allocatorStats = brokerStats.getAllocatorStats("default");
    assertNotNull(allocatorStats);
    Map<String, Map<String, PendingBookieOpsStats>> bookieOpsStats = brokerStats.getPendingBookieOpsStats();
    assertTrue(bookieOpsStats.isEmpty());
    StreamingOutput destination = brokerStats.getDestinations2();
    assertNotNull(destination);
    Map<Long, Collection<ResourceUnit>> resource = brokerStats.getBrokerResourceAvailability("prop", "use", "ns2");
    // size should be 1 with default resourceUnit
    assertTrue(resource.size() == 1);
}
Also used : Metrics(com.yahoo.pulsar.broker.stats.Metrics) LoadReport(com.yahoo.pulsar.common.policies.data.loadbalancer.LoadReport) AllocatorStats(com.yahoo.pulsar.common.stats.AllocatorStats) Collection(java.util.Collection) StreamingOutput(javax.ws.rs.core.StreamingOutput) Map(java.util.Map) HashMap(java.util.HashMap) Test(org.testng.annotations.Test) MockedPulsarServiceBaseTest(com.yahoo.pulsar.broker.auth.MockedPulsarServiceBaseTest)

Example 20 with LoadReport

use of com.yahoo.pulsar.common.policies.data.loadbalancer.LoadReport in project pulsar by yahoo.

the class DiscoveryServiceServlet method redirect.

private void redirect(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    try {
        LoadReport broker = nextBroker();
        URI brokerURI;
        if (request.getScheme().equals("http")) {
            // Use normal HTTP url
            brokerURI = new URI(broker.getWebServiceUrl());
        } else {
            brokerURI = new URI(broker.getWebServiceUrlTls());
        }
        StringBuilder location = new StringBuilder();
        location.append(brokerURI.getScheme()).append("://").append(brokerURI.getHost()).append(':').append(brokerURI.getPort()).append(request.getRequestURI());
        if (request.getQueryString() != null) {
            location.append('?').append(request.getQueryString());
        }
        if (log.isDebugEnabled()) {
            log.info("Redirecting to {}", location);
        }
        response.setStatus(HttpServletResponse.SC_TEMPORARY_REDIRECT);
        response.setHeader("Location", location.toString());
    } catch (URISyntaxException e) {
        log.warn("No broker found in zookeeper {}", e.getMessage(), e);
        throw new RestException(Status.SERVICE_UNAVAILABLE, "Broker is not available");
    }
}
Also used : LoadReport(com.yahoo.pulsar.common.policies.data.loadbalancer.LoadReport) URISyntaxException(java.net.URISyntaxException) URI(java.net.URI)

Aggregations

LoadReport (com.yahoo.pulsar.common.policies.data.loadbalancer.LoadReport)23 HashMap (java.util.HashMap)11 Test (org.testng.annotations.Test)10 Map (java.util.Map)9 TreeMap (java.util.TreeMap)9 KeeperException (org.apache.zookeeper.KeeperException)9 SystemResourceUsage (com.yahoo.pulsar.common.policies.data.loadbalancer.SystemResourceUsage)8 ResourceUnit (com.yahoo.pulsar.broker.loadbalance.ResourceUnit)5 NamespaceBundleStats (com.yahoo.pulsar.common.policies.data.loadbalancer.NamespaceBundleStats)5 PulsarServerException (com.yahoo.pulsar.broker.PulsarServerException)4 SimpleResourceUnit (com.yahoo.pulsar.broker.loadbalance.impl.SimpleResourceUnit)4 DestinationName (com.yahoo.pulsar.common.naming.DestinationName)4 Set (java.util.Set)4 JsonProcessingException (com.fasterxml.jackson.core.JsonProcessingException)3 ResourceQuota (com.yahoo.pulsar.common.policies.data.ResourceQuota)3 ResourceUsage (com.yahoo.pulsar.common.policies.data.loadbalancer.ResourceUsage)3 ServiceConfiguration (com.yahoo.pulsar.broker.ServiceConfiguration)2 BundlesData (com.yahoo.pulsar.common.policies.data.BundlesData)2 ServerManager (com.yahoo.pulsar.discovery.service.server.ServerManager)2 ServiceConfig (com.yahoo.pulsar.discovery.service.server.ServiceConfig)2