Search in sources :

Example 1 with ClusterProperties

use of com.linkedin.d2.balancer.properties.ClusterProperties in project rest.li by linkedin.

the class SimpleLoadBalancer method getClient.

/**
   * Given a Request, returns a TransportClient that can handle requests for the Request.
   *
   *
   * @param request
   *          A request whose URI is a URL of the format "d2://>servicename</optional/path".
   * @param requestContext context for this request
   * @return A client that can be called to retrieve data for the URN.
   * @throws ServiceUnavailableException
   *           If the load balancer can't figure out how to reach a service for the given
   *           URN, an ServiceUnavailableException will be thrown.
   */
@Override
public TransportClient getClient(Request request, RequestContext requestContext) throws ServiceUnavailableException {
    TransportClient client;
    URI uri = request.getURI();
    debug(_log, "get client for uri: ", uri);
    ServiceProperties service = listenToServiceAndCluster(uri);
    String serviceName = service.getServiceName();
    String clusterName = service.getClusterName();
    ClusterProperties cluster = getClusterProperties(serviceName, clusterName);
    // Check if we want to override the service URL and bypass choosing among the existing
    // tracker clients. This is useful when the service we want is not announcing itself to
    // the cluster, ie a private service for a set of clients.
    URI targetService = LoadBalancerUtil.TargetHints.getRequestContextTargetService(requestContext);
    if (targetService == null) {
        LoadBalancerStateItem<UriProperties> uriItem = getUriItem(serviceName, clusterName, cluster);
        UriProperties uris = uriItem.getProperty();
        List<LoadBalancerState.SchemeStrategyPair> orderedStrategies = _state.getStrategiesForService(serviceName, service.getPrioritizedSchemes());
        TrackerClient trackerClient = chooseTrackerClient(request, requestContext, serviceName, clusterName, cluster, uriItem, uris, orderedStrategies, service);
        String clusterAndServiceUriString = trackerClient.getUri() + service.getPath();
        client = new RewriteClient(serviceName, URI.create(clusterAndServiceUriString), trackerClient);
        _serviceAvailableStats.inc();
    } else {
        _log.debug("service hint found, using generic client for target: {}", targetService);
        TransportClient transportClient = _state.getClient(serviceName, targetService.getScheme());
        client = new RewriteClient(serviceName, targetService, transportClient);
    }
    return client;
}
Also used : ServiceProperties(com.linkedin.d2.balancer.properties.ServiceProperties) TransportClient(com.linkedin.r2.transport.common.bridge.client.TransportClient) TrackerClient(com.linkedin.d2.balancer.clients.TrackerClient) UriProperties(com.linkedin.d2.balancer.properties.UriProperties) ClusterProperties(com.linkedin.d2.balancer.properties.ClusterProperties) URI(java.net.URI) RewriteClient(com.linkedin.d2.balancer.clients.RewriteClient)

Example 2 with ClusterProperties

use of com.linkedin.d2.balancer.properties.ClusterProperties in project rest.li by linkedin.

the class LastSeenBalancerWithFacilitiesFactory method create.

@Override
public LoadBalancerWithFacilities create(D2ClientConfig config) {
    LOG.info("Creating D2 LoadBalancer based on LastSeenLoadBalancerWithFacilities");
    D2ClientJmxManager d2ClientJmxManager = new D2ClientJmxManager(config.d2JmxManagerPrefix, config.jmxManager);
    // init connection
    ZKConnectionBuilder zkConnectionBuilder = new ZKConnectionBuilder(config.zkHosts);
    zkConnectionBuilder.setShutdownAsynchronously(config.shutdownAsynchronously).setIsSymlinkAware(config.isSymlinkAware).setTimeout((int) config.zkSessionTimeoutInMs);
    ZKPersistentConnection zkPersistentConnection;
    if (config.zkConnectionToUseForLB != null) {
        LOG.info("LastSeenLoadBalancer using shared connection to zookeeper");
        zkPersistentConnection = config.zkConnectionToUseForLB;
    } else {
        LOG.info("LastSeenLoadBalancer using its own connection to zookeeper");
        zkPersistentConnection = new ZKPersistentConnection(zkConnectionBuilder);
    }
    // init all the stores
    LastSeenZKStore<ClusterProperties> lsClusterStore = getClusterPropertiesLastSeenZKStore(config, zkPersistentConnection, d2ClientJmxManager, config._executorService, config.zookeeperReadWindowMs);
    PropertyEventBus<ClusterProperties> clusterBus = new PropertyEventBusImpl<>(config._executorService);
    clusterBus.setPublisher(lsClusterStore);
    LastSeenZKStore<ServiceProperties> lsServiceStore = getServicePropertiesLastSeenZKStore(config, zkPersistentConnection, d2ClientJmxManager, config._executorService, config.zookeeperReadWindowMs);
    PropertyEventBus<ServiceProperties> serviceBus = new PropertyEventBusImpl<>(config._executorService);
    serviceBus.setPublisher(lsServiceStore);
    LastSeenZKStore<UriProperties> lsUrisStore = getUriPropertiesLastSeenZKStore(config, zkPersistentConnection, d2ClientJmxManager, config._executorService, config.zookeeperReadWindowMs);
    PropertyEventBus<UriProperties> uriBus = new PropertyEventBusImpl<>(config._executorService);
    uriBus.setPublisher(lsUrisStore);
    // create the simple load balancer
    SimpleLoadBalancerState state = new SimpleLoadBalancerState(config._executorService, uriBus, clusterBus, serviceBus, config.clientFactories, config.loadBalancerStrategyFactories, config.sslContext, config.sslParameters, config.isSSLEnabled, config.partitionAccessorRegistry, config.sslSessionValidatorFactory, config.deterministicSubsettingMetadataProvider);
    d2ClientJmxManager.setSimpleLoadBalancerState(state);
    SimpleLoadBalancer simpleLoadBalancer = new SimpleLoadBalancer(state, config.lbWaitTimeout, config.lbWaitUnit, config._executorService);
    d2ClientJmxManager.setSimpleLoadBalancer(simpleLoadBalancer);
    // add facilities
    LastSeenLoadBalancerWithFacilities lastSeenLoadBalancer = new LastSeenLoadBalancerWithFacilities(simpleLoadBalancer, config.basePath, config.d2ServicePath, zkPersistentConnection, lsClusterStore, lsServiceStore, lsUrisStore);
    LoadBalancerWithFacilities balancer = lastSeenLoadBalancer;
    if (config.warmUp) {
        balancer = new WarmUpLoadBalancer(balancer, lastSeenLoadBalancer, config.startUpExecutorService, config.fsBasePath, config.d2ServicePath, config.downstreamServicesFetcher, config.warmUpTimeoutSeconds, config.warmUpConcurrentRequests);
    }
    return balancer;
}
Also used : ZKPersistentConnection(com.linkedin.d2.discovery.stores.zk.ZKPersistentConnection) WarmUpLoadBalancer(com.linkedin.d2.balancer.util.WarmUpLoadBalancer) SimpleLoadBalancerState(com.linkedin.d2.balancer.simple.SimpleLoadBalancerState) SimpleLoadBalancer(com.linkedin.d2.balancer.simple.SimpleLoadBalancer) LastSeenLoadBalancerWithFacilities(com.linkedin.d2.balancer.zkfs.LastSeenLoadBalancerWithFacilities) D2ClientJmxManager(com.linkedin.d2.jmx.D2ClientJmxManager) ServiceProperties(com.linkedin.d2.balancer.properties.ServiceProperties) UriProperties(com.linkedin.d2.balancer.properties.UriProperties) ZKConnectionBuilder(com.linkedin.d2.discovery.stores.zk.ZKConnectionBuilder) PropertyEventBusImpl(com.linkedin.d2.discovery.event.PropertyEventBusImpl) ClusterProperties(com.linkedin.d2.balancer.properties.ClusterProperties) LastSeenLoadBalancerWithFacilities(com.linkedin.d2.balancer.zkfs.LastSeenLoadBalancerWithFacilities)

Example 3 with ClusterProperties

use of com.linkedin.d2.balancer.properties.ClusterProperties in project rest.li by linkedin.

the class SimpleLoadBalancer method getRings.

@Override
public <K> MapKeyResult<Ring<URI>, K> getRings(URI serviceUri, Iterable<K> keys) throws ServiceUnavailableException {
    ServiceProperties service = listenToServiceAndCluster(serviceUri);
    String serviceName = service.getServiceName();
    String clusterName = service.getClusterName();
    ClusterProperties cluster = getClusterProperties(serviceName, clusterName);
    LoadBalancerStateItem<UriProperties> uriItem = getUriItem(serviceName, clusterName, cluster);
    UriProperties uris = uriItem.getProperty();
    List<LoadBalancerState.SchemeStrategyPair> orderedStrategies = _state.getStrategiesForService(serviceName, service.getPrioritizedSchemes());
    if (!orderedStrategies.isEmpty()) {
        PartitionAccessor accessor = getPartitionAccessor(serviceName, clusterName);
        // first distribute keys to partitions
        Map<Integer, Set<K>> partitionSet = new HashMap<>();
        List<MapKeyResult.UnmappedKey<K>> unmappedKeys = new ArrayList<>();
        for (final K key : keys) {
            int partitionId;
            try {
                partitionId = accessor.getPartitionId(key.toString());
            } catch (PartitionAccessException e) {
                unmappedKeys.add(new MapKeyResult.UnmappedKey<>(key, MapKeyResult.ErrorType.FAIL_TO_FIND_PARTITION));
                continue;
            }
            Set<K> set = partitionSet.computeIfAbsent(partitionId, k -> new HashSet<>());
            set.add(key);
        }
        // then we find the ring for each partition and create a map of Ring<URI> to Set<K>
        final Map<Ring<URI>, Collection<K>> ringMap = new HashMap<>(partitionSet.size() * 2);
        for (Map.Entry<Integer, Set<K>> entry : partitionSet.entrySet()) {
            int partitionId = entry.getKey();
            Ring<URI> ring = null;
            for (LoadBalancerState.SchemeStrategyPair pair : orderedStrategies) {
                TrackerClientSubsetItem subsetItem = getPotentialClients(serviceName, service, cluster, uris, pair.getScheme(), partitionId, uriItem.getVersion());
                ring = pair.getStrategy().getRing(uriItem.getVersion(), partitionId, subsetItem.getWeightedSubset(), subsetItem.shouldForceUpdate());
                if (!ring.isEmpty()) {
                    // don't fallback to the next strategy if there are already hosts in the current one
                    break;
                }
            }
            // make sure the same ring is not used in other partition
            ringMap.put(ring, entry.getValue());
        }
        return new MapKeyResult<>(ringMap, unmappedKeys);
    } else {
        throw new ServiceUnavailableException(serviceName, "PEGA_1002. Unable to find a load balancer strategy. " + "Server Schemes: [" + String.join(", ", service.getPrioritizedSchemes()) + ']');
    }
}
Also used : Set(java.util.Set) HashSet(java.util.HashSet) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) ServiceUnavailableException(com.linkedin.d2.balancer.ServiceUnavailableException) URI(java.net.URI) LoadBalancerState(com.linkedin.d2.balancer.LoadBalancerState) UriProperties(com.linkedin.d2.balancer.properties.UriProperties) MapKeyResult(com.linkedin.d2.balancer.util.MapKeyResult) ServiceProperties(com.linkedin.d2.balancer.properties.ServiceProperties) PartitionAccessor(com.linkedin.d2.balancer.util.partitions.PartitionAccessor) Ring(com.linkedin.d2.balancer.util.hashing.Ring) ClusterProperties(com.linkedin.d2.balancer.properties.ClusterProperties) Collection(java.util.Collection) PartitionAccessException(com.linkedin.d2.balancer.util.partitions.PartitionAccessException) Map(java.util.Map) DarkClusterConfigMap(com.linkedin.d2.DarkClusterConfigMap) HashMap(java.util.HashMap) TreeMap(java.util.TreeMap)

Example 4 with ClusterProperties

use of com.linkedin.d2.balancer.properties.ClusterProperties in project rest.li by linkedin.

the class SimpleLoadBalancer method getClient.

/**
 * Given a Request, returns a TransportClient that can handle requests for the Request.
 * The callback is given a client that can be called to retrieve data for the URN.
 *
 * @param request
 *          A request whose URI is a URL of the format "d2://&gt;servicename&lt;/optional/path".
 * @param requestContext context for this request
 * @throws ServiceUnavailableException
 *           If the load balancer can't figure out how to reach a service for the given
 *           URN, an ServiceUnavailableException will be thrown.
 */
@Override
public void getClient(Request request, RequestContext requestContext, Callback<TransportClient> clientCallback) {
    URI uri = request.getURI();
    debug(_log, "get client for uri: ", uri);
    if (!D2_SCHEME_NAME.equalsIgnoreCase(uri.getScheme())) {
        throw new IllegalArgumentException("Unsupported scheme in URI " + uri);
    }
    // get the service for this uri
    String extractedServiceName = LoadBalancerUtil.getServiceNameFromUri(uri);
    listenToServiceAndCluster(extractedServiceName, Callbacks.handle(service -> {
        String serviceName = service.getServiceName();
        String clusterName = service.getClusterName();
        try {
            ClusterProperties cluster = getClusterProperties(serviceName, clusterName);
            // Check if we want to override the service URL and bypass choosing among the existing
            // tracker clients. This is useful when the service we want is not announcing itself to
            // the cluster, ie a private service for a set of clients. This mechanism is deprecated;
            // use host override list instead.
            @SuppressWarnings("deprecation") URI targetService = LoadBalancerUtil.TargetHints.getRequestContextTargetService(requestContext);
            // Checks if we have a host override list provided in the request context. If present,
            // get the override URI available override for the current cluster and service names.
            HostOverrideList overrides = (HostOverrideList) requestContext.getLocalAttr(HOST_OVERRIDE_LIST);
            URI override = overrides == null ? null : overrides.getOverride(clusterName, serviceName);
            if (targetService == null && override == null) {
                LoadBalancerStateItem<UriProperties> uriItem = getUriItem(serviceName, clusterName, cluster);
                UriProperties uris = uriItem.getProperty();
                List<LoadBalancerState.SchemeStrategyPair> orderedStrategies = _state.getStrategiesForService(serviceName, service.getPrioritizedSchemes());
                TrackerClient trackerClient = chooseTrackerClient(request, requestContext, serviceName, clusterName, cluster, uriItem, uris, orderedStrategies, service);
                String clusterAndServiceUriString = trackerClient.getUri() + service.getPath();
                _serviceAvailableStats.inc();
                clientCallback.onSuccess(new RewriteLoadBalancerClient(serviceName, URI.create(clusterAndServiceUriString), trackerClient));
            } else {
                URI target = override == null ? targetService : URI.create(override + service.getPath());
                if (targetService != null && override != null) {
                    _log.warn("Both TargetHints and HostOverrideList are found. HostOverList will take precedence %s.", target);
                }
                if (_log.isDebugEnabled()) {
                    _log.debug("Rewrite URI as specified in the TargetHints/HostOverrideList {} for cluster {} and service {}.", target, clusterName, serviceName);
                }
                TransportClient transportClient = _state.getClient(serviceName, target.getScheme());
                if (transportClient == null) {
                    throw new ServiceUnavailableException(serviceName, String.format("PEGA_1001. Cannot find transportClient for service %s and scheme %s with URI specified in" + "TargetHints/HostOverrideList %s", serviceName, target.getScheme(), target));
                }
                clientCallback.onSuccess(new RewriteLoadBalancerClient(serviceName, target, transportClient));
            }
        } catch (ServiceUnavailableException e) {
            clientCallback.onError(e);
        }
    }, clientCallback));
}
Also used : LoadBalancerStateListenerCallback(com.linkedin.d2.balancer.LoadBalancerState.LoadBalancerStateListenerCallback) NullStateListenerCallback(com.linkedin.d2.balancer.LoadBalancerState.NullStateListenerCallback) LoadBalancerStrategy(com.linkedin.d2.balancer.strategies.LoadBalancerStrategy) LoggerFactory(org.slf4j.LoggerFactory) TimeoutException(java.util.concurrent.TimeoutException) Random(java.util.Random) KeysAndHosts(com.linkedin.d2.balancer.util.KeysAndHosts) Request(com.linkedin.r2.message.Request) LoadBalancerStateItem(com.linkedin.d2.balancer.LoadBalancerStateItem) TransportClientFactory(com.linkedin.r2.transport.common.TransportClientFactory) Map(java.util.Map) URI(java.net.URI) HashFunction(com.linkedin.d2.balancer.util.hashing.HashFunction) ClusterProperties(com.linkedin.d2.balancer.properties.ClusterProperties) Collection(java.util.Collection) LogUtil.warn(com.linkedin.d2.discovery.util.LogUtil.warn) UriProperties(com.linkedin.d2.balancer.properties.UriProperties) Set(java.util.Set) Collectors(java.util.stream.Collectors) TimeoutCallback(com.linkedin.r2.transport.http.client.TimeoutCallback) RewriteLoadBalancerClient(com.linkedin.d2.balancer.clients.RewriteLoadBalancerClient) CountDownLatch(java.util.concurrent.CountDownLatch) List(java.util.List) None(com.linkedin.common.util.None) LoadBalancer(com.linkedin.d2.balancer.LoadBalancer) LoadBalancerState(com.linkedin.d2.balancer.LoadBalancerState) PropertyEventShutdownCallback(com.linkedin.d2.discovery.event.PropertyEventThread.PropertyEventShutdownCallback) PartitionData(com.linkedin.d2.balancer.properties.PartitionData) ServiceProperties(com.linkedin.d2.balancer.properties.ServiceProperties) PartitionInfoProvider(com.linkedin.d2.balancer.util.partitions.PartitionInfoProvider) Callbacks(com.linkedin.common.callback.Callbacks) DarkClusterConfigMap(com.linkedin.d2.DarkClusterConfigMap) PartitionAccessException(com.linkedin.d2.balancer.util.partitions.PartitionAccessException) LogUtil.debug(com.linkedin.d2.discovery.util.LogUtil.debug) FutureCallback(com.linkedin.common.callback.FutureCallback) PartitionAccessor(com.linkedin.d2.balancer.util.partitions.PartitionAccessor) Callback(com.linkedin.common.callback.Callback) TransportClient(com.linkedin.r2.transport.common.bridge.client.TransportClient) HashMap(java.util.HashMap) LoadBalancerClusterListener(com.linkedin.d2.balancer.LoadBalancerClusterListener) ArrayList(java.util.ArrayList) HashSet(java.util.HashSet) HashRingProvider(com.linkedin.d2.balancer.util.hashing.HashRingProvider) ClusterInfoProvider(com.linkedin.d2.balancer.util.ClusterInfoProvider) ScheduledExecutorService(java.util.concurrent.ScheduledExecutorService) Ring(com.linkedin.d2.balancer.util.hashing.Ring) HostOverrideList(com.linkedin.d2.balancer.util.HostOverrideList) ClientFactoryProvider(com.linkedin.d2.balancer.util.ClientFactoryProvider) SubsettingState(com.linkedin.d2.balancer.subsetting.SubsettingState) Logger(org.slf4j.Logger) Iterator(java.util.Iterator) Stats(com.linkedin.d2.discovery.util.Stats) HostToKeyMapper(com.linkedin.d2.balancer.util.HostToKeyMapper) ExecutionException(java.util.concurrent.ExecutionException) TimeUnit(java.util.concurrent.TimeUnit) WarmUpService(com.linkedin.d2.balancer.WarmUpService) RequestContext(com.linkedin.r2.message.RequestContext) TreeMap(java.util.TreeMap) LogUtil.info(com.linkedin.d2.discovery.util.LogUtil.info) KeyMapper(com.linkedin.d2.balancer.KeyMapper) MapKeyResult(com.linkedin.d2.balancer.util.MapKeyResult) ServiceUnavailableException(com.linkedin.d2.balancer.ServiceUnavailableException) Collections(java.util.Collections) TrackerClient(com.linkedin.d2.balancer.clients.TrackerClient) LoadBalancerUtil(com.linkedin.d2.balancer.util.LoadBalancerUtil) TransportClient(com.linkedin.r2.transport.common.bridge.client.TransportClient) RewriteLoadBalancerClient(com.linkedin.d2.balancer.clients.RewriteLoadBalancerClient) ServiceUnavailableException(com.linkedin.d2.balancer.ServiceUnavailableException) URI(java.net.URI) LoadBalancerState(com.linkedin.d2.balancer.LoadBalancerState) TrackerClient(com.linkedin.d2.balancer.clients.TrackerClient) UriProperties(com.linkedin.d2.balancer.properties.UriProperties) HostOverrideList(com.linkedin.d2.balancer.util.HostOverrideList) ClusterProperties(com.linkedin.d2.balancer.properties.ClusterProperties) LoadBalancerStateItem(com.linkedin.d2.balancer.LoadBalancerStateItem) List(java.util.List) ArrayList(java.util.ArrayList) HostOverrideList(com.linkedin.d2.balancer.util.HostOverrideList)

Example 5 with ClusterProperties

use of com.linkedin.d2.balancer.properties.ClusterProperties in project rest.li by linkedin.

the class SimpleLoadBalancer method getPotentialClients.

private Map<URI, TrackerClient> getPotentialClients(String serviceName, ServiceProperties serviceProperties, ClusterProperties clusterProperties, Set<URI> possibleUris, int partitionId, SubsettingState.SubsetItem subsetItem) {
    Map<URI, TrackerClient> clientsToLoadBalance;
    if (possibleUris == null) {
        // just return an empty list if possibleUris is 'null'.
        clientsToLoadBalance = Collections.emptyMap();
    } else {
        Map<URI, Double> weightedSubset = subsetItem.getWeightedUriSubset();
        ;
        Set<URI> doNotSlowStartUris = subsetItem.getDoNotSlowStartUris();
        clientsToLoadBalance = new HashMap<>(possibleUris.size());
        for (URI possibleUri : possibleUris) {
            // don't pay attention to this uri if it's banned or not in the subset
            if (!serviceProperties.isBanned(possibleUri) && !clusterProperties.isBanned(possibleUri)) {
                if (weightedSubset.containsKey(possibleUri)) {
                    TrackerClient possibleTrackerClient = _state.getClient(serviceName, possibleUri);
                    if (possibleTrackerClient != null) {
                        if (doNotSlowStartUris.contains(possibleUri)) {
                            possibleTrackerClient.setDoNotSlowStart(true);
                        }
                        // Only update subset weight if the subset item is a weighted subset
                        if (subsetItem.isWeightedSubset()) {
                            possibleTrackerClient.setSubsetWeight(partitionId, weightedSubset.get(possibleUri));
                        }
                        clientsToLoadBalance.put(possibleUri, possibleTrackerClient);
                    }
                }
            } else {
                warn(_log, "skipping banned uri: ", possibleUri);
            }
        }
    }
    debug(_log, "got clients to load balancer for ", serviceName, ": ", clientsToLoadBalance);
    return clientsToLoadBalance;
}
Also used : TrackerClient(com.linkedin.d2.balancer.clients.TrackerClient) URI(java.net.URI)

Aggregations

ClusterProperties (com.linkedin.d2.balancer.properties.ClusterProperties)72 HashMap (java.util.HashMap)51 ServiceProperties (com.linkedin.d2.balancer.properties.ServiceProperties)49 Test (org.testng.annotations.Test)47 ArrayList (java.util.ArrayList)42 UriProperties (com.linkedin.d2.balancer.properties.UriProperties)41 URI (java.net.URI)38 Map (java.util.Map)32 PartitionData (com.linkedin.d2.balancer.properties.PartitionData)24 DegraderLoadBalancerTest (com.linkedin.d2.balancer.strategies.degrader.DegraderLoadBalancerTest)24 List (java.util.List)20 NullStateListenerCallback (com.linkedin.d2.balancer.LoadBalancerState.NullStateListenerCallback)18 LoadBalancerStrategy (com.linkedin.d2.balancer.strategies.LoadBalancerStrategy)18 None (com.linkedin.common.util.None)16 TransportClientFactory (com.linkedin.r2.transport.common.TransportClientFactory)16 FutureCallback (com.linkedin.common.callback.FutureCallback)15 HashSet (java.util.HashSet)14 DarkClusterConfigMap (com.linkedin.d2.DarkClusterConfigMap)13 RequestContext (com.linkedin.r2.message.RequestContext)13 ClusterPropertiesJsonSerializer (com.linkedin.d2.balancer.properties.ClusterPropertiesJsonSerializer)12