use of com.linkedin.d2.balancer.strategies.degrader.DegraderLoadBalancerStrategyConfig in project rest.li by linkedin.
the class DegraderLoadBalancerTest method testStateIsNullAndCallCountIsGreaterThanZero.
@Test(groups = { "small", "back-end" })
public void testStateIsNullAndCallCountIsGreaterThanZero() throws URISyntaxException, InterruptedException {
// check for average cluster latency < max latency
// max so we don't time out from lag on testing machine
DegraderLoadBalancerStrategyV3 strategy = new DegraderLoadBalancerStrategyV3(new DegraderLoadBalancerStrategyConfig(5000), "DegraderLoadBalancerTest", null, DEGRADER_STATE_LISTENER_FACTORIES);
List<DegraderTrackerClient> clients = new ArrayList<>();
TestClock clock1 = new TestClock();
TestClock clock2 = new TestClock();
clients.add(getClient(URI.create("http://test.linkedin.com:3242/fdsaf"), clock1));
clients.add(getClient(URI.create("http://test.linkedin.com:3243/fdsaf"), clock2));
for (int i = 0; i < 1000; ++i) {
clients.get(i % 2).getCallTracker().startCall().endCall();
}
clock1.addMs(5000);
// this should trigger setting _state (state is null and count > 0) with an override
// of 0d
getTrackerClient(strategy, null, new RequestContext(), -1, clients);
for (DegraderTrackerClient client : clients) {
assertEquals(client.getDegraderControl(DEFAULT_PARTITION_ID).getOverrideDropRate(), 0d);
}
}
use of com.linkedin.d2.balancer.strategies.degrader.DegraderLoadBalancerStrategyConfig in project rest.li by linkedin.
the class DelegatingRingFactoryTest method testRandomChangePoints.
@Test(groups = { "small", "back-end" })
public void testRandomChangePoints() throws URISyntaxException {
int pointNum = 5;
int loopNum = 100;
Map<String, Integer> pointsMp = buildPointsMap(pointNum);
Map<String, Integer> maxPoints = new HashMap<>(pointNum);
Random random = new Random();
for (String uri : pointsMp.keySet()) {
maxPoints.put(uri, 100);
}
PointBasedConsistentHashRingFactory<String> ringFactory = new PointBasedConsistentHashRingFactory<>(new DegraderLoadBalancerStrategyConfig(1L));
Ring<String> ring = ringFactory.createRing(pointsMp);
assertNotNull(ring.get(1000));
for (int i = 0; i < loopNum; ++i) {
// new point list
for (String uri : pointsMp.keySet()) {
int newPoints = random.nextInt(200);
if (newPoints == 0) {
continue;
}
pointsMp.put(uri, newPoints);
if (newPoints > maxPoints.get(uri)) {
maxPoints.put(uri, ((newPoints + 3) / 4) * 4);
}
}
ring = ringFactory.createRing(pointsMp);
assertNotNull(ring.get(1000));
Map<String, List<Point<String>>> pointList = ringFactory.getPointsMap();
for (String uri : pointsMp.keySet()) {
assertEquals((int) maxPoints.get(uri), pointList.get(uri).size());
}
}
}
use of com.linkedin.d2.balancer.strategies.degrader.DegraderLoadBalancerStrategyConfig in project rest.li by linkedin.
the class DegraderLoadBalancerStrategyV3 method enrollNewClientInRecoveryMap.
/**
* /**
* Enroll new client into RecoveryMap
*
* When fastRecovery mode is enabled, we want to enroll the new client into recoveryMap to help its recovery
*/
private static void enrollNewClientInRecoveryMap(Map<DegraderTrackerClient, Double> recoveryMap, PartitionDegraderLoadBalancerState state, DegraderLoadBalancerStrategyConfig config, DegraderControl degraderControl, DegraderTrackerClientUpdater clientUpdater) {
DegraderTrackerClient client = clientUpdater.getTrackerClient();
if (// client is not in the map yet
!recoveryMap.containsKey(client) && // client is new
!state.getTrackerClients().contains(client) && // Fast recovery is enabled
config.getRingRampFactor() > FAST_RECOVERY_THRESHOLD && // Slow start is enabled
degraderControl.getInitialDropRate() > SLOW_START_THRESHOLD && // current client is not degrading or QPS is too low
!degraderControl.isHigh() && // doNotSlowStart is set to false
!client.doNotSlowStart()) {
recoveryMap.put(client, clientUpdater.getMaxDropRate());
// also set the maxDropRate to the computedDropRate if not 1;
double maxDropRate = 1.0 - config.getInitialRecoveryLevel();
clientUpdater.setMaxDropRate(Math.min(degraderControl.getCurrentComputedDropRate(), maxDropRate));
}
}
use of com.linkedin.d2.balancer.strategies.degrader.DegraderLoadBalancerStrategyConfig in project rest.li by linkedin.
the class DegraderLoadBalancerStrategyV3 method getUnhealthyTrackerClients.
private static List<DegraderTrackerClient> getUnhealthyTrackerClients(List<DegraderTrackerClientUpdater> degraderTrackerClientUpdaters, Map<URI, Integer> pointsMap, Map<DegraderTrackerClient, LoadBalancerQuarantine> quarantineMap, DegraderLoadBalancerStrategyConfig config, int partitionId) {
List<DegraderTrackerClient> unhealthyClients = new ArrayList<>();
for (DegraderTrackerClientUpdater clientUpdater : degraderTrackerClientUpdaters) {
DegraderTrackerClient client = clientUpdater.getTrackerClient();
int perfectHealth = (int) (client.getPartitionWeight(partitionId) * client.getSubsetWeight(partitionId) * config.getPointsPerWeight());
URI uri = client.getUri();
if (!pointsMap.containsKey(uri)) {
_log.warn("Client with URI {} is absent in point map, pointMap={}, quarantineMap={}", new Object[] { uri, pointsMap, quarantineMap });
continue;
}
Integer point = pointsMap.get(uri);
if (point < perfectHealth) {
unhealthyClients.add(client);
}
}
return unhealthyClients;
}
use of com.linkedin.d2.balancer.strategies.degrader.DegraderLoadBalancerStrategyConfig in project rest.li by linkedin.
the class DegraderLoadBalancerStrategyV3 method checkQuarantineState.
/**
* checkQuarantineState decides if the D2Quarantine can be enabled or not, by health
* checking all the trackerClients once. It enables quarantine only if at least one of the
* clients return success for the checking.
*
* The reasons for this checking include:
*
* . The default method "OPTIONS" is not always enabled by the service
* . The user can config any path/method for checking. We do a sanity checking to
* make sure the configuration is correct, and service/host responds in time.
* Otherwise the host can be kept in quarantine forever if we blindly enable it.
*
* This check actually can warm up the R2 connection pool by making a connection to
* each trackerClient. However since the check happens before any real requests are sent,
* it generally takes much longer time to get the results, due to different warming up
* requirements. Therefore the checking will be retried in next update if current check
* fails.
*
* This function is supposed to be protected by the update lock.
*
* @param clients
* @param config
*/
private void checkQuarantineState(List<DegraderTrackerClientUpdater> clients, DegraderLoadBalancerStrategyConfig config) {
Callback<None> healthCheckCallback = new Callback<None>() {
@Override
public void onError(Throwable e) {
// Do nothing as the quarantine is disabled by default
if (!_state.isQuarantineEnabled()) {
// No need to log the error message if quarantine is already enabled
_rateLimitedLogger.warn("Error enabling quarantine. Health checking failed for service {}: ", _state.getServiceName(), e);
}
}
@Override
public void onSuccess(None result) {
if (_state.tryEnableQuarantine()) {
_log.info("Quarantine is enabled for service {}", _state.getServiceName());
}
}
};
// Ideally we would like to healthchecking all the service hosts (ie all TrackerClients) because
// this can help to warm up the R2 connections to the service hosts, thus speed up the initial access
// speed when d2client starts to access those hosts. However this can expose/expedite the problem that
// the d2client host needs too many connections or file handles to all the hosts, when the downstream
// services have large amount of hosts. Before that problem is addressed, we limit the number of hosts
// for pre-healthchecking to a small number
clients.stream().limit(MAX_HOSTS_TO_CHECK_QUARANTINE).forEach(client -> {
try {
HealthCheck healthCheckClient = _state.getHealthCheckMap().get(client);
if (healthCheckClient == null) {
// create a new client if not exits
healthCheckClient = new HealthCheckClientBuilder().setHealthCheckOperations(config.getHealthCheckOperations()).setHealthCheckPath(config.getHealthCheckPath()).setServicePath(config.getServicePath()).setClock(config.getClock()).setLatency(config.getQuarantineLatency()).setMethod(config.getHealthCheckMethod()).setClient(client.getTrackerClient()).build();
_state.putHealthCheckClient(client, healthCheckClient);
}
healthCheckClient.checkHealth(healthCheckCallback);
} catch (URISyntaxException e) {
_log.error("Error to build healthCheckClient ", e);
}
});
// also remove the entries that the corresponding trackerClientUpdaters do not exist anymore
for (DegraderTrackerClientUpdater client : _state.getHealthCheckMap().keySet()) {
if (!clients.contains(client)) {
_state.getHealthCheckMap().remove(client);
}
}
}
Aggregations