use of com.linkedin.d2.balancer.clients.DegraderTrackerClient in project rest.li by linkedin.
the class DegraderLoadBalancerTest method runMultiThreadedTest.
private void runMultiThreadedTest(final DegraderLoadBalancerStrategyAdapter strategyAdapter, final List<DegraderTrackerClient> clients, final int numberOfThread, final boolean trackerClientMustNotBeNull) {
final CountDownLatch exitLatch = new CountDownLatch(numberOfThread);
final CountDownLatch startLatch = new CountDownLatch(numberOfThread);
ExecutorService executorService = Executors.newFixedThreadPool(numberOfThread);
List<Future<Boolean>> futures = new ArrayList<>();
for (int i = 0; i < numberOfThread; i++) {
// testNG won't be able to "know" if a child thread's assertion is false, so to get around it we
// need to throw an exception so executorService can notify the main thread about the false assertion
// even though executorService has an invokeAll method, it doesn't seem run the threads at the same time
// so we have to use a latch to make sure all the threads run at the same time to simulate concurrent access
Future<Boolean> future = executorService.submit(new Runnable() {
@Override
public void run() {
startLatch.countDown();
try {
// wait until all threads are ready to run together
startLatch.await();
} catch (InterruptedException e) {
throw new RuntimeException("Failed the test because thread was interrupted");
}
// if config is broken, every thread would fail and state update would be unsuccessful
try {
TrackerClient resultTC = getTrackerClient(strategyAdapter, null, new RequestContext(), 1, clients);
if (trackerClientMustNotBeNull && resultTC == null) {
throw new RuntimeException("Failed the test because resultTC returns null");
}
} catch (DummyException ex) {
// expected
}
exitLatch.countDown();
try {
// make sure all threads are not stuck on WAIT_THREAD
if (!exitLatch.await(5, TimeUnit.SECONDS)) {
throw new RuntimeException("Failed the test because we waited longer than 1 second");
}
} catch (InterruptedException e) {
throw new RuntimeException("Failed the test because thread was interrupted");
}
}
}, Boolean.TRUE);
futures.add(future);
}
for (Future<Boolean> future : futures) {
try {
assertTrue(future.get());
} catch (Exception e) {
fail("something is failing", e);
}
}
executorService.shutdownNow();
}
use of com.linkedin.d2.balancer.clients.DegraderTrackerClient in project rest.li by linkedin.
the class DegraderLoadBalancerTest method stressTest.
@Test(groups = { "small", "back-end" })
public void stressTest() {
final DegraderLoadBalancerStrategyV3 strategyV3 = getStrategy();
TestClock testClock = new TestClock();
String baseUri = "http://linkedin.com:9999";
int numberOfPartitions = 10;
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);
final List<DegraderTrackerClient> clients = new ArrayList<>();
for (int i = 0; i < numberOfPartitions; i++) {
URI uri = URI.create(baseUri + i);
DegraderTrackerClient client = new DegraderTrackerClientImpl(uri, getDefaultPartitionData(1, numberOfPartitions), new TestLoadBalancerClient(uri), testClock, degraderConfig);
clients.add(client);
}
final ExecutorService executor = Executors.newFixedThreadPool(100);
final CountDownLatch startLatch = new CountDownLatch(1);
final CountDownLatch finishLatch = new CountDownLatch(100);
try {
for (int i = 0; i < numberOfPartitions; i++) {
Assert.assertFalse(strategyV3.getState().getPartitionState(i).isInitialized());
}
for (int i = 0; i < 100; i++) {
final int partitionId = i % numberOfPartitions;
executor.submit(new Runnable() {
@Override
public void run() {
try {
startLatch.await();
} catch (InterruptedException ex) {
}
strategyV3.getRing(1, partitionId, toMap(clients));
finishLatch.countDown();
}
});
}
// all threads would try to getRing simultanously
startLatch.countDown();
if (!finishLatch.await(10, TimeUnit.SECONDS)) {
fail("Stress test failed to finish within 10 seconds");
}
for (int i = 0; i < numberOfPartitions; i++) {
Assert.assertTrue(strategyV3.getState().getPartitionState(i).isInitialized());
}
} catch (InterruptedException ex) {
} finally {
executor.shutdownNow();
}
}
use of com.linkedin.d2.balancer.clients.DegraderTrackerClient in project rest.li by linkedin.
the class DegraderLoadBalancerTest method testWeightedAndLatencyDegradationBalancingRing.
@Test(groups = { "small", "back-end" }, dataProvider = "consistentHashAlgorithms")
public void testWeightedAndLatencyDegradationBalancingRing(String consistentHashAlgorithm) throws URISyntaxException {
DegraderLoadBalancerStrategyV3 strategy = getStrategy(consistentHashAlgorithm);
List<DegraderTrackerClient> clients = new ArrayList<>();
URI uri1 = URI.create("http://test.linkedin.com:3242/fdsaf");
URI uri2 = URI.create("http://test.linkedin.com:3243/fdsaf");
TestClock clock1 = new TestClock();
TestClock clock2 = new TestClock();
DegraderTrackerClient client1 = new DegraderTrackerClientImpl(uri1, getDefaultPartitionData(1d), new TestLoadBalancerClient(uri1), clock1, null);
DegraderTrackerClient client2 = new DegraderTrackerClientImpl(uri2, getDefaultPartitionData(0.8d), new TestLoadBalancerClient(uri2), clock2, null);
clients.add(client1);
clients.add(client2);
DegraderControl dcClient2Default = client2.getDegraderControl(DEFAULT_PARTITION_ID);
dcClient2Default.setOverrideMinCallCount(1);
dcClient2Default.setMinCallCount(1);
dcClient2Default.setMaxDropRate(1d);
dcClient2Default.setUpStep(0.4d);
dcClient2Default.setHighErrorRate(0);
CallCompletion cc = client2.getCallTracker().startCall();
clock2.addMs(1);
cc.endCallWithError();
clock1.addMs(15000);
clock2.addMs(5000);
// trigger a state update
assertNotNull(getTrackerClient(strategy, null, new RequestContext(), 1, clients));
// now do a basic verification to verify getTrackerClient is properly weighting things
double calls = 10000d;
int client1Count = 0;
int client2Count = 0;
double tolerance = 0.05d;
for (int i = 0; i < calls; ++i) {
TrackerClient client = getTrackerClient(strategy, null, new RequestContext(), 1, clients);
assertNotNull(client);
if (client.getUri().equals(uri1)) {
++client1Count;
} else {
++client2Count;
}
}
assertTrue(Math.abs((client1Count / calls) - (100 / 148d)) < tolerance);
assertTrue(Math.abs((client2Count / calls) - (48 / 148d)) < tolerance);
}
use of com.linkedin.d2.balancer.clients.DegraderTrackerClient in project rest.li by linkedin.
the class DegraderLoadBalancerTest method testRandom.
@Test(groups = { "small", "back-end" })
public void testRandom() throws URISyntaxException {
DegraderLoadBalancerStrategyV3 strategy = getStrategy();
List<DegraderTrackerClient> clients = new ArrayList<>();
URI uri1 = URI.create("http://test.linkedin.com:3242/fdsaf");
URI uri2 = URI.create("http://test.linkedin.com:3243/fdsaf");
clients.add(getClient(uri1, new TestClock()));
clients.add(getClient(uri2, new TestClock()));
// since cluster call count is 0, we will default to random
for (int i = 0; i < 1000; ++i) {
TrackerClient client = getTrackerClient(strategy, null, new RequestContext(), 0, clients);
assertNotNull(client);
assertTrue(clients.contains(client));
}
}
use of com.linkedin.d2.balancer.clients.DegraderTrackerClient in project rest.li by linkedin.
the class DegraderLoadBalancerTest method testInconsistentHashAndTrackerclients.
@Test(groups = { "small", "back-end" }, dataProvider = "consistentHashAlgorithms")
public void testInconsistentHashAndTrackerclients(String consistentHashAlgorithm) throws URISyntaxException, InterruptedException {
// check if the inconsistent Hash ring and trackerlients can be handled
TestClock clock = new TestClock();
Map<String, Object> myMap = lbDefaultConfig();
myMap.put(PropertyKeys.CLOCK, clock);
myMap.put(PropertyKeys.HTTP_LB_CONSISTENT_HASH_ALGORITHM, consistentHashAlgorithm);
DegraderLoadBalancerStrategyConfig config = DegraderLoadBalancerStrategyConfig.createHttpConfigFromMap(myMap);
DegraderLoadBalancerStrategyV3 strategy = new DegraderLoadBalancerStrategyV3(config, "DegraderLoadBalancerTest", null, DEGRADER_STATE_LISTENER_FACTORIES);
List<DegraderTrackerClient> clients = new ArrayList<>();
clients.add(getClient(URI.create("http://test.linkedin.com:3242/fdsaf"), clock));
clients.add(getClient(URI.create("http://test.linkedin.com:3243/fdsaf"), clock));
TrackerClient chosen = getTrackerClient(strategy, null, new RequestContext(), 0, clients);
assertNotNull(chosen);
// remove the client from the list, now the ring and the trackerClient list are inconsistent
clients.remove(chosen);
assertNotNull(getTrackerClient(strategy, null, new RequestContext(), 0, clients));
// update the hash ring we should get the results as well
assertNotNull(getTrackerClient(strategy, null, new RequestContext(), 1, clients));
}
Aggregations