use of com.linkedin.d2.balancer.properties.ClusterProperties in project rest.li by linkedin.
the class SimpleLoadBalancer method getClient.
/**
* Given a Request, returns a TransportClient that can handle requests for the Request.
*
*
* @param request
* A request whose URI is a URL of the format "d2://>servicename</optional/path".
* @param requestContext context for this request
* @return A client that can be called to retrieve data for the URN.
* @throws ServiceUnavailableException
* If the load balancer can't figure out how to reach a service for the given
* URN, an ServiceUnavailableException will be thrown.
*/
@Override
public TransportClient getClient(Request request, RequestContext requestContext) throws ServiceUnavailableException {
TransportClient client;
URI uri = request.getURI();
debug(_log, "get client for uri: ", uri);
ServiceProperties service = listenToServiceAndCluster(uri);
String serviceName = service.getServiceName();
String clusterName = service.getClusterName();
ClusterProperties cluster = getClusterProperties(serviceName, clusterName);
// Check if we want to override the service URL and bypass choosing among the existing
// tracker clients. This is useful when the service we want is not announcing itself to
// the cluster, ie a private service for a set of clients.
URI targetService = LoadBalancerUtil.TargetHints.getRequestContextTargetService(requestContext);
if (targetService == null) {
LoadBalancerStateItem<UriProperties> uriItem = getUriItem(serviceName, clusterName, cluster);
UriProperties uris = uriItem.getProperty();
List<LoadBalancerState.SchemeStrategyPair> orderedStrategies = _state.getStrategiesForService(serviceName, service.getPrioritizedSchemes());
TrackerClient trackerClient = chooseTrackerClient(request, requestContext, serviceName, clusterName, cluster, uriItem, uris, orderedStrategies, service);
String clusterAndServiceUriString = trackerClient.getUri() + service.getPath();
client = new RewriteClient(serviceName, URI.create(clusterAndServiceUriString), trackerClient);
_serviceAvailableStats.inc();
} else {
_log.debug("service hint found, using generic client for target: {}", targetService);
TransportClient transportClient = _state.getClient(serviceName, targetService.getScheme());
client = new RewriteClient(serviceName, targetService, transportClient);
}
return client;
}
use of com.linkedin.d2.balancer.properties.ClusterProperties in project rest.li by linkedin.
the class LastSeenBalancerWithFacilitiesFactory method create.
@Override
public LoadBalancerWithFacilities create(D2ClientConfig config) {
LOG.info("Creating D2 LoadBalancer based on LastSeenLoadBalancerWithFacilities");
D2ClientJmxManager d2ClientJmxManager = new D2ClientJmxManager(config.d2JmxManagerPrefix, config.jmxManager);
// init connection
ZKConnectionBuilder zkConnectionBuilder = new ZKConnectionBuilder(config.zkHosts);
zkConnectionBuilder.setShutdownAsynchronously(config.shutdownAsynchronously).setIsSymlinkAware(config.isSymlinkAware).setTimeout((int) config.zkSessionTimeoutInMs);
ZKPersistentConnection zkPersistentConnection;
if (config.zkConnectionToUseForLB != null) {
LOG.info("LastSeenLoadBalancer using shared connection to zookeeper");
zkPersistentConnection = config.zkConnectionToUseForLB;
} else {
LOG.info("LastSeenLoadBalancer using its own connection to zookeeper");
zkPersistentConnection = new ZKPersistentConnection(zkConnectionBuilder);
}
// init all the stores
LastSeenZKStore<ClusterProperties> lsClusterStore = getClusterPropertiesLastSeenZKStore(config, zkPersistentConnection, d2ClientJmxManager, config._executorService, config.zookeeperReadWindowMs);
PropertyEventBus<ClusterProperties> clusterBus = new PropertyEventBusImpl<>(config._executorService);
clusterBus.setPublisher(lsClusterStore);
LastSeenZKStore<ServiceProperties> lsServiceStore = getServicePropertiesLastSeenZKStore(config, zkPersistentConnection, d2ClientJmxManager, config._executorService, config.zookeeperReadWindowMs);
PropertyEventBus<ServiceProperties> serviceBus = new PropertyEventBusImpl<>(config._executorService);
serviceBus.setPublisher(lsServiceStore);
LastSeenZKStore<UriProperties> lsUrisStore = getUriPropertiesLastSeenZKStore(config, zkPersistentConnection, d2ClientJmxManager, config._executorService, config.zookeeperReadWindowMs);
PropertyEventBus<UriProperties> uriBus = new PropertyEventBusImpl<>(config._executorService);
uriBus.setPublisher(lsUrisStore);
// create the simple load balancer
SimpleLoadBalancerState state = new SimpleLoadBalancerState(config._executorService, uriBus, clusterBus, serviceBus, config.clientFactories, config.loadBalancerStrategyFactories, config.sslContext, config.sslParameters, config.isSSLEnabled, config.partitionAccessorRegistry, config.sslSessionValidatorFactory, config.deterministicSubsettingMetadataProvider);
d2ClientJmxManager.setSimpleLoadBalancerState(state);
SimpleLoadBalancer simpleLoadBalancer = new SimpleLoadBalancer(state, config.lbWaitTimeout, config.lbWaitUnit, config._executorService);
d2ClientJmxManager.setSimpleLoadBalancer(simpleLoadBalancer);
// add facilities
LastSeenLoadBalancerWithFacilities lastSeenLoadBalancer = new LastSeenLoadBalancerWithFacilities(simpleLoadBalancer, config.basePath, config.d2ServicePath, zkPersistentConnection, lsClusterStore, lsServiceStore, lsUrisStore);
LoadBalancerWithFacilities balancer = lastSeenLoadBalancer;
if (config.warmUp) {
balancer = new WarmUpLoadBalancer(balancer, lastSeenLoadBalancer, config.startUpExecutorService, config.fsBasePath, config.d2ServicePath, config.downstreamServicesFetcher, config.warmUpTimeoutSeconds, config.warmUpConcurrentRequests);
}
return balancer;
}
use of com.linkedin.d2.balancer.properties.ClusterProperties in project rest.li by linkedin.
the class SimpleLoadBalancer method getRings.
@Override
public <K> MapKeyResult<Ring<URI>, K> getRings(URI serviceUri, Iterable<K> keys) throws ServiceUnavailableException {
ServiceProperties service = listenToServiceAndCluster(serviceUri);
String serviceName = service.getServiceName();
String clusterName = service.getClusterName();
ClusterProperties cluster = getClusterProperties(serviceName, clusterName);
LoadBalancerStateItem<UriProperties> uriItem = getUriItem(serviceName, clusterName, cluster);
UriProperties uris = uriItem.getProperty();
List<LoadBalancerState.SchemeStrategyPair> orderedStrategies = _state.getStrategiesForService(serviceName, service.getPrioritizedSchemes());
if (!orderedStrategies.isEmpty()) {
PartitionAccessor accessor = getPartitionAccessor(serviceName, clusterName);
// first distribute keys to partitions
Map<Integer, Set<K>> partitionSet = new HashMap<>();
List<MapKeyResult.UnmappedKey<K>> unmappedKeys = new ArrayList<>();
for (final K key : keys) {
int partitionId;
try {
partitionId = accessor.getPartitionId(key.toString());
} catch (PartitionAccessException e) {
unmappedKeys.add(new MapKeyResult.UnmappedKey<>(key, MapKeyResult.ErrorType.FAIL_TO_FIND_PARTITION));
continue;
}
Set<K> set = partitionSet.computeIfAbsent(partitionId, k -> new HashSet<>());
set.add(key);
}
// then we find the ring for each partition and create a map of Ring<URI> to Set<K>
final Map<Ring<URI>, Collection<K>> ringMap = new HashMap<>(partitionSet.size() * 2);
for (Map.Entry<Integer, Set<K>> entry : partitionSet.entrySet()) {
int partitionId = entry.getKey();
Ring<URI> ring = null;
for (LoadBalancerState.SchemeStrategyPair pair : orderedStrategies) {
TrackerClientSubsetItem subsetItem = getPotentialClients(serviceName, service, cluster, uris, pair.getScheme(), partitionId, uriItem.getVersion());
ring = pair.getStrategy().getRing(uriItem.getVersion(), partitionId, subsetItem.getWeightedSubset(), subsetItem.shouldForceUpdate());
if (!ring.isEmpty()) {
// don't fallback to the next strategy if there are already hosts in the current one
break;
}
}
// make sure the same ring is not used in other partition
ringMap.put(ring, entry.getValue());
}
return new MapKeyResult<>(ringMap, unmappedKeys);
} else {
throw new ServiceUnavailableException(serviceName, "PEGA_1002. Unable to find a load balancer strategy. " + "Server Schemes: [" + String.join(", ", service.getPrioritizedSchemes()) + ']');
}
}
use of com.linkedin.d2.balancer.properties.ClusterProperties in project rest.li by linkedin.
the class SimpleLoadBalancer method getClient.
/**
* Given a Request, returns a TransportClient that can handle requests for the Request.
* The callback is given a client that can be called to retrieve data for the URN.
*
* @param request
* A request whose URI is a URL of the format "d2://>servicename</optional/path".
* @param requestContext context for this request
* @throws ServiceUnavailableException
* If the load balancer can't figure out how to reach a service for the given
* URN, an ServiceUnavailableException will be thrown.
*/
@Override
public void getClient(Request request, RequestContext requestContext, Callback<TransportClient> clientCallback) {
URI uri = request.getURI();
debug(_log, "get client for uri: ", uri);
if (!D2_SCHEME_NAME.equalsIgnoreCase(uri.getScheme())) {
throw new IllegalArgumentException("Unsupported scheme in URI " + uri);
}
// get the service for this uri
String extractedServiceName = LoadBalancerUtil.getServiceNameFromUri(uri);
listenToServiceAndCluster(extractedServiceName, Callbacks.handle(service -> {
String serviceName = service.getServiceName();
String clusterName = service.getClusterName();
try {
ClusterProperties cluster = getClusterProperties(serviceName, clusterName);
// Check if we want to override the service URL and bypass choosing among the existing
// tracker clients. This is useful when the service we want is not announcing itself to
// the cluster, ie a private service for a set of clients. This mechanism is deprecated;
// use host override list instead.
@SuppressWarnings("deprecation") URI targetService = LoadBalancerUtil.TargetHints.getRequestContextTargetService(requestContext);
// Checks if we have a host override list provided in the request context. If present,
// get the override URI available override for the current cluster and service names.
HostOverrideList overrides = (HostOverrideList) requestContext.getLocalAttr(HOST_OVERRIDE_LIST);
URI override = overrides == null ? null : overrides.getOverride(clusterName, serviceName);
if (targetService == null && override == null) {
LoadBalancerStateItem<UriProperties> uriItem = getUriItem(serviceName, clusterName, cluster);
UriProperties uris = uriItem.getProperty();
List<LoadBalancerState.SchemeStrategyPair> orderedStrategies = _state.getStrategiesForService(serviceName, service.getPrioritizedSchemes());
TrackerClient trackerClient = chooseTrackerClient(request, requestContext, serviceName, clusterName, cluster, uriItem, uris, orderedStrategies, service);
String clusterAndServiceUriString = trackerClient.getUri() + service.getPath();
_serviceAvailableStats.inc();
clientCallback.onSuccess(new RewriteLoadBalancerClient(serviceName, URI.create(clusterAndServiceUriString), trackerClient));
} else {
URI target = override == null ? targetService : URI.create(override + service.getPath());
if (targetService != null && override != null) {
_log.warn("Both TargetHints and HostOverrideList are found. HostOverList will take precedence %s.", target);
}
if (_log.isDebugEnabled()) {
_log.debug("Rewrite URI as specified in the TargetHints/HostOverrideList {} for cluster {} and service {}.", target, clusterName, serviceName);
}
TransportClient transportClient = _state.getClient(serviceName, target.getScheme());
if (transportClient == null) {
throw new ServiceUnavailableException(serviceName, String.format("PEGA_1001. Cannot find transportClient for service %s and scheme %s with URI specified in" + "TargetHints/HostOverrideList %s", serviceName, target.getScheme(), target));
}
clientCallback.onSuccess(new RewriteLoadBalancerClient(serviceName, target, transportClient));
}
} catch (ServiceUnavailableException e) {
clientCallback.onError(e);
}
}, clientCallback));
}
use of com.linkedin.d2.balancer.properties.ClusterProperties in project rest.li by linkedin.
the class SimpleLoadBalancer method getPotentialClients.
private Map<URI, TrackerClient> getPotentialClients(String serviceName, ServiceProperties serviceProperties, ClusterProperties clusterProperties, Set<URI> possibleUris, int partitionId, SubsettingState.SubsetItem subsetItem) {
Map<URI, TrackerClient> clientsToLoadBalance;
if (possibleUris == null) {
// just return an empty list if possibleUris is 'null'.
clientsToLoadBalance = Collections.emptyMap();
} else {
Map<URI, Double> weightedSubset = subsetItem.getWeightedUriSubset();
;
Set<URI> doNotSlowStartUris = subsetItem.getDoNotSlowStartUris();
clientsToLoadBalance = new HashMap<>(possibleUris.size());
for (URI possibleUri : possibleUris) {
// don't pay attention to this uri if it's banned or not in the subset
if (!serviceProperties.isBanned(possibleUri) && !clusterProperties.isBanned(possibleUri)) {
if (weightedSubset.containsKey(possibleUri)) {
TrackerClient possibleTrackerClient = _state.getClient(serviceName, possibleUri);
if (possibleTrackerClient != null) {
if (doNotSlowStartUris.contains(possibleUri)) {
possibleTrackerClient.setDoNotSlowStart(true);
}
// Only update subset weight if the subset item is a weighted subset
if (subsetItem.isWeightedSubset()) {
possibleTrackerClient.setSubsetWeight(partitionId, weightedSubset.get(possibleUri));
}
clientsToLoadBalance.put(possibleUri, possibleTrackerClient);
}
}
} else {
warn(_log, "skipping banned uri: ", possibleUri);
}
}
}
debug(_log, "got clients to load balancer for ", serviceName, ": ", clientsToLoadBalance);
return clientsToLoadBalance;
}
Aggregations