use of com.linkedin.d2.balancer.clients.TrackerClient in project rest.li by linkedin.
the class SimpleLoadBalancerState method refreshTransportClientsPerService.
void refreshTransportClientsPerService(ServiceProperties serviceProperties) {
String serviceName = serviceProperties.getServiceName();
//create new TransportClients
Map<String, TransportClient> newTransportClients = createAndInsertTransportClientTo(serviceProperties);
// clients-by-scheme map is never edited, only replaced.
newTransportClients = Collections.unmodifiableMap(newTransportClients);
final Map<String, TransportClient> oldTransportClients = _serviceClients.put(serviceName, newTransportClients);
// gets the information for configuring the parameter for how DegraderImpl should behave for
// each tracker clients that we instantiate here. If there's no such information, then we'll instantiate
// each tracker clients with default configuration
DegraderImpl.Config config = null;
if (serviceProperties.getDegraderProperties() != null && !serviceProperties.getDegraderProperties().isEmpty()) {
config = DegraderConfigFactory.toDegraderConfig(serviceProperties.getDegraderProperties());
} else {
debug(_log, "trying to see if there's a special degraderImpl properties but serviceInfo.getDegraderImpl() is null" + " for service name = " + serviceName + " so we'll set config to default");
}
Clock clk = SystemClock.instance();
if (serviceProperties.getLoadBalancerStrategyProperties() != null) {
Map<String, Object> loadBalancerStrategyProperties = serviceProperties.getLoadBalancerStrategyProperties();
clk = MapUtil.getWithDefault(loadBalancerStrategyProperties, PropertyKeys.CLOCK, SystemClock.instance(), Clock.class);
}
Map<URI, TrackerClient> newTrackerClients;
// update all tracker clients to use new configs
LoadBalancerStateItem<UriProperties> uriItem = _uriProperties.get(serviceProperties.getClusterName());
UriProperties uriProperties = uriItem == null ? null : uriItem.getProperty();
if (uriProperties != null) {
Set<URI> uris = uriProperties.Uris();
// clients-by-uri map may be edited later by UriPropertiesListener.handlePut
newTrackerClients = new ConcurrentHashMap<URI, TrackerClient>(CollectionUtils.getMapInitialCapacity(uris.size(), 0.75f), 0.75f, 1);
long trackerClientInterval = getTrackerClientInterval(serviceProperties);
String errorStatusPattern = getErrorStatusPattern(serviceProperties);
for (URI uri : uris) {
TrackerClient trackerClient = getTrackerClient(serviceName, uri, uriProperties.getPartitionDataMap(uri), config, clk, trackerClientInterval, errorStatusPattern);
if (trackerClient != null) {
newTrackerClients.put(uri, trackerClient);
}
}
} else {
// clients-by-uri map may be edited later by UriPropertiesListener.handlePut
newTrackerClients = new ConcurrentHashMap<URI, TrackerClient>(16, 0.75f, 1);
}
//override the oldTrackerClients with newTrackerClients
_trackerClients.put(serviceName, newTrackerClients);
// No need to shut down oldTrackerClients, because they all point directly to the TransportClient for the service
// We do need to shut down the old transport clients
shutdownTransportClients(oldTransportClients, serviceName);
}
use of com.linkedin.d2.balancer.clients.TrackerClient in project rest.li by linkedin.
the class SimpleLoadBalancerState method shutdown.
@Override
public void shutdown(final PropertyEventShutdownCallback shutdown) {
trace(_log, "shutdown");
// shutdown all three registries, all tracker clients, and the event thread
_executor.execute(new PropertyEvent("shutdown load balancer state") {
@Override
public void innerRun() {
// Need to shutdown loadBalancerStrategies before the transportClients are shutdown
for (Map<String, LoadBalancerStrategy> strategyEntry : _serviceStrategies.values()) {
strategyEntry.values().forEach(LoadBalancerStrategy::shutdown);
}
// put all tracker clients into a single set for convenience
Set<TransportClient> transportClients = new HashSet<TransportClient>();
for (Map<String, TransportClient> clientsByScheme : _serviceClients.values()) {
transportClients.addAll(clientsByScheme.values());
}
Callback<None> trackerCallback = Callbacks.countDown(Callbacks.<None>adaptSimple(new SimpleCallback() {
@Override
public void onDone() {
shutdown.done();
}
}), transportClients.size());
info(_log, "shutting down cluster clients");
for (TransportClient transportClient : transportClients) {
transportClient.shutdown(trackerCallback);
}
// so it is needed to notify all the listeners
for (SimpleLoadBalancerStateListener listener : _listeners) {
// Notify the strategy removal
for (Map.Entry<String, Map<String, LoadBalancerStrategy>> serviceStrategy : _serviceStrategies.entrySet()) {
for (Map.Entry<String, LoadBalancerStrategy> strategyEntry : serviceStrategy.getValue().entrySet()) {
listener.onStrategyRemoved(serviceStrategy.getKey(), strategyEntry.getKey(), strategyEntry.getValue());
}
// Also notify the client removal
Map<URI, TrackerClient> trackerClients = _trackerClients.get(serviceStrategy.getKey());
if (trackerClients != null) {
for (TrackerClient client : trackerClients.values()) {
listener.onClientRemoved(serviceStrategy.getKey(), client);
}
}
}
}
}
});
}
use of com.linkedin.d2.balancer.clients.TrackerClient in project rest.li by linkedin.
the class DegraderLoadBalancerStrategyV2 method getTrackerClient.
@Override
public TrackerClient getTrackerClient(Request request, RequestContext requestContext, long clusterGenerationId, int partitionId, List<TrackerClient> trackerClients) {
if (partitionId != DEFAULT_PARTITION_ID) {
throw new UnsupportedOperationException("Trying to access partition: " + partitionId + "on an unpartitioned cluster");
}
debug(_log, "getTrackerClient with generation id ", clusterGenerationId, " on tracker clients: ", clusterGenerationId);
if (trackerClients == null || trackerClients.size() == 0) {
warn(_log, "getTrackerClient called with null/empty trackerClients, so returning null");
return null;
}
// only one thread will be allowed to enter updateState, so if multiple threads call
// getTrackerClient while the _state is not populated, they won't be able return a
// tracker client from the hash ring, and will return null.
checkUpdateState(clusterGenerationId, trackerClients);
boolean hasInitializationError = _state.hasError();
URI targetHostUri = KeyMapper.TargetHostHints.getRequestContextTargetHost(requestContext);
Set<URI> excludedUris = ExcludedHostHints.getRequestContextExcludedHosts(requestContext);
URI hostHeaderUri = targetHostUri;
//no valid target host header was found in the request
if (!hasInitializationError && targetHostUri == null) {
// Compute the hash code
int hashCode = _hashFunction.hash(request);
// we operate only on URIs to ensure that we never hold on to an old tracker client
// that the cluster manager has removed
Ring<URI> ring = _state.getRing();
Iterator<URI> iterator = ring.getIterator(hashCode);
while (iterator.hasNext() && targetHostUri == null) {
URI uri = iterator.next();
if (excludedUris == null || !excludedUris.contains(uri)) {
targetHostUri = uri;
}
}
ExcludedHostHints.addRequestContextExcludedHost(requestContext, targetHostUri);
} else if (hasInitializationError && targetHostUri == null) {
//if we encounter an error while initializing the state, we'll choose a tracker client at random
targetHostUri = trackerClients.get(new Random().nextInt(trackerClients.size())).getUri();
} else {
debug(_log, "Degrader honoring target host header in request, skipping hashing. URI: " + targetHostUri.toString());
}
TrackerClient client = null;
if (targetHostUri != null) {
// consistent hash ring! Therefore, this linear scan is the best we can do.
for (TrackerClient trackerClient : trackerClients) {
if (trackerClient.getUri().equals(targetHostUri)) {
client = trackerClient;
break;
}
}
if (client == null) {
warn(_log, "No client found for " + targetHostUri + (hostHeaderUri == null ? ", degrader load balancer state is inconsistent with cluster manager" : ", target host specified is no longer part of cluster"));
}
} else {
warn(_log, "unable to find a URI to use");
}
boolean dropCall = client == null;
if (!dropCall) {
dropCall = client.getDegrader(DEFAULT_PARTITION_ID).checkDrop();
if (dropCall) {
warn(_log, "client's degrader is dropping call for: ", client);
} else {
debug(_log, "returning client: ", client);
}
}
return (!dropCall) ? client : null;
}
use of com.linkedin.d2.balancer.clients.TrackerClient in project rest.li by linkedin.
the class DegraderLoadBalancerStrategyV2 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 trackerClients
* @param pointsMap
* @param pointsPerWeight
*/
public static void overrideMinCallCount(double newOverrideDropRate, List<TrackerClient> trackerClients, Map<URI, Integer> pointsMap, int pointsPerWeight) {
for (TrackerClient client : trackerClients) {
int currentOverrideMinCallCount = client.getDegraderControl(DEFAULT_PARTITION_ID).getOverrideMinCallCount();
double hashFactor = pointsMap.get(client.getUri()) / pointsPerWeight;
double transmitFactor = 1.0 - newOverrideDropRate;
int newOverrideMinCallCount = (int) Math.max(Math.round(client.getDegraderControl(DEFAULT_PARTITION_ID).getMinCallCount() * hashFactor * transmitFactor), 1);
if (newOverrideMinCallCount != currentOverrideMinCallCount) {
client.getDegraderControl(DEFAULT_PARTITION_ID).setOverrideMinCallCount(newOverrideMinCallCount);
warn(_log, "overriding Min Call Count to ", newOverrideMinCallCount, " for client: ", client.getUri());
}
}
}
use of com.linkedin.d2.balancer.clients.TrackerClient in project rest.li by linkedin.
the class DegraderLoadBalancerStrategyV2 method getUnhealthyTrackerClients.
private static List<String> getUnhealthyTrackerClients(List<TrackerClient> trackerClients, Map<URI, Integer> pointsMap, DegraderLoadBalancerStrategyConfig config) {
List<String> unhealthyClients = new ArrayList<String>();
for (TrackerClient client : trackerClients) {
int perfectHealth = (int) (client.getPartitionWeight(DEFAULT_PARTITION_ID) * config.getPointsPerWeight());
Integer point = pointsMap.get(client.getUri());
if (point < perfectHealth) {
unhealthyClients.add(client.getUri() + ":" + point + "/" + perfectHealth);
}
}
return unhealthyClients;
}
Aggregations