use of com.linkedin.d2.balancer.clients.TrackerClient in project rest.li by linkedin.
the class SimpleLoadBalancerStateTest method testClientsShutdownAfterPropertyUpdatesRestRequest.
@Test(groups = { "small", "back-end" })
public void testClientsShutdownAfterPropertyUpdatesRestRequest() throws URISyntaxException, InterruptedException {
reset();
URI uri = URI.create("http://cluster-1/test");
List<String> schemes = new ArrayList<>();
Map<Integer, PartitionData> partitionData = new HashMap<>(1);
partitionData.put(DefaultPartitionAccessor.DEFAULT_PARTITION_ID, new PartitionData(1d));
Map<URI, Map<Integer, PartitionData>> uriData = new HashMap<>();
uriData.put(uri, partitionData);
schemes.add("http");
// set up state
_state.listenToService("service-1", new NullStateListenerCallback());
_state.listenToCluster("cluster-1", new NullStateListenerCallback());
_state.setDelayedExecution(0);
_serviceRegistry.put("service-1", new ServiceProperties("service-1", "cluster-1", "/test", Arrays.asList("random"), Collections.<String, Object>emptyMap(), Collections.<String, Object>emptyMap(), Collections.<String, String>emptyMap(), schemes, Collections.<URI>emptySet()));
_clusterRegistry.put("cluster-1", new ClusterProperties("cluster-1"));
_uriRegistry.put("cluster-1", new UriProperties("cluster-1", uriData));
URI uri1 = URI.create("http://partition-cluster-1/test1");
URI uri2 = URI.create("http://partition-cluster-1/test2");
_state.listenToCluster("partition-cluster-1", new NullStateListenerCallback());
_clusterRegistry.put("partition-cluster-1", new ClusterProperties("partition-cluster-1", null, new HashMap<>(), new HashSet<>(), new RangeBasedPartitionProperties("id=(\\d+)", 0, 100, 2)));
_state.listenToService("partition-service-1", new NullStateListenerCallback());
_serviceRegistry.put("partition-service-1", new ServiceProperties("partition-service-1", "partition-cluster-1", "/partition-test", Arrays.asList("degraderV3"), Collections.<String, Object>emptyMap(), Collections.<String, Object>emptyMap(), Collections.<String, String>emptyMap(), schemes, Collections.<URI>emptySet()));
Map<Integer, PartitionData> partitionWeight = new HashMap<>();
partitionWeight.put(0, new PartitionData(1d));
partitionWeight.put(1, new PartitionData(2d));
Map<URI, Map<Integer, PartitionData>> partitionDesc = new HashMap<>();
partitionDesc.put(uri1, partitionWeight);
partitionWeight.remove(0);
partitionWeight.put(2, new PartitionData(1d));
partitionDesc.put(uri2, partitionWeight);
_uriRegistry.put("partition-cluster-1", new UriProperties("partition-cluster-1", partitionDesc));
TrackerClient client1 = _state.getClient("partition-service-1", uri1);
TrackerClient client2 = _state.getClient("partition-service-1", uri2);
assertEquals(client2.getPartitionWeight(1), 2d);
assertEquals(client2.getPartitionWeight(2), 1d);
assertEquals(client1.getPartitionWeight(1), 2d);
// Get client, then refresh cluster
TrackerClient client = _state.getClient("service-1", uri);
client.restRequest(new RestRequestBuilder(URI.create("d2://service-1/foo")).build(), new RequestContext(), Collections.emptyMap(), new TransportCallbackAdapter<>(Callbacks.empty()));
// now force a refresh by adding cluster
_clusterRegistry.put("cluster-1", new ClusterProperties("cluster-1"));
// Get client, then refresh service
client = _state.getClient("service-1", uri);
client.restRequest(new RestRequestBuilder(URI.create("d2://service-1/foo")).build(), new RequestContext(), Collections.emptyMap(), new TransportCallbackAdapter<>(Callbacks.empty()));
// refresh by adding service
_serviceRegistry.put("service-1", new ServiceProperties("service-1", "cluster-1", "/test", Arrays.asList("random"), Collections.<String, Object>emptyMap(), null, null, schemes, null));
// Get client, then mark server up/down
client = _state.getClient("service-1", uri);
client.restRequest(new RestRequestBuilder(URI.create("d2://service-1/foo")).build(), new RequestContext(), Collections.emptyMap(), new TransportCallbackAdapter<>(Callbacks.empty()));
_uriRegistry.put("cluster-1", new UriProperties("cluster-1", Collections.<URI, Map<Integer, PartitionData>>emptyMap()));
_uriRegistry.put("cluster-1", new UriProperties("cluster-1", uriData));
// Get the client one last time
client = _state.getClient("service-1", uri);
client.restRequest(new RestRequestBuilder(URI.create("d2://service-1/foo")).build(), new RequestContext(), Collections.emptyMap(), new TransportCallbackAdapter<>(Callbacks.empty()));
TestShutdownCallback callback = new TestShutdownCallback();
_state.shutdown(callback);
assertTrue(callback.await(10, TimeUnit.SECONDS), "Failed to shut down state");
for (TransportClientFactory factory : _clientFactories.values()) {
SimpleLoadBalancerTest.DoNothingClientFactory f = (SimpleLoadBalancerTest.DoNothingClientFactory) factory;
assertEquals(f.getRunningClientCount(), 0, "not all clients were shut down");
}
}
use of com.linkedin.d2.balancer.clients.TrackerClient in project rest.li by linkedin.
the class SimpleLoadBalancerStateTest method testClientsShutdownAfterPropertyUpdatesStreamRequest.
@Test(groups = { "small", "back-end" })
public void testClientsShutdownAfterPropertyUpdatesStreamRequest() throws URISyntaxException, InterruptedException {
reset();
URI uri = URI.create("http://cluster-1/test");
List<String> schemes = new ArrayList<>();
Map<Integer, PartitionData> partitionData = new HashMap<>(1);
partitionData.put(DefaultPartitionAccessor.DEFAULT_PARTITION_ID, new PartitionData(1d));
Map<URI, Map<Integer, PartitionData>> uriData = new HashMap<>();
uriData.put(uri, partitionData);
schemes.add("http");
// set up state
_state.listenToService("service-1", new NullStateListenerCallback());
_state.listenToCluster("cluster-1", new NullStateListenerCallback());
_state.setDelayedExecution(0);
_serviceRegistry.put("service-1", new ServiceProperties("service-1", "cluster-1", "/test", Arrays.asList("random"), Collections.<String, Object>emptyMap(), Collections.<String, Object>emptyMap(), Collections.<String, String>emptyMap(), schemes, Collections.<URI>emptySet()));
_clusterRegistry.put("cluster-1", new ClusterProperties("cluster-1"));
_uriRegistry.put("cluster-1", new UriProperties("cluster-1", uriData));
URI uri1 = URI.create("http://partition-cluster-1/test1");
URI uri2 = URI.create("http://partition-cluster-1/test2");
_state.listenToCluster("partition-cluster-1", new NullStateListenerCallback());
_clusterRegistry.put("partition-cluster-1", new ClusterProperties("partition-cluster-1", null, new HashMap<>(), new HashSet<>(), new RangeBasedPartitionProperties("id=(\\d+)", 0, 100, 2)));
_state.listenToService("partition-service-1", new NullStateListenerCallback());
_serviceRegistry.put("partition-service-1", new ServiceProperties("partition-service-1", "partition-cluster-1", "/partition-test", Arrays.asList("degraderV3"), Collections.emptyMap(), Collections.emptyMap(), Collections.emptyMap(), schemes, Collections.emptySet()));
Map<Integer, PartitionData> partitionWeight = new HashMap<>();
partitionWeight.put(0, new PartitionData(1d));
partitionWeight.put(1, new PartitionData(2d));
Map<URI, Map<Integer, PartitionData>> partitionDesc = new HashMap<>();
partitionDesc.put(uri1, partitionWeight);
partitionWeight.remove(0);
partitionWeight.put(2, new PartitionData(1d));
partitionDesc.put(uri2, partitionWeight);
_uriRegistry.put("partition-cluster-1", new UriProperties("partition-cluster-1", partitionDesc));
TrackerClient client1 = _state.getClient("partition-service-1", uri1);
TrackerClient client2 = _state.getClient("partition-service-1", uri2);
assertEquals(client2.getPartitionWeight(1), 2d);
assertEquals(client2.getPartitionWeight(2), 1d);
assertEquals(client1.getPartitionWeight(1), 2d);
// Get client, then refresh cluster
TrackerClient client = _state.getClient("service-1", uri);
client.streamRequest(new StreamRequestBuilder(URI.create("d2://service-1/foo")).build(EntityStreams.emptyStream()), new RequestContext(), Collections.emptyMap(), new TransportCallbackAdapter<>(Callbacks.empty()));
// now force a refresh by adding cluster
_clusterRegistry.put("cluster-1", new ClusterProperties("cluster-1"));
// Get client, then refresh service
client = _state.getClient("service-1", uri);
client.streamRequest(new StreamRequestBuilder(URI.create("d2://service-1/foo")).build(EntityStreams.emptyStream()), new RequestContext(), Collections.emptyMap(), new TransportCallbackAdapter<>(Callbacks.empty()));
// refresh by adding service
_serviceRegistry.put("service-1", new ServiceProperties("service-1", "cluster-1", "/test", Arrays.asList("random"), Collections.<String, Object>emptyMap(), null, null, schemes, null));
// Get client, then mark server up/down
client = _state.getClient("service-1", uri);
client.streamRequest(new StreamRequestBuilder(URI.create("d2://service-1/foo")).build(EntityStreams.emptyStream()), new RequestContext(), Collections.emptyMap(), new TransportCallbackAdapter<>(Callbacks.empty()));
_uriRegistry.put("cluster-1", new UriProperties("cluster-1", Collections.<URI, Map<Integer, PartitionData>>emptyMap()));
_uriRegistry.put("cluster-1", new UriProperties("cluster-1", uriData));
// Get the client one last time
client = _state.getClient("service-1", uri);
client.streamRequest(new StreamRequestBuilder(URI.create("d2://service-1/foo")).build(EntityStreams.emptyStream()), new RequestContext(), Collections.emptyMap(), new TransportCallbackAdapter<>(Callbacks.empty()));
TestShutdownCallback callback = new TestShutdownCallback();
_state.shutdown(callback);
assertTrue(callback.await(10, TimeUnit.SECONDS), "Failed to shut down state");
for (TransportClientFactory factory : _clientFactories.values()) {
SimpleLoadBalancerTest.DoNothingClientFactory f = (SimpleLoadBalancerTest.DoNothingClientFactory) factory;
assertEquals(f.getRunningClientCount(), 0, "not all clients were shut down");
}
}
use of com.linkedin.d2.balancer.clients.TrackerClient in project rest.li by linkedin.
the class DegraderLoadBalancerTest method TestRandomIncreaseReduceTrackerClients.
@Test(groups = { "small", "back-end" }, dataProvider = "consistentHashAlgorithms")
public void TestRandomIncreaseReduceTrackerClients(String consistentHashAlgorithm) {
final DegraderLoadBalancerStrategyV3 strategy = getStrategy(consistentHashAlgorithm);
TestClock testClock = new TestClock();
String baseUri = "http://linkedin.com:9999";
int numberOfClients = 100;
int loopNumber = 100;
Map<String, String> degraderProperties = new HashMap<>();
degraderProperties.put(PropertyKeys.DEGRADER_HIGH_ERROR_RATE, "0.5");
degraderProperties.put(PropertyKeys.DEGRADER_LOW_ERROR_RATE, "0.2");
DegraderImpl.Config degraderConfig = DegraderConfigFactory.toDegraderConfig(degraderProperties);
Random random = new Random();
final List<DegraderTrackerClient> clients = new ArrayList<>();
random.setSeed(123456789L);
for (int i = 0; i < loopNumber; ++i) {
int currentSize = clients.size();
if (currentSize > numberOfClients) {
// need to remove some clients
clients.subList(numberOfClients, currentSize).clear();
} else {
// add more clients
for (int j = currentSize; j < numberOfClients; j++) {
URI uri = URI.create(baseUri + j);
DegraderTrackerClient client = new DegraderTrackerClientImpl(uri, getDefaultPartitionData(1, 1), new TestLoadBalancerClient(uri), testClock, degraderConfig);
clients.add(client);
}
}
TrackerClient client = strategy.getTrackerClient(null, new RequestContext(), i, DefaultPartitionAccessor.DEFAULT_PARTITION_ID, toMap(clients));
assertNotNull(client);
// update the client number
if (random.nextBoolean()) {
numberOfClients += random.nextInt(numberOfClients / 5);
} else {
numberOfClients -= random.nextInt(numberOfClients / 5);
}
}
}
use of com.linkedin.d2.balancer.clients.TrackerClient in project rest.li by linkedin.
the class DegraderLoadBalancerTest method clusterTotalRecovery1TC.
/**
* simulates the situation where a cluster latency gets so high that we will reduce the number of
* points in hashring to 0 and then increase the call drop rate to 1.0
* This will causes the cluster to receive no traffic and we want to see if the cluster can recover
* from such situation.
* @param myMap
* @param clock
* @param timeInterval
* @param strategy
*/
public void clusterTotalRecovery1TC(Map<String, Object> myMap, TestClock clock, Long timeInterval, DegraderLoadBalancerStrategyAdapter strategy) {
final int NUM_CHECKS = 5;
final Long TIME_INTERVAL = timeInterval;
DegraderLoadBalancerStrategyConfig config = DegraderLoadBalancerStrategyConfig.createHttpConfigFromMap(myMap);
List<DegraderTrackerClient> clients = new ArrayList<>();
URI uri1 = URI.create("http://test.linkedin.com:3242/fdsaf");
URIRequest request = new URIRequest(uri1);
DegraderTrackerClient client1 = new DegraderTrackerClientImpl(uri1, getDefaultPartitionData(1d), new TestLoadBalancerClient(uri1), clock, null);
clients.add(client1);
// force client1 to be disabled
DegraderControl dcClient1Default = client1.getDegraderControl(DEFAULT_PARTITION_ID);
dcClient1Default.setOverrideMinCallCount(5);
dcClient1Default.setMinCallCount(5);
dcClient1Default.setMaxDropRate(1d);
dcClient1Default.setUpStep(1.0d);
List<CallCompletion> ccList = new ArrayList<>();
CallCompletion cc;
for (int j = 0; j < NUM_CHECKS; j++) {
cc = client1.getCallTracker().startCall();
ccList.add(cc);
}
// add high latency and errors to shut off traffic to this tracker client.
clock.addMs(3500);
for (Iterator<CallCompletion> iter = ccList.listIterator(); iter.hasNext(); ) {
cc = iter.next();
cc.endCallWithError();
iter.remove();
}
// go to next time interval.
clock.addMs(TIME_INTERVAL);
Assert.assertEquals(dcClient1Default.getCurrentComputedDropRate(), 1.0);
// trigger a state update
TrackerClient resultTC = getTrackerClient(strategy, request, new RequestContext(), 1, clients);
// now we mimic the high latency and force the state to drop all calls so to make
// the overrideClusterDropRate to 1.0
ccList = new ArrayList<>();
for (int j = 0; j < NUM_CHECKS; j++) {
cc = client1.getCallTracker().startCall();
ccList.add(cc);
}
// make sure that the latency is really high
clock.addMs(3500);
for (Iterator<CallCompletion> iter = ccList.listIterator(); iter.hasNext(); ) {
cc = iter.next();
cc.endCallWithError();
iter.remove();
}
// go to next time interval.
clock.addMs(TIME_INTERVAL);
// trigger a state update
resultTC = getTrackerClient(strategy, request, new RequestContext(), 1, clients);
// this time the cluster override drop rate is set to 1.0 so resultTC should be null because we drop the client
assertNull(resultTC);
assertEquals(strategy.getCurrentOverrideDropRate(), config.getGlobalStepUp());
// add another time interval
clock.addMs(TIME_INTERVAL);
// usually we alternate between LoadBalancing and CallDropping strategy but we want to test
// call dropping strategy
strategy.setStrategyToCallDrop();
// we simulate call drop by not calling callCompletion endCall() or endCallWithEror() like we did above
// because override drop rate is set to 1.0 that means all call will be dropped so resultTc should be null
resultTC = getTrackerClient(strategy, request, new RequestContext(), 1, clients);
// this time the cluster override drop rate is set to 0.2 because we're recovering
assertEquals(strategy.getCurrentOverrideDropRate(), 1 - config.getGlobalStepDown());
// add another time interval
clock.addMs(TIME_INTERVAL);
// set the strategy to callDropping again
strategy.setStrategyToCallDrop();
// because override drop rate is set to 0.2 and we simulate as if we still don't get any call
// this cycle we will set the override drop rate to 0
resultTC = getTrackerClient(strategy, request, new RequestContext(), 1, clients);
assertEquals(strategy.getCurrentOverrideDropRate(), 0.0);
}
use of com.linkedin.d2.balancer.clients.TrackerClient in project rest.li by linkedin.
the class DegraderLoadBalancerTest method testClientGlitch.
@Test(groups = { "small", "back-end" }, dataProvider = "clientGlitch", enabled = false)
public /**
* The strategy recovers after a TrackerClient throws one Exception.
*/
void testClientGlitch(final int numberOfPartitions, final LoadBalancerStrategy strategy, final TestClock clock, final long timeInterval) throws Exception {
final List<DegraderTrackerClient> client = Collections.singletonList(new ErrorClient(1, numberOfPartitions, clock));
final int partitionId = DefaultPartitionAccessor.DEFAULT_PARTITION_ID + numberOfPartitions - 1;
final Callable<Ring<URI>> getRing = new Callable<Ring<URI>>() {
@Override
public Ring<URI> call() {
return strategy.getRing(1L, partitionId, toMap(client));
}
};
try {
// initialization
getRing.call();
fail("no glitch");
} catch (DummyCheckedException expectedGlitch) {
}
final int numberOfThreads = 5;
final ExecutorService executor = Executors.newFixedThreadPool(numberOfThreads);
try {
final List<Future<Ring<URI>>> results = new ArrayList<>();
for (int r = 0; r < numberOfThreads; ++r) results.add(executor.submit(getRing));
clock.addMs(timeInterval);
// During this time,
Thread.sleep(timeInterval * 2);
// one of the threads should initialize the partition state,
// and then all of the threads should get the new ring.
assertEquals(countDone(results), results.size());
} finally {
executor.shutdownNow();
}
}
Aggregations