use of com.linkedin.d2.balancer.clients.DegraderTrackerClient in project rest.li by linkedin.
the class DegraderLoadBalancerStrategyV3 method overrideMinCallCount.
/**
* Both the drop in hash ring points and the global drop rate influence the minimum call count
* that we should see to qualify for a state update. Currently, both factors are equally weighed,
* and multiplied together to come up with a scale factor. With this scheme, if either factor is
* zero, then the overrideMinCallCount will be set to 1. If both factors are at half weight, then
* the overall weight will be .5 * .5 = .25 of the original minCallCount.
*
* @param newOverrideDropRate
* @param degraderTrackerClientUpdaters
* @param pointsMap
* @param pointsPerWeight
*/
public static void overrideMinCallCount(int partitionId, double newOverrideDropRate, List<DegraderTrackerClientUpdater> degraderTrackerClientUpdaters, Map<URI, Integer> pointsMap, int pointsPerWeight) {
for (DegraderTrackerClientUpdater clientUpdater : degraderTrackerClientUpdaters) {
if (!pointsMap.containsKey(clientUpdater.getTrackerClient().getUri())) {
continue;
}
DegraderTrackerClient client = clientUpdater.getTrackerClient();
DegraderControl degraderControl = client.getDegraderControl(partitionId);
int currentOverrideMinCallCount = client.getDegraderControl(partitionId).getOverrideMinCallCount();
double hashFactor = pointsMap.get(client.getUri()) / pointsPerWeight;
double transmitFactor = 1.0 - newOverrideDropRate;
int newOverrideMinCallCount = (int) Math.max(Math.round(degraderControl.getMinCallCount() * hashFactor * transmitFactor), 1);
if (newOverrideMinCallCount != currentOverrideMinCallCount) {
clientUpdater.setOverrideMinCallCount(newOverrideMinCallCount);
// log min call count change if current value != initial value
if (currentOverrideMinCallCount != DegraderImpl.DEFAULT_OVERRIDE_MIN_CALL_COUNT) {
warn(_log, "partitionId=", partitionId, "overriding Min Call Count to ", newOverrideMinCallCount, " for client: ", client.getUri());
}
}
}
}
use of com.linkedin.d2.balancer.clients.DegraderTrackerClient in project rest.li by linkedin.
the class DegraderLoadBalancerStrategyV3 method updatePartitionState.
private void updatePartitionState(long clusterGenerationId, Partition partition, List<DegraderTrackerClient> trackerClients, DegraderLoadBalancerStrategyConfig config) {
PartitionDegraderLoadBalancerState partitionState = partition.getState();
List<DegraderTrackerClientUpdater> clientUpdaters = new ArrayList<>();
for (DegraderTrackerClient client : trackerClients) {
clientUpdaters.add(new DegraderTrackerClientUpdater(client, partition.getId()));
}
boolean quarantineEnabled = _state.isQuarantineEnabled();
if (config.getQuarantineMaxPercent() > 0.0 && !quarantineEnabled) {
// check the hosts to see if the quarantine can be enabled.
if (_state.incrementAndGetQuarantineRetries() <= MAX_RETRIES_TO_CHECK_QUARANTINE) {
_config.getExecutorService().submit(() -> checkQuarantineState(clientUpdaters, config));
}
}
// doUpdatePartitionState has no side effects on _state or trackerClients.
// all changes to the trackerClients would be recorded in clientUpdaters
partitionState = doUpdatePartitionState(clusterGenerationId, partition.getId(), partitionState, config, clientUpdaters, quarantineEnabled);
partition.setState(partitionState);
// only if state update succeeded, do we actually apply the recorded changes to trackerClients
for (DegraderTrackerClientUpdater clientUpdater : clientUpdaters) {
clientUpdater.update();
}
}
use of com.linkedin.d2.balancer.clients.DegraderTrackerClient in project rest.li by linkedin.
the class DegraderLoadBalancerStrategyV3 method getTrackerClient.
@Override
public TrackerClient getTrackerClient(Request request, RequestContext requestContext, long clusterGenerationId, int partitionId, Map<URI, TrackerClient> trackerClients, boolean shouldForceUpdate) {
debug(_log, "getTrackerClient with generation id ", clusterGenerationId, " partition id: ", partitionId, " on tracker clients: ", trackerClients);
if (trackerClients == null || trackerClients.size() == 0) {
warn(_log, "getTrackerClient called with null/empty trackerClients, so returning null");
return null;
}
List<DegraderTrackerClient> degraderTrackerClients = castToDegraderTrackerClients(trackerClients);
// only one thread will be allowed to enter updatePartitionState for any partition
TimingContextUtil.markTiming(requestContext, TIMING_KEY);
checkUpdatePartitionState(clusterGenerationId, partitionId, degraderTrackerClients, shouldForceUpdate);
TimingContextUtil.markTiming(requestContext, TIMING_KEY);
Ring<URI> ring = _state.getRing(partitionId);
URI targetHostUri = KeyMapper.TargetHostHints.getRequestContextTargetHost(requestContext);
Set<URI> excludedUris = ExcludedHostHints.getRequestContextExcludedHosts(requestContext);
if (excludedUris == null) {
excludedUris = new HashSet<>();
}
// no valid target host header was found in the request
DegraderTrackerClient client;
if (targetHostUri == null) {
client = findValidClientFromRing(request, ring, degraderTrackerClients, excludedUris, requestContext);
} else {
debug(_log, "Degrader honoring target host header in request, skipping hashing. URI: ", targetHostUri);
client = searchClientFromUri(targetHostUri, degraderTrackerClients);
if (client == null) {
warn(_log, "No client found for ", targetHostUri, ". Target host specified is no longer part of cluster");
} else {
// if this flag is set to be true, that means affinity routing is preferred but backup requests are still acceptable
Boolean otherHostAcceptable = KeyMapper.TargetHostHints.getRequestContextOtherHostAcceptable(requestContext);
if (otherHostAcceptable != null && otherHostAcceptable) {
ExcludedHostHints.addRequestContextExcludedHost(requestContext, targetHostUri);
}
}
}
if (client == null) {
return null;
}
// Decides whether to drop the call
Degrader degrader = client.getDegrader(partitionId);
if (degrader.checkDrop()) {
warn(_log, "client's degrader is dropping call for: ", client);
return null;
}
debug(_log, "returning client: ", client);
// Decides whether to degrade call at the transport layer
if (degrader.checkPreemptiveTimeout()) {
DegraderControl degraderControl = client.getDegraderControl(partitionId);
requestContext.putLocalAttr(R2Constants.PREEMPTIVE_TIMEOUT_RATE, degraderControl.getPreemptiveRequestTimeoutRate());
}
return client;
}
use of com.linkedin.d2.balancer.clients.DegraderTrackerClient in project rest.li by linkedin.
the class DegraderTrackerClientTest method testDoNotSlowStartWhenFalse.
@Test
public void testDoNotSlowStartWhenFalse() {
Map<Integer, PartitionData> partitionDataMap = createDefaultPartitionData(1d);
DegraderImpl.Config config = new DegraderImpl.Config();
double initialDropRate = 0.99d;
config.setInitialDropRate(initialDropRate);
DegraderTrackerClient client = new DegraderTrackerClientImpl(URI.create("http://test.qa.com:1234/foo"), partitionDataMap, new TestClient(), new SettableClock(), config, DegraderLoadBalancerStrategyConfig.DEFAULT_UPDATE_INTERVAL_MS, TrackerClientImpl.DEFAULT_ERROR_STATUS_PATTERN, false);
DegraderControl degraderControl = client.getDegraderControl(DefaultPartitionAccessor.DEFAULT_PARTITION_ID);
Assert.assertEquals(degraderControl.getInitialDropRate(), initialDropRate, "Initial drop rate in config should not have been overridden by doNotSlowStart uri property.");
}
use of com.linkedin.d2.balancer.clients.DegraderTrackerClient 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);
}
Aggregations