Search in sources :

Example 6 with TrackerClient

use of com.linkedin.d2.balancer.clients.TrackerClient in project rest.li by linkedin.

the class SimpleLoadBalancerState method refreshTransportClientsPerService.

void refreshTransportClientsPerService(ServiceProperties serviceProperties) {
    String serviceName = serviceProperties.getServiceName();
    //create new TransportClients
    Map<String, TransportClient> newTransportClients = createAndInsertTransportClientTo(serviceProperties);
    // clients-by-scheme map is never edited, only replaced.
    newTransportClients = Collections.unmodifiableMap(newTransportClients);
    final Map<String, TransportClient> oldTransportClients = _serviceClients.put(serviceName, newTransportClients);
    // gets the information for configuring the parameter for how DegraderImpl should behave for
    // each tracker clients that we instantiate here. If there's no such information, then we'll instantiate
    // each tracker clients with default configuration
    DegraderImpl.Config config = null;
    if (serviceProperties.getDegraderProperties() != null && !serviceProperties.getDegraderProperties().isEmpty()) {
        config = DegraderConfigFactory.toDegraderConfig(serviceProperties.getDegraderProperties());
    } else {
        debug(_log, "trying to see if there's a special degraderImpl properties but serviceInfo.getDegraderImpl() is null" + " for service name = " + serviceName + " so we'll set config to default");
    }
    Clock clk = SystemClock.instance();
    if (serviceProperties.getLoadBalancerStrategyProperties() != null) {
        Map<String, Object> loadBalancerStrategyProperties = serviceProperties.getLoadBalancerStrategyProperties();
        clk = MapUtil.getWithDefault(loadBalancerStrategyProperties, PropertyKeys.CLOCK, SystemClock.instance(), Clock.class);
    }
    Map<URI, TrackerClient> newTrackerClients;
    // update all tracker clients to use new configs
    LoadBalancerStateItem<UriProperties> uriItem = _uriProperties.get(serviceProperties.getClusterName());
    UriProperties uriProperties = uriItem == null ? null : uriItem.getProperty();
    if (uriProperties != null) {
        Set<URI> uris = uriProperties.Uris();
        // clients-by-uri map may be edited later by UriPropertiesListener.handlePut
        newTrackerClients = new ConcurrentHashMap<URI, TrackerClient>(CollectionUtils.getMapInitialCapacity(uris.size(), 0.75f), 0.75f, 1);
        long trackerClientInterval = getTrackerClientInterval(serviceProperties);
        String errorStatusPattern = getErrorStatusPattern(serviceProperties);
        for (URI uri : uris) {
            TrackerClient trackerClient = getTrackerClient(serviceName, uri, uriProperties.getPartitionDataMap(uri), config, clk, trackerClientInterval, errorStatusPattern);
            if (trackerClient != null) {
                newTrackerClients.put(uri, trackerClient);
            }
        }
    } else {
        // clients-by-uri map may be edited later by UriPropertiesListener.handlePut
        newTrackerClients = new ConcurrentHashMap<URI, TrackerClient>(16, 0.75f, 1);
    }
    //override the oldTrackerClients with newTrackerClients
    _trackerClients.put(serviceName, newTrackerClients);
    // No need to shut down oldTrackerClients, because they all point directly to the TransportClient for the service
    // We do need to shut down the old transport clients
    shutdownTransportClients(oldTransportClients, serviceName);
}
Also used : TransportClient(com.linkedin.r2.transport.common.bridge.client.TransportClient) DegraderImpl(com.linkedin.util.degrader.DegraderImpl) SystemClock(com.linkedin.util.clock.SystemClock) Clock(com.linkedin.util.clock.Clock) URI(java.net.URI) TrackerClient(com.linkedin.d2.balancer.clients.TrackerClient) UriProperties(com.linkedin.d2.balancer.properties.UriProperties)

Example 7 with TrackerClient

use of com.linkedin.d2.balancer.clients.TrackerClient in project rest.li by linkedin.

the class SimpleLoadBalancerState method shutdown.

@Override
public void shutdown(final PropertyEventShutdownCallback shutdown) {
    trace(_log, "shutdown");
    // shutdown all three registries, all tracker clients, and the event thread
    _executor.execute(new PropertyEvent("shutdown load balancer state") {

        @Override
        public void innerRun() {
            // Need to shutdown loadBalancerStrategies before the transportClients are shutdown
            for (Map<String, LoadBalancerStrategy> strategyEntry : _serviceStrategies.values()) {
                strategyEntry.values().forEach(LoadBalancerStrategy::shutdown);
            }
            // put all tracker clients into a single set for convenience
            Set<TransportClient> transportClients = new HashSet<TransportClient>();
            for (Map<String, TransportClient> clientsByScheme : _serviceClients.values()) {
                transportClients.addAll(clientsByScheme.values());
            }
            Callback<None> trackerCallback = Callbacks.countDown(Callbacks.<None>adaptSimple(new SimpleCallback() {

                @Override
                public void onDone() {
                    shutdown.done();
                }
            }), transportClients.size());
            info(_log, "shutting down cluster clients");
            for (TransportClient transportClient : transportClients) {
                transportClient.shutdown(trackerCallback);
            }
            // so it is needed to notify all the listeners
            for (SimpleLoadBalancerStateListener listener : _listeners) {
                // Notify the strategy removal
                for (Map.Entry<String, Map<String, LoadBalancerStrategy>> serviceStrategy : _serviceStrategies.entrySet()) {
                    for (Map.Entry<String, LoadBalancerStrategy> strategyEntry : serviceStrategy.getValue().entrySet()) {
                        listener.onStrategyRemoved(serviceStrategy.getKey(), strategyEntry.getKey(), strategyEntry.getValue());
                    }
                    // Also notify the client removal
                    Map<URI, TrackerClient> trackerClients = _trackerClients.get(serviceStrategy.getKey());
                    if (trackerClients != null) {
                        for (TrackerClient client : trackerClients.values()) {
                            listener.onClientRemoved(serviceStrategy.getKey(), client);
                        }
                    }
                }
            }
        }
    });
}
Also used : TransportClient(com.linkedin.r2.transport.common.bridge.client.TransportClient) Set(java.util.Set) HashSet(java.util.HashSet) PropertyEvent(com.linkedin.d2.discovery.event.PropertyEventThread.PropertyEvent) LoadBalancerStrategy(com.linkedin.d2.balancer.strategies.LoadBalancerStrategy) PropertyEventShutdownCallback(com.linkedin.d2.discovery.event.PropertyEventThread.PropertyEventShutdownCallback) Callback(com.linkedin.common.callback.Callback) SimpleCallback(com.linkedin.common.callback.SimpleCallback) TrackerClient(com.linkedin.d2.balancer.clients.TrackerClient) Map(java.util.Map) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) HashMap(java.util.HashMap) ConcurrentMap(java.util.concurrent.ConcurrentMap) None(com.linkedin.common.util.None) SimpleCallback(com.linkedin.common.callback.SimpleCallback)

Example 8 with TrackerClient

use of com.linkedin.d2.balancer.clients.TrackerClient in project rest.li by linkedin.

the class DegraderLoadBalancerStrategyV2 method getTrackerClient.

@Override
public TrackerClient getTrackerClient(Request request, RequestContext requestContext, long clusterGenerationId, int partitionId, List<TrackerClient> trackerClients) {
    if (partitionId != DEFAULT_PARTITION_ID) {
        throw new UnsupportedOperationException("Trying to access partition: " + partitionId + "on an unpartitioned cluster");
    }
    debug(_log, "getTrackerClient with generation id ", clusterGenerationId, " on tracker clients: ", clusterGenerationId);
    if (trackerClients == null || trackerClients.size() == 0) {
        warn(_log, "getTrackerClient called with null/empty trackerClients, so returning null");
        return null;
    }
    // only one thread will be allowed to enter updateState, so if multiple threads call
    // getTrackerClient while the _state is not populated, they won't be able return a
    // tracker client from the hash ring, and will return null.
    checkUpdateState(clusterGenerationId, trackerClients);
    boolean hasInitializationError = _state.hasError();
    URI targetHostUri = KeyMapper.TargetHostHints.getRequestContextTargetHost(requestContext);
    Set<URI> excludedUris = ExcludedHostHints.getRequestContextExcludedHosts(requestContext);
    URI hostHeaderUri = targetHostUri;
    //no valid target host header was found in the request
    if (!hasInitializationError && targetHostUri == null) {
        // Compute the hash code
        int hashCode = _hashFunction.hash(request);
        // we operate only on URIs to ensure that we never hold on to an old tracker client
        // that the cluster manager has removed
        Ring<URI> ring = _state.getRing();
        Iterator<URI> iterator = ring.getIterator(hashCode);
        while (iterator.hasNext() && targetHostUri == null) {
            URI uri = iterator.next();
            if (excludedUris == null || !excludedUris.contains(uri)) {
                targetHostUri = uri;
            }
        }
        ExcludedHostHints.addRequestContextExcludedHost(requestContext, targetHostUri);
    } else if (hasInitializationError && targetHostUri == null) {
        //if we encounter an error while initializing the state, we'll choose a tracker client at random
        targetHostUri = trackerClients.get(new Random().nextInt(trackerClients.size())).getUri();
    } else {
        debug(_log, "Degrader honoring target host header in request, skipping hashing.  URI: " + targetHostUri.toString());
    }
    TrackerClient client = null;
    if (targetHostUri != null) {
        // consistent hash ring! Therefore, this linear scan is the best we can do.
        for (TrackerClient trackerClient : trackerClients) {
            if (trackerClient.getUri().equals(targetHostUri)) {
                client = trackerClient;
                break;
            }
        }
        if (client == null) {
            warn(_log, "No client found for " + targetHostUri + (hostHeaderUri == null ? ", degrader load balancer state is inconsistent with cluster manager" : ", target host specified is no longer part of cluster"));
        }
    } else {
        warn(_log, "unable to find a URI to use");
    }
    boolean dropCall = client == null;
    if (!dropCall) {
        dropCall = client.getDegrader(DEFAULT_PARTITION_ID).checkDrop();
        if (dropCall) {
            warn(_log, "client's degrader is dropping call for: ", client);
        } else {
            debug(_log, "returning client: ", client);
        }
    }
    return (!dropCall) ? client : null;
}
Also used : Random(java.util.Random) TrackerClient(com.linkedin.d2.balancer.clients.TrackerClient) URI(java.net.URI)

Example 9 with TrackerClient

use of com.linkedin.d2.balancer.clients.TrackerClient in project rest.li by linkedin.

the class DegraderLoadBalancerStrategyV2 method overrideMinCallCount.

/**
   * Both the drop in hash ring points and the global drop rate influence the minimum call count
   * that we should see to qualify for a state update. Currently, both factors are equally weighed,
   * and multiplied together to come up with a scale factor. With this scheme, if either factor is
   * zero, then the overrideMinCallCount will be set to 1. If both factors are at half weight, then
   * the overall weight will be .5 * .5 = .25 of the original minCallCount.
   *
   * @param newOverrideDropRate
   * @param trackerClients
   * @param pointsMap
   * @param pointsPerWeight
   */
public static void overrideMinCallCount(double newOverrideDropRate, List<TrackerClient> trackerClients, Map<URI, Integer> pointsMap, int pointsPerWeight) {
    for (TrackerClient client : trackerClients) {
        int currentOverrideMinCallCount = client.getDegraderControl(DEFAULT_PARTITION_ID).getOverrideMinCallCount();
        double hashFactor = pointsMap.get(client.getUri()) / pointsPerWeight;
        double transmitFactor = 1.0 - newOverrideDropRate;
        int newOverrideMinCallCount = (int) Math.max(Math.round(client.getDegraderControl(DEFAULT_PARTITION_ID).getMinCallCount() * hashFactor * transmitFactor), 1);
        if (newOverrideMinCallCount != currentOverrideMinCallCount) {
            client.getDegraderControl(DEFAULT_PARTITION_ID).setOverrideMinCallCount(newOverrideMinCallCount);
            warn(_log, "overriding Min Call Count to ", newOverrideMinCallCount, " for client: ", client.getUri());
        }
    }
}
Also used : TrackerClient(com.linkedin.d2.balancer.clients.TrackerClient)

Example 10 with TrackerClient

use of com.linkedin.d2.balancer.clients.TrackerClient in project rest.li by linkedin.

the class DegraderLoadBalancerStrategyV2 method getUnhealthyTrackerClients.

private static List<String> getUnhealthyTrackerClients(List<TrackerClient> trackerClients, Map<URI, Integer> pointsMap, DegraderLoadBalancerStrategyConfig config) {
    List<String> unhealthyClients = new ArrayList<String>();
    for (TrackerClient client : trackerClients) {
        int perfectHealth = (int) (client.getPartitionWeight(DEFAULT_PARTITION_ID) * config.getPointsPerWeight());
        Integer point = pointsMap.get(client.getUri());
        if (point < perfectHealth) {
            unhealthyClients.add(client.getUri() + ":" + point + "/" + perfectHealth);
        }
    }
    return unhealthyClients;
}
Also used : TrackerClient(com.linkedin.d2.balancer.clients.TrackerClient) ArrayList(java.util.ArrayList)

Aggregations

TrackerClient (com.linkedin.d2.balancer.clients.TrackerClient)94 URI (java.net.URI)57 Test (org.testng.annotations.Test)53 ArrayList (java.util.ArrayList)52 HashMap (java.util.HashMap)51 TrackerClientTest (com.linkedin.d2.balancer.clients.TrackerClientTest)39 RequestContext (com.linkedin.r2.message.RequestContext)33 PartitionData (com.linkedin.d2.balancer.properties.PartitionData)23 DegraderImpl (com.linkedin.util.degrader.DegraderImpl)17 ServiceProperties (com.linkedin.d2.balancer.properties.ServiceProperties)16 AtomicLong (java.util.concurrent.atomic.AtomicLong)16 UriProperties (com.linkedin.d2.balancer.properties.UriProperties)15 DegraderControl (com.linkedin.util.degrader.DegraderControl)13 Map (java.util.Map)13 NullStateListenerCallback (com.linkedin.d2.balancer.LoadBalancerState.NullStateListenerCallback)11 DegraderLoadBalancerTest (com.linkedin.d2.balancer.strategies.degrader.DegraderLoadBalancerTest)11 CallCompletion (com.linkedin.util.degrader.CallCompletion)11 ClusterProperties (com.linkedin.d2.balancer.properties.ClusterProperties)9 URIRequest (com.linkedin.d2.balancer.util.URIRequest)9 HashSet (java.util.HashSet)8