Search in sources :

Example 11 with ClockedExecutor

use of com.linkedin.test.util.ClockedExecutor in project rest.li by linkedin.

the class TestRampUpRateLimiter method testRampDownImmediately.

@Test(timeOut = TEST_TIMEOUT)
public void testRampDownImmediately() {
    ClockedExecutor clockedExecutor = new ClockedExecutor();
    RampUpRateLimiter rateLimiter = new RampUpRateLimiterImpl(new SmoothRateLimiter(clockedExecutor, clockedExecutor, clockedExecutor, _queue, Integer.MAX_VALUE, SmoothRateLimiter.BufferOverflowMode.DROP, RATE_LIMITER_NAME_TEST), clockedExecutor);
    rateLimiter.setRate(1000d, ONE_SECOND_PERIOD, MINIMUM_BURST);
    List<FutureCallback<None>> callbacks = new ArrayList<>();
    IntStream.range(0, 1002).forEach(i -> {
        FutureCallback<None> callback = new FutureCallback<>();
        rateLimiter.submit(callback);
        callbacks.add(callback);
    });
    // -1 because if it passes a full second, the new batch of permits will be issued
    clockedExecutor.runFor(ONE_SECOND_PERIOD - 1);
    IntStream.range(0, 1000).forEach(i -> assertTrue(callbacks.get(i).isDone()));
    IntStream.range(1000, 1002).forEach(i -> assertFalse(callbacks.get(i).isDone(), i + " should not have been executed"));
    rateLimiter.setRate(1, ONE_SECOND_PERIOD, 1, Integer.MAX_VALUE);
    clockedExecutor.runFor(ONE_SECOND_PERIOD);
    IntStream.range(1000, 1001).forEach(i -> assertTrue(callbacks.get(i).isDone()));
    IntStream.range(1001, 1002).forEach(i -> assertFalse(callbacks.get(i).isDone(), i + " should not have been executed"));
    clockedExecutor.runFor(ONE_SECOND_PERIOD);
    IntStream.range(1001, 1002).forEach(i -> assertTrue(callbacks.get(i).isDone()));
}
Also used : SmoothRateLimiter(com.linkedin.r2.transport.http.client.SmoothRateLimiter) ArrayList(java.util.ArrayList) ClockedExecutor(com.linkedin.test.util.ClockedExecutor) None(com.linkedin.common.util.None) FutureCallback(com.linkedin.common.callback.FutureCallback) Test(org.testng.annotations.Test)

Example 12 with ClockedExecutor

use of com.linkedin.test.util.ClockedExecutor in project rest.li by linkedin.

the class TestConstantQpsRateLimiter method ensureRandomButConstantRate.

@Test
public void ensureRandomButConstantRate() {
    ClockedExecutor executor = new ClockedExecutor();
    ClockedExecutor circularBufferExecutor = new ClockedExecutor();
    ConstantQpsRateLimiter rateLimiter = new ConstantQpsRateLimiter(executor, executor, executor, TestEvictingCircularBuffer.getBuffer(circularBufferExecutor));
    rateLimiter.setRate(200d, ONE_SECOND, 1);
    rateLimiter.setBufferCapacity(1);
    TattlingCallback<None> tattler = new TattlingCallback<>(executor);
    rateLimiter.submit(tattler);
    executor.runFor(ONE_SECOND * TEST_NUM_CYCLES);
    long prevTime = 0;
    List<Long> timeDeltas = new ArrayList<>();
    for (Long stamp : tattler.getOccurrences()) {
        timeDeltas.add(stamp - prevTime);
        prevTime = stamp;
    }
    // Ensure variance up to 10 possible time deltas given a rate of 200 requests per second
    Set<Long> uniqueTimeDeltas = new HashSet<>(timeDeltas);
    assert (uniqueTimeDeltas.size() > 8 && uniqueTimeDeltas.size() < 11);
}
Also used : ConstantQpsRateLimiter(com.linkedin.r2.transport.http.client.ConstantQpsRateLimiter) ArrayList(java.util.ArrayList) ClockedExecutor(com.linkedin.test.util.ClockedExecutor) None(com.linkedin.common.util.None) HashSet(java.util.HashSet) Test(org.testng.annotations.Test)

Example 13 with ClockedExecutor

use of com.linkedin.test.util.ClockedExecutor in project rest.li by linkedin.

the class TestConstantQpsRateLimiter method lowNonWholeRate.

@Test(timeOut = TEST_TIMEOUT)
public void lowNonWholeRate() {
    for (int i = 0; i < TEST_NUM_CYCLES; i++) {
        ClockedExecutor executor = new ClockedExecutor();
        ClockedExecutor circularBufferExecutor = new ClockedExecutor();
        ConstantQpsRateLimiter rateLimiter = new ConstantQpsRateLimiter(executor, executor, executor, TestEvictingCircularBuffer.getBuffer(circularBufferExecutor));
        rateLimiter.setRate(TEST_LOW_FRACTIONAL_QPS, ONE_SECOND, UNLIMITED_BURST);
        rateLimiter.setBufferCapacity(1);
        TattlingCallback<None> tattler = new TattlingCallback<>(executor);
        rateLimiter.submit(tattler);
        // run for enough time such that 3 queries are sent
        executor.runFor((int) (((ONE_SECOND / TEST_LOW_FRACTIONAL_QPS) * 3) - 1));
        Assert.assertTrue(tattler.getInteractCount() == 3);
    }
}
Also used : ConstantQpsRateLimiter(com.linkedin.r2.transport.http.client.ConstantQpsRateLimiter) ClockedExecutor(com.linkedin.test.util.ClockedExecutor) None(com.linkedin.common.util.None) Test(org.testng.annotations.Test)

Example 14 with ClockedExecutor

use of com.linkedin.test.util.ClockedExecutor in project rest.li by linkedin.

the class SimpleLoadBalancerStateTest method reset.

public void reset(boolean useSSL, boolean enableRelativeLoadBalancer) {
    _executorService = new SynchronousExecutorService();
    _uriRegistry = new MockStore<>();
    _clusterRegistry = new MockStore<>();
    _serviceRegistry = new MockStore<>();
    _clientFactories = new HashMap<>();
    _loadBalancerStrategyFactories = new HashMap<>();
    if (enableRelativeLoadBalancer) {
        _loadBalancerStrategyFactories.put(RelativeLoadBalancerStrategy.RELATIVE_LOAD_BALANCER_STRATEGY_NAME, new RelativeLoadBalancerStrategyFactory(new ClockedExecutor(), null, Collections.emptyList(), new NoopEventEmitter(), SystemClock.instance()));
    }
    _loadBalancerStrategyFactories.put("random", new RandomLoadBalancerStrategyFactory());
    _loadBalancerStrategyFactories.put("degraderV3", new DegraderLoadBalancerStrategyFactoryV3());
    _loadBalancerStrategyFactories.put(DegraderLoadBalancerStrategyV3.DEGRADER_STRATEGY_NAME, new DegraderLoadBalancerStrategyFactoryV3());
    try {
        _sslContext = SSLContext.getDefault();
    } catch (NoSuchAlgorithmException e) {
        throw new RuntimeException(e);
    }
    _sslParameters = new SSLParameters();
    if (useSSL) {
        _clientFactories.put("https", new SimpleLoadBalancerTest.DoNothingClientFactory());
        _state = new SimpleLoadBalancerState(_executorService, new PropertyEventBusImpl<>(_executorService, _uriRegistry), new PropertyEventBusImpl<>(_executorService, _clusterRegistry), new PropertyEventBusImpl<>(_executorService, _serviceRegistry), _clientFactories, _loadBalancerStrategyFactories, _sslContext, _sslParameters, true, null, SSL_SESSION_VALIDATOR_FACTORY);
    } else {
        _clientFactories.put("http", new SimpleLoadBalancerTest.DoNothingClientFactory());
        _state = new SimpleLoadBalancerState(_executorService, _uriRegistry, _clusterRegistry, _serviceRegistry, _clientFactories, _loadBalancerStrategyFactories);
    }
    FutureCallback<None> callback = new FutureCallback<>();
    _state.start(callback);
    try {
        callback.get();
    } catch (Exception e) {
        Assert.fail("State start failed", e);
    }
}
Also used : SynchronousExecutorService(com.linkedin.d2.discovery.event.SynchronousExecutorService) NoopEventEmitter(com.linkedin.d2.balancer.event.NoopEventEmitter) DegraderLoadBalancerStrategyFactoryV3(com.linkedin.d2.balancer.strategies.degrader.DegraderLoadBalancerStrategyFactoryV3) RandomLoadBalancerStrategyFactory(com.linkedin.d2.balancer.strategies.random.RandomLoadBalancerStrategyFactory) NoSuchAlgorithmException(java.security.NoSuchAlgorithmException) ClockedExecutor(com.linkedin.test.util.ClockedExecutor) URISyntaxException(java.net.URISyntaxException) NoSuchAlgorithmException(java.security.NoSuchAlgorithmException) SslSessionNotTrustedException(com.linkedin.r2.transport.http.client.common.ssl.SslSessionNotTrustedException) ExecutionException(java.util.concurrent.ExecutionException) SSLParameters(javax.net.ssl.SSLParameters) RelativeLoadBalancerStrategyFactory(com.linkedin.d2.balancer.strategies.relative.RelativeLoadBalancerStrategyFactory) PropertyEventBusImpl(com.linkedin.d2.discovery.event.PropertyEventBusImpl) None(com.linkedin.common.util.None) FutureCallback(com.linkedin.common.callback.FutureCallback)

Example 15 with ClockedExecutor

use of com.linkedin.test.util.ClockedExecutor in project rest.li by linkedin.

the class TestConstantQpsDarkClusterStrategy method testStrategy.

@Test(dataProvider = "qpsKeys")
public void testStrategy(int duration, float inboundQps, float outboundQps, int numSourceInstances, int numDarkInstances) {
    IntStream.of(1, 1000, 1000000).forEach(capacity -> {
        DarkClusterDispatcher darkClusterDispatcher = new DefaultDarkClusterDispatcher(new MockClient(false));
        ClockedExecutor executor = new ClockedExecutor();
        Supplier<ConstantQpsRateLimiter> uniqueRateLimiterSupplier = () -> {
            EvictingCircularBuffer uniqueBuffer = TestConstantQpsDarkClusterStrategy.getBuffer(executor);
            ConstantQpsRateLimiter limiter = new ConstantQpsRateLimiter(executor, executor, executor, uniqueBuffer);
            limiter.setBufferCapacity(capacity);
            limiter.setBufferTtl(Integer.MAX_VALUE, ChronoUnit.DAYS);
            return limiter;
        };
        ConstantQpsRateLimiter sharedRateLimiter = uniqueRateLimiterSupplier.get();
        Supplier<ConstantQpsRateLimiter> sharedRateLimiterSupplier = () -> sharedRateLimiter;
        MockClusterInfoProvider mockClusterInfoProvider = new MockClusterInfoProvider();
        mockClusterInfoProvider.putHttpsClusterCount(SOURCE_CLUSTER_NAME, numSourceInstances);
        // dark cluster 1
        BaseDarkClusterDispatcherImpl baseDispatcherOne = new BaseDarkClusterDispatcherImpl(DARK_CLUSTER_NAME_ONE, darkClusterDispatcher, new DoNothingNotifier(), new CountingVerifierManager());
        mockClusterInfoProvider.putHttpsClusterCount(DARK_CLUSTER_NAME_ONE, numDarkInstances);
        ConstantQpsRateLimiter rateLimiterOne = sharedRateLimiterSupplier.get();
        // dark cluster 2
        BaseDarkClusterDispatcherImpl baseDispatcherTwo = new BaseDarkClusterDispatcherImpl(DARK_CLUSTER_NAME_TWO, darkClusterDispatcher, new DoNothingNotifier(), new CountingVerifierManager());
        mockClusterInfoProvider.putHttpsClusterCount(DARK_CLUSTER_NAME_TWO, numDarkInstances);
        ConstantQpsRateLimiter rateLimiterTwo = sharedRateLimiterSupplier.get();
        // dark cluster 3
        BaseDarkClusterDispatcherImpl baseDispatcherThree = new BaseDarkClusterDispatcherImpl(DARK_CLUSTER_NAME_THREE, darkClusterDispatcher, new DoNothingNotifier(), new CountingVerifierManager());
        mockClusterInfoProvider.putHttpsClusterCount(DARK_CLUSTER_NAME_THREE, numDarkInstances);
        ConstantQpsRateLimiter rateLimiterThree = uniqueRateLimiterSupplier.get();
        List<ConstantQpsDarkClusterStrategy> strategies = new ArrayList<>();
        strategies.add(new ConstantQpsDarkClusterStrategy(SOURCE_CLUSTER_NAME, DARK_CLUSTER_NAME_ONE, outboundQps, baseDispatcherOne, new DoNothingNotifier(), mockClusterInfoProvider, rateLimiterOne));
        strategies.add(new ConstantQpsDarkClusterStrategy(SOURCE_CLUSTER_NAME, DARK_CLUSTER_NAME_TWO, outboundQps, baseDispatcherTwo, new DoNothingNotifier(), mockClusterInfoProvider, rateLimiterTwo));
        strategies.add(new ConstantQpsDarkClusterStrategy(SOURCE_CLUSTER_NAME, DARK_CLUSTER_NAME_THREE, outboundQps, baseDispatcherThree, new DoNothingNotifier(), mockClusterInfoProvider, rateLimiterThree));
        // simulate receiving the configured qps while dispatching over the duration
        int msBetweenEachInboundRequest = (int) (1000 / inboundQps);
        for (int runTime = 0; runTime < duration; runTime = runTime + msBetweenEachInboundRequest) {
            RestRequest dummyRestRequest = new RestRequestBuilder(URI.create("foo")).build();
            for (ConstantQpsDarkClusterStrategy strategy : strategies) {
                strategy.handleRequest(dummyRestRequest, dummyRestRequest, new RequestContext());
            }
            executor.runFor(msBetweenEachInboundRequest);
        }
        double validation = ((duration == 0 ? 0 : duration / 1000.0) * outboundQps * numDarkInstances) / (double) (numSourceInstances);
        // Cluster One and Two share a rate limiter, so their combined QPS should match the expected value.
        int actualCountClusterOne = baseDispatcherOne.getRequestCount();
        int actualCountClusterTwo = baseDispatcherTwo.getRequestCount();
        int expectedCountClusterOneAndTwo = (int) validation;
        Assert.assertEquals(actualCountClusterOne + actualCountClusterTwo, expectedCountClusterOneAndTwo, expectedCountClusterOneAndTwo * ERR_PCT, "count not within expected range");
        // Cluster Three uses its own so it matches the expected value on its own.
        int expectedCountClusterThree = (int) validation;
        int actualCountClusterThree = baseDispatcherThree.getRequestCount();
        Assert.assertEquals(actualCountClusterThree, expectedCountClusterThree, expectedCountClusterThree * ERR_PCT, "count not within expected range");
    });
}
Also used : DefaultDarkClusterDispatcher(com.linkedin.darkcluster.impl.DefaultDarkClusterDispatcher) DarkClusterDispatcher(com.linkedin.darkcluster.api.DarkClusterDispatcher) DefaultDarkClusterDispatcher(com.linkedin.darkcluster.impl.DefaultDarkClusterDispatcher) ArrayList(java.util.ArrayList) ClockedExecutor(com.linkedin.test.util.ClockedExecutor) ConstantQpsRateLimiter(com.linkedin.r2.transport.http.client.ConstantQpsRateLimiter) EvictingCircularBuffer(com.linkedin.r2.transport.http.client.EvictingCircularBuffer) RestRequest(com.linkedin.r2.message.rest.RestRequest) RestRequestBuilder(com.linkedin.r2.message.rest.RestRequestBuilder) RequestContext(com.linkedin.r2.message.RequestContext) ConstantQpsDarkClusterStrategy(com.linkedin.darkcluster.impl.ConstantQpsDarkClusterStrategy) BaseDarkClusterDispatcherImpl(com.linkedin.darkcluster.impl.BaseDarkClusterDispatcherImpl) Test(org.testng.annotations.Test)

Aggregations

ClockedExecutor (com.linkedin.test.util.ClockedExecutor)16 Test (org.testng.annotations.Test)14 None (com.linkedin.common.util.None)12 ArrayList (java.util.ArrayList)9 ConstantQpsRateLimiter (com.linkedin.r2.transport.http.client.ConstantQpsRateLimiter)7 FutureCallback (com.linkedin.common.callback.FutureCallback)6 AsyncRateLimiter (com.linkedin.r2.transport.http.client.AsyncRateLimiter)3 ExecutionException (java.util.concurrent.ExecutionException)3 LongTracking (com.linkedin.common.stats.LongTracking)2 DarkClusterDispatcher (com.linkedin.darkcluster.api.DarkClusterDispatcher)2 DefaultDarkClusterDispatcher (com.linkedin.darkcluster.impl.DefaultDarkClusterDispatcher)2 RestRequest (com.linkedin.r2.message.rest.RestRequest)2 RestRequestBuilder (com.linkedin.r2.message.rest.RestRequestBuilder)2 AsyncPoolImpl (com.linkedin.r2.transport.http.client.AsyncPoolImpl)2 ExponentialBackOffRateLimiter (com.linkedin.r2.transport.http.client.ExponentialBackOffRateLimiter)2 ObjectCreationTimeoutException (com.linkedin.r2.transport.http.client.ObjectCreationTimeoutException)2 PoolStats (com.linkedin.r2.transport.http.client.PoolStats)2 SmoothRateLimiter (com.linkedin.r2.transport.http.client.SmoothRateLimiter)2 TimeoutException (java.util.concurrent.TimeoutException)2 DarkClusterConfig (com.linkedin.d2.DarkClusterConfig)1