Search in sources :

Example 1 with Clock

use of com.linkedin.util.clock.Clock 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 2 with Clock

use of com.linkedin.util.clock.Clock in project rest.li by linkedin.

the class TrackerClientTest method testClientRestRequest.

@Test(groups = { "small", "back-end" })
public void testClientRestRequest() throws URISyntaxException {
    URI uri = URI.create("http://test.qa.com:1234/foo");
    double weight = 3d;
    TestClient wrappedClient = new TestClient();
    Clock clock = new SettableClock();
    Map<Integer, PartitionData> partitionDataMap = new HashMap<Integer, PartitionData>(2);
    partitionDataMap.put(DefaultPartitionAccessor.DEFAULT_PARTITION_ID, new PartitionData(3d));
    TrackerClient client = new TrackerClient(uri, partitionDataMap, wrappedClient, clock, null);
    assertEquals(client.getUri(), uri);
    Double clientWeight = client.getPartitionWeight(DefaultPartitionAccessor.DEFAULT_PARTITION_ID);
    assertEquals(clientWeight, weight);
    assertEquals(client.getWrappedClient(), wrappedClient);
    RestRequest restRequest = new RestRequestBuilder(uri).build();
    Map<String, String> restWireAttrs = new HashMap<String, String>();
    TestTransportCallback<RestResponse> restCallback = new TestTransportCallback<RestResponse>();
    client.restRequest(restRequest, new RequestContext(), restWireAttrs, restCallback);
    assertFalse(restCallback.response.hasError());
    assertEquals(wrappedClient.restRequest, restRequest);
    assertEquals(wrappedClient.restWireAttrs, restWireAttrs);
}
Also used : HashMap(java.util.HashMap) RestResponse(com.linkedin.r2.message.rest.RestResponse) ByteString(com.linkedin.data.ByteString) Clock(com.linkedin.util.clock.Clock) SettableClock(com.linkedin.util.clock.SettableClock) URI(java.net.URI) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) RestRequest(com.linkedin.r2.message.rest.RestRequest) PartitionData(com.linkedin.d2.balancer.properties.PartitionData) SettableClock(com.linkedin.util.clock.SettableClock) RestRequestBuilder(com.linkedin.r2.message.rest.RestRequestBuilder) RequestContext(com.linkedin.r2.message.RequestContext) Test(org.testng.annotations.Test)

Example 3 with Clock

use of com.linkedin.util.clock.Clock in project rest.li by linkedin.

the class LoadBalancerStrategyBenchmark method createTrackerClients.

private static Map<URI, TrackerClient> createTrackerClients(int numHosts) {
    Map<URI, TrackerClient> trackerClients = new HashMap<>();
    for (int i = 0; i < numHosts; i++) {
        URI uri = URI.create(URI_PREFIX + i + URI_SUFFIX);
        trackerClients.put(uri, new TrackerClientImpl(uri, DEFAULT_PARTITION_DATA_MAP, new BaseTransportTestClient(), CLOCK, RelativeLoadBalancerStrategyFactory.DEFAULT_UPDATE_INTERVAL_MS, (status) -> status >= 500 && status <= 599));
    }
    return trackerClients;
}
Also used : Arrays(java.util.Arrays) BenchmarkMode(org.openjdk.jmh.annotations.BenchmarkMode) RelativeLoadBalancerStrategy(com.linkedin.d2.balancer.strategies.relative.RelativeLoadBalancerStrategy) NamedThreadFactory(com.linkedin.r2.util.NamedThreadFactory) Measurement(org.openjdk.jmh.annotations.Measurement) D2RelativeStrategyProperties(com.linkedin.d2.D2RelativeStrategyProperties) RestRequestBuilder(com.linkedin.r2.message.rest.RestRequestBuilder) HashMap(java.util.HashMap) Scope(org.openjdk.jmh.annotations.Scope) Warmup(org.openjdk.jmh.annotations.Warmup) ArrayList(java.util.ArrayList) URIRequest(com.linkedin.d2.balancer.util.URIRequest) Request(com.linkedin.r2.message.Request) OutputTimeUnit(org.openjdk.jmh.annotations.OutputTimeUnit) Map(java.util.Map) ScheduledExecutorService(java.util.concurrent.ScheduledExecutorService) SystemClock(com.linkedin.util.clock.SystemClock) URI(java.net.URI) RelativeLoadBalancerStrategyFactory(com.linkedin.d2.balancer.strategies.relative.RelativeLoadBalancerStrategyFactory) RestRequest(com.linkedin.r2.message.rest.RestRequest) Setup(org.openjdk.jmh.annotations.Setup) Mode(org.openjdk.jmh.annotations.Mode) Clock(com.linkedin.util.clock.Clock) DegraderLoadBalancerStrategyV3(com.linkedin.d2.balancer.strategies.degrader.DegraderLoadBalancerStrategyV3) DegraderTrackerClientImpl(com.linkedin.d2.balancer.clients.DegraderTrackerClientImpl) TrackerClientImpl(com.linkedin.d2.balancer.clients.TrackerClientImpl) State(org.openjdk.jmh.annotations.State) Executors(java.util.concurrent.Executors) Benchmark(org.openjdk.jmh.annotations.Benchmark) DegraderLoadBalancerStrategyFactoryV3(com.linkedin.d2.balancer.strategies.degrader.DegraderLoadBalancerStrategyFactoryV3) TimeUnit(java.util.concurrent.TimeUnit) List(java.util.List) RequestContext(com.linkedin.r2.message.RequestContext) RelativeStrategyPropertiesConverter(com.linkedin.d2.balancer.config.RelativeStrategyPropertiesConverter) Level(org.openjdk.jmh.annotations.Level) Fork(org.openjdk.jmh.annotations.Fork) PartitionData(com.linkedin.d2.balancer.properties.PartitionData) ServiceProperties(com.linkedin.d2.balancer.properties.ServiceProperties) TrackerClient(com.linkedin.d2.balancer.clients.TrackerClient) TrackerClient(com.linkedin.d2.balancer.clients.TrackerClient) HashMap(java.util.HashMap) URI(java.net.URI) DegraderTrackerClientImpl(com.linkedin.d2.balancer.clients.DegraderTrackerClientImpl) TrackerClientImpl(com.linkedin.d2.balancer.clients.TrackerClientImpl)

Example 4 with Clock

use of com.linkedin.util.clock.Clock in project rest.li by linkedin.

the class DegraderLoadBalancerStrategyConfig method createHttpConfigFromMap.

static DegraderLoadBalancerStrategyConfig createHttpConfigFromMap(Map<String, Object> map, HealthCheckOperations healthCheckOperations, ScheduledExecutorService overrideExecutorService, Map<String, String> degraderProperties, EventEmitter emitter) {
    Clock clock = MapUtil.getWithDefault(map, PropertyKeys.CLOCK, DEFAULT_CLOCK, Clock.class);
    Long updateIntervalMs = MapUtil.getWithDefault(map, PropertyKeys.HTTP_LB_STRATEGY_PROPERTIES_UPDATE_INTERVAL_MS, DEFAULT_UPDATE_INTERVAL_MS, Long.class);
    Boolean updateOnlyAtInterval = MapUtil.getWithDefault(map, PropertyKeys.HTTP_LB_STRATEGY_PROPERTIES_UPDATE_ONLY_AT_INTERVAL, DEFAULT_UPDATE_ONLY_AT_INTERVAL, Boolean.class);
    Integer pointsPerWeight = MapUtil.getWithDefault(map, PropertyKeys.HTTP_LB_STRATEGY_PROPERTIES_POINTS_PER_WEIGHT, DEFAULT_POINTS_PER_WEIGHT, Integer.class);
    String hashMethod = MapUtil.getWithDefault(map, PropertyKeys.HTTP_LB_HASH_METHOD, null, String.class);
    Long minClusterCallCountHighWaterMark = MapUtil.getWithDefault(map, PropertyKeys.HTTP_LB_CLUSTER_MIN_CALL_COUNT_HIGH_WATER_MARK, DEFAULT_CLUSTER_MIN_CALL_COUNT_HIGH_WATER_MARK, Long.class);
    Long minClusterCallCountLowWaterMark = MapUtil.getWithDefault(map, PropertyKeys.HTTP_LB_CLUSTER_MIN_CALL_COUNT_LOW_WATER_MARK, DEFAULT_CLUSTER_MIN_CALL_COUNT_HIGH_WATER_MARK, Long.class);
    Double initialRecoveryLevel = MapUtil.getWithDefault(map, PropertyKeys.HTTP_LB_INITIAL_RECOVERY_LEVEL, DEFAULT_INITIAL_RECOVERY_LEVEL, Double.class);
    Double ringRampFactor = MapUtil.getWithDefault(map, PropertyKeys.HTTP_LB_RING_RAMP_FACTOR, DEFAULT_RAMP_FACTOR, Double.class);
    Double highWaterMark = MapUtil.getWithDefault(map, PropertyKeys.HTTP_LB_HIGH_WATER_MARK, DEFAULT_HIGH_WATER_MARK, Double.class);
    Double lowWaterMark = MapUtil.getWithDefault(map, PropertyKeys.HTTP_LB_LOW_WATER_MARK, DEFAULT_LOW_WATER_MARK, Double.class);
    Double globalStepUp = MapUtil.getWithDefault(map, PropertyKeys.HTTP_LB_GLOBAL_STEP_UP, DEFAULT_GLOBAL_STEP_UP, Double.class);
    Double globalStepDown = MapUtil.getWithDefault(map, PropertyKeys.HTTP_LB_GLOBAL_STEP_DOWN, DEFAULT_GLOBAL_STEP_DOWN, Double.class);
    Object obj = MapUtil.getWithDefault(map, PropertyKeys.HTTP_LB_HASH_CONFIG, Collections.emptyMap(), Map.class);
    // // to appease java 7, which appears to have compilation bugs that cause it to ignore some suppressions, needed to first assign to obj, then assign to the map
    @SuppressWarnings("unchecked") Map<String, Object> hashConfig = (Map<String, Object>) obj;
    Double hashRingPointCleanUpRate = MapUtil.getWithDefault(map, PropertyKeys.HTTP_LB_HASHRING_POINT_CLEANUP_RATE, DEFAULT_HASHRING_POINT_CLEANUP_RATE, Double.class);
    String consistentHashAlgorithm = MapUtil.getWithDefault(map, PropertyKeys.HTTP_LB_CONSISTENT_HASH_ALGORITHM, null, String.class);
    Integer numProbes = MapUtil.getWithDefault(map, PropertyKeys.HTTP_LB_CONSISTENT_HASH_NUM_PROBES, DEFAULT_NUM_PROBES);
    Integer pointsPerHost = MapUtil.getWithDefault(map, PropertyKeys.HTTP_LB_CONSISTENT_HASH_POINTS_PER_HOST, DEFAULT_POINTS_PER_HOST);
    Double boundedLoadBalancingFactor = MapUtil.getWithDefault(map, PropertyKeys.HTTP_LB_CONSISTENT_HASH_BOUNDED_LOAD_BALANCING_FACTOR, DEFAULT_BOUNDED_LOAD_BALANCING_FACTOR, Double.class);
    String servicePath = MapUtil.getWithDefault(map, PropertyKeys.PATH, null, String.class);
    Double quarantineMaxPercent = MapUtil.getWithDefault(map, PropertyKeys.HTTP_LB_QUARANTINE_MAX_PERCENT, DEFAULT_QUARANTINE_MAXPERCENT, Double.class);
    if (quarantineMaxPercent > QUARANTINE_MAXPERCENT_CAP) {
        // if the user configures the max percent to a very high value, it can dramatically limit the capacity of the
        // cluster when something goes wrong. So impose a cap to max percent.
        quarantineMaxPercent = QUARANTINE_MAXPERCENT_CAP;
        _log.warn("MaxPercent value {} is too high. Changed it to {}", quarantineMaxPercent, QUARANTINE_MAXPERCENT_CAP);
    }
    ScheduledExecutorService executorService = MapUtil.getWithDefault(map, PropertyKeys.HTTP_LB_QUARANTINE_EXECUTOR_SERVICE, null, ScheduledExecutorService.class);
    String method = MapUtil.getWithDefault(map, PropertyKeys.HTTP_LB_QUARANTINE_METHOD, DEFAULT_QUARANTINE_METHOD, String.class);
    // lowLatency reflects the expected health threshold for the service so we can use this value as the
    // quarantine health checking latency.
    Long quarantineLatency = (degraderProperties == null) ? DegraderImpl.DEFAULT_LOW_LATENCY : MapUtil.getWithDefault(degraderProperties, PropertyKeys.DEGRADER_LOW_LATENCY, DegraderImpl.DEFAULT_LOW_LATENCY, Long.class);
    // operations of the service therefore should not take that long
    if (quarantineLatency > MAX_QUARANTINE_LATENCY) {
        quarantineLatency = MAX_QUARANTINE_LATENCY;
    }
    // health checking method can be customized from d2config.
    // The supported format is "<Restli Method>:<URI path>". Both part are optional.
    // If <Restli method> is missing, the default method is 'OPTIONS'. If the <URI path>
    // is missing, the service path will be used. For example, "OPTIONS:" and
    // "GET:/contextPath/service/resources/1234" are all valid settings. Specifically,
    // "GET:/<contextPath>/admin" can be used for admin node health checking, where
    // <contextPath> has to match the product-spec.json topology configuration.
    String healthCheckMethod = method;
    String healthCheckPath = null;
    int idx = method.indexOf(':');
    if (idx != -1) {
        // Currently allows user to specify any method for health checking (including non-idempotent one)
        healthCheckMethod = method.substring(0, idx);
        healthCheckPath = method.substring(idx + 1);
    }
    if (healthCheckMethod.isEmpty()) {
        healthCheckMethod = DEFAULT_QUARANTINE_METHOD;
    }
    Long lowEmittingInterval = MapUtil.getWithDefault(map, PropertyKeys.HTTP_LB_LOW_EVENT_EMITTING_INTERVAL, DEFAULT_LOW_EVENT_EMITTING_INTERVAL, Long.class);
    Long highEmittingInterval = MapUtil.getWithDefault(map, PropertyKeys.HTTP_LB_HIGH_EVENT_EMITTING_INTERVAL, DEFAULT_HIGH_EVENT_EMITTING_INTERVAL, Long.class);
    final String clusterName = MapUtil.getWithDefault(map, PropertyKeys.CLUSTER_NAME, DEFAULT_CLUSTER_NAME, String.class);
    return new DegraderLoadBalancerStrategyConfig(updateIntervalMs, updateOnlyAtInterval, pointsPerWeight, hashMethod, hashConfig, clock, initialRecoveryLevel, ringRampFactor, highWaterMark, lowWaterMark, globalStepUp, globalStepDown, minClusterCallCountHighWaterMark, minClusterCallCountLowWaterMark, hashRingPointCleanUpRate, consistentHashAlgorithm, numProbes, pointsPerHost, boundedLoadBalancingFactor, servicePath, quarantineMaxPercent, overrideExecutorService != null ? overrideExecutorService : executorService, healthCheckOperations, healthCheckMethod, healthCheckPath, quarantineLatency, emitter, lowEmittingInterval, highEmittingInterval, clusterName);
}
Also used : ScheduledExecutorService(java.util.concurrent.ScheduledExecutorService) Clock(com.linkedin.util.clock.Clock) SystemClock(com.linkedin.util.clock.SystemClock) Map(java.util.Map)

Example 5 with Clock

use of com.linkedin.util.clock.Clock in project rest.li by linkedin.

the class DegraderTrackerClientTest method testClientRestRequest.

@Test(groups = { "small", "back-end" })
public void testClientRestRequest() throws URISyntaxException {
    URI uri = URI.create("http://test.qa.com:1234/foo");
    double weight = 3d;
    TestClient wrappedClient = new TestClient();
    Clock clock = new SettableClock();
    Map<Integer, PartitionData> partitionDataMap = createDefaultPartitionData(3d);
    DegraderTrackerClient client = new DegraderTrackerClientImpl(uri, partitionDataMap, wrappedClient, clock, null);
    Assert.assertEquals(client.getUri(), uri);
    Double clientWeight = client.getPartitionWeight(DefaultPartitionAccessor.DEFAULT_PARTITION_ID);
    Assert.assertEquals(clientWeight, weight);
    Assert.assertEquals(client.getTransportClient(), wrappedClient);
    RestRequest restRequest = new RestRequestBuilder(uri).build();
    Map<String, String> restWireAttrs = new HashMap<>();
    TestTransportCallback<RestResponse> restCallback = new TestTransportCallback<>();
    client.restRequest(restRequest, new RequestContext(), restWireAttrs, restCallback);
    Assert.assertFalse(restCallback.response.hasError());
    Assert.assertEquals(wrappedClient.restRequest, restRequest);
    Assert.assertEquals(wrappedClient.restWireAttrs, restWireAttrs);
}
Also used : HashMap(java.util.HashMap) RestResponse(com.linkedin.r2.message.rest.RestResponse) ByteString(com.linkedin.data.ByteString) Clock(com.linkedin.util.clock.Clock) SettableClock(com.linkedin.util.clock.SettableClock) URI(java.net.URI) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) RestRequest(com.linkedin.r2.message.rest.RestRequest) PartitionData(com.linkedin.d2.balancer.properties.PartitionData) SettableClock(com.linkedin.util.clock.SettableClock) RestRequestBuilder(com.linkedin.r2.message.rest.RestRequestBuilder) RequestContext(com.linkedin.r2.message.RequestContext) Test(org.testng.annotations.Test)

Aggregations

Clock (com.linkedin.util.clock.Clock)10 URI (java.net.URI)6 PartitionData (com.linkedin.d2.balancer.properties.PartitionData)5 RequestContext (com.linkedin.r2.message.RequestContext)5 SettableClock (com.linkedin.util.clock.SettableClock)5 SystemClock (com.linkedin.util.clock.SystemClock)5 HashMap (java.util.HashMap)5 Test (org.testng.annotations.Test)5 ByteString (com.linkedin.data.ByteString)4 AtomicInteger (java.util.concurrent.atomic.AtomicInteger)4 RestRequest (com.linkedin.r2.message.rest.RestRequest)3 RestRequestBuilder (com.linkedin.r2.message.rest.RestRequestBuilder)3 Map (java.util.Map)3 ScheduledExecutorService (java.util.concurrent.ScheduledExecutorService)3 TrackerClient (com.linkedin.d2.balancer.clients.TrackerClient)2 RestResponse (com.linkedin.r2.message.rest.RestResponse)2 StreamRequest (com.linkedin.r2.message.stream.StreamRequest)2 StreamRequestBuilder (com.linkedin.r2.message.stream.StreamRequestBuilder)2 StreamResponse (com.linkedin.r2.message.stream.StreamResponse)2 DegraderImpl (com.linkedin.util.degrader.DegraderImpl)2