use of com.linkedin.d2.balancer.util.hashing.Ring in project rest.li by linkedin.
the class RelativeLoadBalancerStrategyFactory method putDefaultValues.
static D2RelativeStrategyProperties putDefaultValues(D2RelativeStrategyProperties properties) {
properties.setUpStep(getOrDefault(properties.getUpStep(), DEFAULT_UP_STEP));
properties.setDownStep(getOrDefault(properties.getDownStep(), DEFAULT_DOWN_STEP));
properties.setHighErrorRate(getOrDefault(properties.getHighErrorRate(), DEFAULT_HIGH_ERROR_RATE));
properties.setLowErrorRate(getOrDefault(properties.getLowErrorRate(), DEFAULT_LOW_ERROR_RATE));
properties.setRelativeLatencyHighThresholdFactor(getOrDefault(properties.getRelativeLatencyHighThresholdFactor(), DEFAULT_RELATIVE_LATENCY_HIGH_THRESHOLD_FACTOR));
properties.setRelativeLatencyLowThresholdFactor(getOrDefault(properties.getRelativeLatencyLowThresholdFactor(), DEFAULT_RELATIVE_LATENCY_LOW_THRESHOLD_FACTOR));
properties.setMinCallCount(getOrDefault(properties.getMinCallCount(), DEFAULT_MIN_CALL_COUNT));
properties.setUpdateIntervalMs(getOrDefault(properties.getUpdateIntervalMs(), DEFAULT_UPDATE_INTERVAL_MS));
properties.setInitialHealthScore(getOrDefault(properties.getInitialHealthScore(), DEFAULT_INITIAL_HEALTH_SCORE));
properties.setSlowStartThreshold(getOrDefault(properties.getSlowStartThreshold(), DEFAULT_SLOW_START_THRESHOLD));
properties.setErrorStatusFilter(getOrDefault(properties.getErrorStatusFilter(), DEFAULT_ERROR_STATUS_FILTER));
properties.setEmittingIntervalMs(getOrDefault(properties.getEmittingIntervalMs(), DEFAULT_EMITTING_INTERVAL_MS));
properties.setEnableFastRecovery(getOrDefault(properties.isEnableFastRecovery(), DEFAULT_ENABLE_FAST_RECOVERY));
D2QuarantineProperties quarantineProperties = properties.hasQuarantineProperties() ? properties.getQuarantineProperties() : new D2QuarantineProperties();
quarantineProperties.setQuarantineMaxPercent(getOrDefault(quarantineProperties.getQuarantineMaxPercent(), DEFAULT_QUARANTINE_MAX_PERCENT));
quarantineProperties.setHealthCheckMethod(getOrDefault(quarantineProperties.getHealthCheckMethod(), DEFAULT_HTTP_METHOD));
properties.setQuarantineProperties(quarantineProperties);
// Most ring properties are initialized in {@link DelegatingRingFactory}
D2RingProperties ringProperties = properties.hasRingProperties() ? properties.getRingProperties() : new D2RingProperties();
ringProperties.setPointsPerWeight(getOrDefault(ringProperties.getPointsPerWeight(), DEFAULT_POINTS_PER_WEIGHT));
properties.setRingProperties(ringProperties);
return properties;
}
use of com.linkedin.d2.balancer.util.hashing.Ring in project rest.li by linkedin.
the class DeterministicSubsettingStrategy method getWeightedSubset.
@Override
public Map<T, Double> getWeightedSubset(Map<T, Double> weightMap, DeterministicSubsettingMetadata metadata) {
if (metadata != null) {
List<T> points = new ArrayList<>(weightMap.keySet());
Collections.sort(points);
Collections.shuffle(points, new Random(_randomSeed));
List<Double> weights = points.stream().map(weightMap::get).collect(Collectors.toList());
double totalWeight = weights.stream().mapToDouble(Double::doubleValue).sum();
if (totalWeight == 0) {
return null;
}
Ring ring = new Ring(weights, totalWeight);
double offset = metadata.getInstanceId() / (double) metadata.getTotalInstanceCount();
double subsetSliceWidth = getSubsetSliceWidth(metadata.getTotalInstanceCount(), points.size());
List<Integer> indices = ring.getIndices(offset, subsetSliceWidth);
return indices.stream().collect(Collectors.toMap(points::get, i -> round(ring.getWeight(i, offset, subsetSliceWidth), WEIGHT_DECIMAL_PLACE)));
} else {
_log.warn("Cannot retrieve metadata required for D2 subsetting. Revert to use all available hosts.");
return null;
}
}
use of com.linkedin.d2.balancer.util.hashing.Ring in project rest.li by linkedin.
the class ConsistentHashKeyMapper method mapKeysV2.
@Override
public <K> MapKeyResult<URI, K> mapKeysV2(URI serviceUri, Iterable<K> keys) throws ServiceUnavailableException {
// distribute keys to rings for partitions
// Note that we assume the keys are partitioning keys
MapKeyResult<Ring<URI>, K> keyToPartitionResult = _ringProvider.getRings(serviceUri, keys);
Map<Ring<URI>, Collection<K>> ringToKeys = keyToPartitionResult.getMapResult();
Map<URI, Collection<K>> result = new HashMap<>();
Collection<MapKeyResult.UnmappedKey<K>> unmappedKeys = new ArrayList<>();
// first collect unmappedkeys in ditributing keys to partitions
unmappedKeys.addAll(keyToPartitionResult.getUnmappedKeys());
// for each partition, distribute keys to different server uris
for (Map.Entry<Ring<URI>, Collection<K>> entry : ringToKeys.entrySet()) {
MapKeyResult<URI, K> keyToHostResult = doMapKeys(entry.getKey(), entry.getValue());
// collect map key to host result
Map<URI, Collection<K>> hostToKeys = keyToHostResult.getMapResult();
for (Map.Entry<URI, Collection<K>> hostEntry : hostToKeys.entrySet()) {
URI uri = hostEntry.getKey();
Collection<K> collection = result.get(uri);
if (collection == null) {
collection = new ArrayList<>();
result.put(uri, collection);
}
collection.addAll(hostEntry.getValue());
}
// collect unmapped keys
unmappedKeys.addAll(keyToHostResult.getUnmappedKeys());
}
return new MapKeyResult<>(result, unmappedKeys);
}
use of com.linkedin.d2.balancer.util.hashing.Ring in project rest.li by linkedin.
the class DegraderLoadBalancerTest method testAdjustedMinCallCount.
@Test(groups = { "small", "back-end" })
public void testAdjustedMinCallCount() {
final int NUM_CHECKS = 5;
final Long TIME_INTERVAL = 5000L;
Map<String, Object> myMap = lbDefaultConfig();
// myMap.put(PropertyKeys.LB_INITIAL_RECOVERY_LEVEL, 0.01);
// myMap.put("rampFactor", 2d);
myMap.put(PropertyKeys.HTTP_LB_STRATEGY_PROPERTIES_UPDATE_INTERVAL_MS, TIME_INTERVAL);
TestClock clock = new TestClock();
myMap.put(PropertyKeys.CLOCK, clock);
DegraderLoadBalancerStrategyConfig config = DegraderLoadBalancerStrategyConfig.createHttpConfigFromMap(myMap);
DegraderLoadBalancerStrategyV3 strategy = new DegraderLoadBalancerStrategyV3(config, "DegraderLoadBalancerTest", null, DEGRADER_STATE_LISTENER_FACTORIES);
List<DegraderTrackerClient> clients = new ArrayList<>();
URI uri1 = URI.create("http://test.linkedin.com:3242/fdsaf");
URIRequest request = new URIRequest(uri1);
List<CallCompletion> ccList = new ArrayList<>();
CallCompletion cc;
DegraderTrackerClient client1 = new DegraderTrackerClientImpl(uri1, getDefaultPartitionData(1d), new TestLoadBalancerClient(uri1), clock, null);
clients.add(client1);
// force client1 to be disabled if we encounter errors/high latency
DegraderControl dcClient1Default = client1.getDegraderControl(DEFAULT_PARTITION_ID);
dcClient1Default.setOverrideMinCallCount(5);
dcClient1Default.setMinCallCount(5);
dcClient1Default.setUpStep(1.0);
dcClient1Default.setHighErrorRate(0);
// Issue high latency calls to reduce client1 to the minimum number of hash points allowed.
// (1 in this case)
TrackerClient resultTC = getTrackerClient(strategy, request, new RequestContext(), 1, clients);
assertNotNull(resultTC, "expected non-null trackerclient");
for (int j = 0; j < NUM_CHECKS; j++) {
cc = ((DegraderTrackerClient) resultTC).getCallTracker().startCall();
ccList.add(cc);
}
clock.addMs(3500);
for (int j = 0; j < NUM_CHECKS; j++) {
cc = ccList.get(j);
cc.endCall();
}
// bump to next interval, and get stats.
clock.addMs(5000);
// because we want to test out the adjusted min drop rate, force the hash ring adjustment now.
strategy.setStrategy(DEFAULT_PARTITION_ID, PartitionDegraderLoadBalancerState.Strategy.LOAD_BALANCE);
resultTC = getTrackerClient(strategy, request, new RequestContext(), 1, clients);
// client1 should be reduced to 1 hash point, but since it is the only TC, it should be the
// TC returned.
assertEquals(resultTC, client1, "expected non-null trackerclient");
assertEquals((int) (strategy.getState().getPartitionState(DEFAULT_PARTITION_ID).getPointsMap().get(client1.getUri())), 1, "expected client1 to have only 1 point in hash map");
// make low latency call, we expect the computedDropRate to be adjusted because the minimum
// call count was also scaled down.
cc = client1.getCallTracker().startCall();
clock.addMs(10);
cc.endCall();
clock.addMs(TIME_INTERVAL);
Assert.assertTrue(dcClient1Default.getCurrentComputedDropRate() < 1.0, "client1 drop rate not less than 1.");
}
use of com.linkedin.d2.balancer.util.hashing.Ring 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