@Test public void testPropertyChange() throws Exception { BlobStoreConfigurationSource source = new BlobStoreConfigurationSource(ctx); FixedDelayPollingScheduler scheduler = new FixedDelayPollingScheduler(0, 1000, false); DynamicConfiguration dynamicConfig = new DynamicConfiguration(source, scheduler); ConfigurationManager.loadPropertiesFromConfiguration(dynamicConfig); DynamicStringProperty test1 = DynamicPropertyFactory.getInstance().getStringProperty("test1", ""); DynamicStringProperty test2 = DynamicPropertyFactory.getInstance().getStringProperty("test2", ""); DynamicStringProperty test3 = DynamicPropertyFactory.getInstance().getStringProperty("test3", ""); assertEquals("val1", test1.get()); assertEquals("val2", test2.get()); assertEquals("val3", test3.get()); update(); Thread.sleep(1000); assertEquals("vala", test1.get()); assertEquals("valb", test2.get()); assertEquals("valc", test3.get()); }
@Override public Server chooseServer(Object key) { if (!ENABLED.get() || getLoadBalancerStats().getAvailableZones().size() <= 1) { logger.debug("Zone aware logic disabled or there is only one zone"); return super.chooseServer(key); } Server server = null; try { LoadBalancerStats lbStats = getLoadBalancerStats(); Map<String, ZoneSnapshot> zoneSnapshot = ZoneAvoidanceRule.createSnapshot(lbStats); logger.debug("Zone snapshots: {}", zoneSnapshot); if (triggeringLoad == null) { triggeringLoad = DynamicPropertyFactory.getInstance() .getDoubleProperty( "ZoneAwareNIWSDiscoveryLoadBalancer." + this.getName() + ".triggeringLoadPerServerThreshold", 0.2d); } if (triggeringBlackoutPercentage == null) { triggeringBlackoutPercentage = DynamicPropertyFactory.getInstance() .getDoubleProperty( "ZoneAwareNIWSDiscoveryLoadBalancer." + this.getName() + ".avoidZoneWithBlackoutPercetage", 0.99999d); } Set<String> availableZones = ZoneAvoidanceRule.getAvailableZones( zoneSnapshot, triggeringLoad.get(), triggeringBlackoutPercentage.get()); logger.debug("Available zones: {}", availableZones); if (availableZones != null && availableZones.size() < zoneSnapshot.keySet().size()) { String zone = ZoneAvoidanceRule.randomChooseZone(zoneSnapshot, availableZones); logger.debug("Zone chosen: {}", zone); if (zone != null) { BaseLoadBalancer zoneLoadBalancer = getLoadBalancer(zone); server = zoneLoadBalancer.chooseServer(key); } } } catch (Throwable e) { logger.error("Unexpected exception when choosing server using zone aware logic", e); } if (server != null) { return server; } else { logger.debug("Zone avoidance logic is not invoked."); return super.chooseServer(key); } }
public RibbonCommand( String commandKey, RestClient restClient, HttpClientRequest.Verb verb, String uri, MultivaluedMap<String, String> headers, MultivaluedMap<String, String> params, InputStream requestEntity) throws URISyntaxException { super( Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey(commandKey)) .andCommandPropertiesDefaults( // we want to default to semaphore-isolation since this wraps // 2 others commands that are already thread isolated HystrixCommandProperties.Setter() .withExecutionIsolationStrategy( HystrixCommandProperties.ExecutionIsolationStrategy.SEMAPHORE) .withExecutionIsolationSemaphoreMaxConcurrentRequests( DynamicPropertyFactory.getInstance() .getIntProperty( ZuulConstants.ZUUL_EUREKA + commandKey + ".semaphore.maxSemaphores", 100) .get()))); this.restClient = restClient; this.verb = verb; this.uri = new URI(uri); this.headers = headers; this.params = params; this.requestEntity = requestEntity; }
private static Object getPluginImplementationViaArchaius(Class<?> pluginClass) { String classSimpleName = pluginClass.getSimpleName(); // Check Archaius for plugin class. String propertyName = "hystrix.plugin." + classSimpleName + ".implementation"; String implementingClass = DynamicPropertyFactory.getInstance().getStringProperty(propertyName, null).get(); if (implementingClass != null) { try { Class<?> cls = Class.forName(implementingClass); // narrow the scope (cast) to the type we're expecting cls = cls.asSubclass(pluginClass); return cls.newInstance(); } catch (ClassCastException e) { throw new RuntimeException( classSimpleName + " implementation is not an instance of " + classSimpleName + ": " + implementingClass); } catch (ClassNotFoundException e) { throw new RuntimeException( classSimpleName + " implementation class not found: " + implementingClass, e); } catch (InstantiationException e) { throw new RuntimeException( classSimpleName + " implementation not able to be instantiated: " + implementingClass, e); } catch (IllegalAccessException e) { throw new RuntimeException( classSimpleName + " implementation not able to be accessed: " + implementingClass, e); } } else { return null; } }
/** * Constructor * * @param serviceName the service cluster name * @param myAvailabilityZone the availability zone of the server running the load balancer * @param metricRegistry the registry for collected metrics */ public ZoneAwareLoadBalancer( String serviceName, String myAvailabilityZone, MetricRegistry metricRegistry) { Preconditions.checkArgument( !Strings.isNullOrEmpty(serviceName), "'serviceName' cannot be null or empty."); Preconditions.checkArgument( !Strings.isNullOrEmpty(myAvailabilityZone), "'myAvailabilityZone' cannot be null or empty."); this.serviceName = serviceName; this.myLocation = new Location(myAvailabilityZone); this.locations = CacheBuilder.newBuilder() .expireAfterAccess(5, TimeUnit.MINUTES) .build( new CacheLoader<ServerStats, Location>() { @Override public Location load(ServerStats key) throws Exception { return getLocationFromServer(key); } }); this.propMaxRequestsPerSecond = DynamicPropertyFactory.getInstance() .getDoubleProperty("janus.serviceName." + serviceName + ".maxRequestsPerSecond", 100); this.propEscapeAreaThreshold = DynamicPropertyFactory.getInstance() .getDoubleProperty("janus.serviceName." + serviceName + ".escapeAreaThreshold", 0.9); this.propEscapeRegionThreshold = DynamicPropertyFactory.getInstance() .getDoubleProperty("janus.serviceName." + serviceName + ".escapeRegionThreshold", 0.9); this.propEscapeAvailabilityThreshold = DynamicPropertyFactory.getInstance() .getDoubleProperty( "janus.serviceName." + serviceName + ".escapeAvailabilityThreshold", 0.9); this.metricRegistry = metricRegistry; }
/** Servlet that writes SSE JSON every time a request is made */ public class HystrixRequestEventsSseServlet extends HystrixSampleSseServlet { private static final long serialVersionUID = 6389353893099737870L; /* used to track number of connections and throttle */ private static AtomicInteger concurrentConnections = new AtomicInteger(0); private static DynamicIntProperty maxConcurrentConnections = DynamicPropertyFactory.getInstance() .getIntProperty("hystrix.config.stream.maxConcurrentConnections", 5); public HystrixRequestEventsSseServlet() { this( HystrixRequestEventsStream.getInstance().observe(), DEFAULT_PAUSE_POLLER_THREAD_DELAY_IN_MS); } /* package-private */ HystrixRequestEventsSseServlet( Observable<HystrixRequestEvents> sampleStream, int pausePollerThreadDelayInMs) { super( sampleStream.map( new Func1<HystrixRequestEvents, String>() { @Override public String call(HystrixRequestEvents requestEvents) { return SerialHystrixRequestEvents.toJsonString(requestEvents); } }), pausePollerThreadDelayInMs); } @Override protected int getMaxNumberConcurrentConnectionsAllowed() { return maxConcurrentConnections.get(); } @Override protected int getNumberCurrentConnections() { return concurrentConnections.get(); } @Override protected int incrementAndGetCurrentConcurrentConnections() { return concurrentConnections.incrementAndGet(); } @Override protected void decrementCurrentConcurrentConnections() { concurrentConnections.decrementAndGet(); } }
protected void setPropertyInternal(final String propName, Object value) { String stringValue = (value == null) ? "" : String.valueOf(value); properties.put(propName, stringValue); if (!enableDynamicProperties) { return; } String configKey = getConfigKey(propName); final DynamicStringProperty prop = DynamicPropertyFactory.getInstance().getStringProperty(configKey, null); Runnable callback = new Runnable() { @Override public void run() { String value = prop.get(); if (value != null) { properties.put(propName, value); } else { properties.remove(propName); } } // equals and hashcode needed // since this is anonymous object is later used as a set key @Override public boolean equals(Object other) { if (other == null) { return false; } if (getClass() == other.getClass()) { return toString().equals(other.toString()); } return false; } @Override public String toString() { return propName; } @Override public int hashCode() { return propName.hashCode(); } }; prop.addCallback(callback); dynamicProperties.put(propName, prop); }
/** * Convert <code>VIPAddress</code> by substituting environment variables if necessary. * * @param vipAddressMacro the macro for which the interpolation needs to be made. * @return a string representing the final <code>VIPAddress</code> after substitution. */ private static String resolveDeploymentContextBasedVipAddresses(String vipAddressMacro) { String result = vipAddressMacro; if (vipAddressMacro == null) { return null; } Matcher matcher = VIP_ATTRIBUTES_PATTERN.matcher(result); while (matcher.find()) { String key = matcher.group(1); String value = DynamicPropertyFactory.getInstance().getStringProperty(key, "").get(); logger.debug("att:" + matcher.group()); logger.debug(", att key:" + key); logger.debug(", att value:" + value); logger.debug(""); result = result.replaceAll("\\$\\{" + key + "\\}", value); matcher = VIP_ATTRIBUTES_PATTERN.matcher(result); } return result; }
@CommonsLog public class SimpleHostRoutingFilter extends ZuulFilter { private static final DynamicIntProperty SOCKET_TIMEOUT = DynamicPropertyFactory.getInstance() .getIntProperty(ZuulConstants.ZUUL_HOST_SOCKET_TIMEOUT_MILLIS, 10000); private static final DynamicIntProperty CONNECTION_TIMEOUT = DynamicPropertyFactory.getInstance() .getIntProperty(ZuulConstants.ZUUL_HOST_CONNECT_TIMEOUT_MILLIS, 2000); private final Timer connectionManagerTimer = new Timer("SimpleHostRoutingFilter.connectionManagerTimer", true); private ProxyRequestHelper helper; private PoolingHttpClientConnectionManager connectionManager; private CloseableHttpClient httpClient; private final Runnable clientloader = new Runnable() { @Override public void run() { try { httpClient.close(); } catch (IOException ex) { log.error("error closing client", ex); } httpClient = newClient(); } }; public SimpleHostRoutingFilter() { this(new ProxyRequestHelper()); } public SimpleHostRoutingFilter(ProxyRequestHelper helper) { this.helper = helper; } @PostConstruct private void initialize() { this.httpClient = newClient(); SOCKET_TIMEOUT.addCallback(clientloader); CONNECTION_TIMEOUT.addCallback(clientloader); connectionManagerTimer.schedule( new TimerTask() { @Override public void run() { if (connectionManager == null) { return; } connectionManager.closeExpiredConnections(); } }, 30000, 5000); } @PreDestroy public void stop() { connectionManagerTimer.cancel(); } @Override public String filterType() { return "route"; } @Override public int filterOrder() { return 100; } @Override public boolean shouldFilter() { return RequestContext.getCurrentContext().getRouteHost() != null && RequestContext.getCurrentContext().sendZuulResponse(); } @Override public Object run() { RequestContext context = RequestContext.getCurrentContext(); HttpServletRequest request = context.getRequest(); MultiValueMap<String, String> headers = this.helper.buildZuulRequestHeaders(request); MultiValueMap<String, String> params = this.helper.buildZuulRequestQueryParams(request); String verb = getVerb(request); InputStream requestEntity = getRequestBody(request); String uri = this.helper.buildZuulRequestURI(request); try { HttpResponse response = forward(httpClient, verb, uri, request, headers, params, requestEntity); setResponse(response); } catch (Exception ex) { context.set("error.status_code", HttpServletResponse.SC_INTERNAL_SERVER_ERROR); context.set("error.exception", ex); } return null; } protected PoolingHttpClientConnectionManager newConnectionManager() { try { final SSLContext sslContext = SSLContext.getInstance("SSL"); sslContext.init( null, new TrustManager[] { new X509TrustManager() { @Override public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {} @Override public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {} @Override public X509Certificate[] getAcceptedIssuers() { return null; } } }, new SecureRandom()); final Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create() .register("http", PlainConnectionSocketFactory.INSTANCE) .register("https", new SSLConnectionSocketFactory(sslContext)) .build(); connectionManager = new PoolingHttpClientConnectionManager(registry); connectionManager.setMaxTotal( Integer.parseInt(System.getProperty("zuul.max.host.connections", "200"))); connectionManager.setDefaultMaxPerRoute( Integer.parseInt(System.getProperty("zuul.max.host.connections", "20"))); return connectionManager; } catch (Exception ex) { throw new RuntimeException(ex); } } protected CloseableHttpClient newClient() { final RequestConfig requestConfig = RequestConfig.custom() .setSocketTimeout(SOCKET_TIMEOUT.get()) .setConnectTimeout(CONNECTION_TIMEOUT.get()) .setCookieSpec(CookieSpecs.IGNORE_COOKIES) .build(); return HttpClients.custom() .setConnectionManager(newConnectionManager()) .setDefaultRequestConfig(requestConfig) .setRetryHandler(new DefaultHttpRequestRetryHandler(0, false)) .setRedirectStrategy( new RedirectStrategy() { @Override public boolean isRedirected( HttpRequest request, HttpResponse response, HttpContext context) throws ProtocolException { return false; } @Override public HttpUriRequest getRedirect( HttpRequest request, HttpResponse response, HttpContext context) throws ProtocolException { return null; } }) .build(); } private HttpResponse forward( HttpClient httpclient, String verb, String uri, HttpServletRequest request, MultiValueMap<String, String> headers, MultiValueMap<String, String> params, InputStream requestEntity) throws Exception { Map<String, Object> info = this.helper.debug(verb, uri, headers, params, requestEntity); URL host = RequestContext.getCurrentContext().getRouteHost(); HttpHost httpHost = getHttpHost(host); uri = StringUtils.cleanPath(host.getPath() + uri); HttpRequest httpRequest; switch (verb.toUpperCase()) { case "POST": HttpPost httpPost = new HttpPost(uri + getQueryString()); httpRequest = httpPost; httpPost.setEntity(new InputStreamEntity(requestEntity, request.getContentLength())); break; case "PUT": HttpPut httpPut = new HttpPut(uri + getQueryString()); httpRequest = httpPut; httpPut.setEntity(new InputStreamEntity(requestEntity, request.getContentLength())); break; case "PATCH": HttpPatch httpPatch = new HttpPatch(uri + getQueryString()); httpRequest = httpPatch; httpPatch.setEntity(new InputStreamEntity(requestEntity, request.getContentLength())); break; default: httpRequest = new BasicHttpRequest(verb, uri + getQueryString()); log.debug(uri + getQueryString()); } try { httpRequest.setHeaders(convertHeaders(headers)); log.debug(httpHost.getHostName() + " " + httpHost.getPort() + " " + httpHost.getSchemeName()); HttpResponse zuulResponse = forwardRequest(httpclient, httpHost, httpRequest); this.helper.appendDebug( info, zuulResponse.getStatusLine().getStatusCode(), revertHeaders(zuulResponse.getAllHeaders())); return zuulResponse; } finally { // When HttpClient instance is no longer needed, // shut down the connection manager to ensure // immediate deallocation of all system resources // httpclient.getConnectionManager().shutdown(); } } private MultiValueMap<String, String> revertHeaders(Header[] headers) { MultiValueMap<String, String> map = new LinkedMultiValueMap<String, String>(); for (Header header : headers) { String name = header.getName(); if (!map.containsKey(name)) { map.put(name, new ArrayList<String>()); } map.get(name).add(header.getValue()); } return map; } private Header[] convertHeaders(MultiValueMap<String, String> headers) { List<Header> list = new ArrayList<>(); for (String name : headers.keySet()) { for (String value : headers.get(name)) { list.add(new BasicHeader(name, value)); } } return list.toArray(new BasicHeader[0]); } private HttpResponse forwardRequest( HttpClient httpclient, HttpHost httpHost, HttpRequest httpRequest) throws IOException { return httpclient.execute(httpHost, httpRequest); } private String getQueryString() throws UnsupportedEncodingException { HttpServletRequest request = RequestContext.getCurrentContext().getRequest(); MultiValueMap<String, String> params = helper.buildZuulRequestQueryParams(request); StringBuilder query = new StringBuilder(); for (Map.Entry<String, List<String>> entry : params.entrySet()) { String key = URLEncoder.encode(entry.getKey(), "UTF-8"); for (String value : entry.getValue()) { query.append("&"); query.append(key); query.append("="); query.append(URLEncoder.encode(value, "UTF-8")); } } return (query.length() > 0) ? "?" + query.substring(1) : ""; } private HttpHost getHttpHost(URL host) { HttpHost httpHost = new HttpHost(host.getHost(), host.getPort(), host.getProtocol()); return httpHost; } private InputStream getRequestBody(HttpServletRequest request) { InputStream requestEntity = null; try { requestEntity = request.getInputStream(); } catch (IOException ex) { // no requestBody is ok. } return requestEntity; } private String getVerb(HttpServletRequest request) { String sMethod = request.getMethod(); return sMethod.toUpperCase(); } private void setResponse(HttpResponse response) throws IOException { this.helper.setResponse( response.getStatusLine().getStatusCode(), response.getEntity() == null ? null : response.getEntity().getContent(), revertHeaders(response.getAllHeaders())); } /** * Add header names to exclude from proxied response in the current request. * * @param names */ protected void addIgnoredHeaders(String... names) { helper.addIgnoredHeaders(names); } }
/* * (non-Javadoc) * @see com.netflix.eureka.EurekaServerConfig#getAWSSecretKey() */ @Override public String getAWSSecretKey() { return configInstance.getStringProperty(namespace + "awsSecretKey", null).get().trim(); }
/* * (non-Javadoc) * @see com.netflix.eureka.EurekaServerConfig#getAWSAccessId() */ @Override public String getAWSAccessId() { return configInstance.getStringProperty(namespace + "awsAccessId", null).get().trim(); }
@Override public long getASGUpdateIntervalMs() { return configInstance.getIntProperty(namespace + "asgUpdateIntervalMs", (60 * 1000)).get(); }
/** * User: gorzell Date: 1/17/13 Time: 10:18 AM Some of the basic plumbing and properties for a * polling source that talks to Dynamo. */ public abstract class AbstractDynamoDbConfigurationSource<T> { private static final Logger log = LoggerFactory.getLogger(AbstractDynamoDbConfigurationSource.class); // Property names static final String tablePropertyName = "com.netflix.config.dynamo.tableName"; static final String keyAttributePropertyName = "com.netflix.config.dynamo.keyAttributeName"; static final String valueAttributePropertyName = "com.netflix.config.dynamo.valueAttributeName"; static final String endpointPropertyName = "com.netflix.config.dynamo.endpoint"; static final String pollingMaxBackOffMsPropertyName = "com.netflix.config.dynamo.maxPollingBackOffMs"; static final String pollingMinBackOffMsPropertyName = "com.netflix.config.dynamo.maxPollingBackOffMs"; static final String maxRetryCountPropertyName = "com.netflix.config.dynamo.maxRetryCount"; // Property defaults static final String defaultTable = "archaiusProperties"; static final String defaultKeyAttribute = "key"; static final String defaultValueAttribute = "value"; static final String defaultEndpoint = "dynamodb.us-east-1.amazonaws.com"; static final Long defaultMaxBackOffMs = 5 * 1000L; static final Long defaultMinBackOffMs = 500L; static final Long defaultMaxRetryCount = 100L; // Dynamic Properties protected DynamicStringProperty tableName = DynamicPropertyFactory.getInstance().getStringProperty(tablePropertyName, defaultTable); protected DynamicStringProperty keyAttributeName = DynamicPropertyFactory.getInstance() .getStringProperty(keyAttributePropertyName, defaultKeyAttribute); protected DynamicStringProperty valueAttributeName = DynamicPropertyFactory.getInstance() .getStringProperty(valueAttributePropertyName, defaultValueAttribute); protected DynamicStringProperty endpointName = DynamicPropertyFactory.getInstance().getStringProperty(endpointPropertyName, defaultEndpoint); protected DynamicLongProperty maxBackOffMs = DynamicPropertyFactory.getInstance() .getLongProperty(pollingMaxBackOffMsPropertyName, defaultMaxBackOffMs); protected DynamicLongProperty minBackOffMs = DynamicPropertyFactory.getInstance() .getLongProperty(pollingMinBackOffMsPropertyName, defaultMinBackOffMs); protected DynamicLongProperty maxRetryCount = DynamicPropertyFactory.getInstance() .getLongProperty(maxRetryCountPropertyName, defaultMaxRetryCount); protected AmazonDynamoDB dbClient; public AbstractDynamoDbConfigurationSource() { this(new AmazonDynamoDBClient()); setEndpoint(); } public AbstractDynamoDbConfigurationSource(ClientConfiguration clientConfiguration) { this(new AmazonDynamoDBClient(clientConfiguration)); setEndpoint(); } public AbstractDynamoDbConfigurationSource(AWSCredentials credentials) { this(new AmazonDynamoDBClient(credentials)); setEndpoint(); } public AbstractDynamoDbConfigurationSource( AWSCredentials credentials, ClientConfiguration clientConfiguration) { this(new AmazonDynamoDBClient(credentials, clientConfiguration)); setEndpoint(); } public AbstractDynamoDbConfigurationSource(AWSCredentialsProvider credentialsProvider) { this(new AmazonDynamoDBClient(credentialsProvider)); setEndpoint(); } public AbstractDynamoDbConfigurationSource( AWSCredentialsProvider credentialsProvider, ClientConfiguration clientConfiguration) { this(new AmazonDynamoDBClient(credentialsProvider, clientConfiguration)); setEndpoint(); } public AbstractDynamoDbConfigurationSource(AmazonDynamoDB dbClient) { this.dbClient = dbClient; } protected ScanResult dbScanWithThroughputBackOff(ScanRequest scanRequest) { Long currentBackOffMs = minBackOffMs.get(); Long retryCount = 0L; while (true) { try { return dbClient.scan(scanRequest); } catch (ProvisionedThroughputExceededException e) { currentBackOffMs = Math.min(currentBackOffMs * 2, maxBackOffMs.get()); log.error( String.format( "Failed to poll Dynamo due to ProvisionedThroughputExceededException. Backing off for %d ms.", currentBackOffMs)); if (retryCount > maxRetryCount.get()) { throw e; } retryCount++; try { Thread.sleep(currentBackOffMs); } catch (InterruptedException ex) { } } } } protected abstract Map<String, T> loadPropertiesFromTable(String table); // TODO Javadoc public void validateDb() { String table = tableName.get(); loadPropertiesFromTable(table); log.info("Successfully polled Dynamo for a new configuration based on table:" + table); } private void setEndpoint() { String endpoint = endpointName.get(); dbClient.setEndpoint(endpoint); log.info("Set Dynamo endpoint:" + endpoint); } }
protected DynamicStringProperty getProperty(String key) { return DynamicPropertyFactory.getInstance().getStringProperty(key, VALUE_NOT_SET); }
@Override public int getMaxElementsInReplicationPool() { return configInstance.getIntProperty(namespace + "maxElementsInReplicationPool", 120).get(); }
@Override public int getMinThreadsForStatusReplication() { return configInstance.getIntProperty(namespace + "minThreadsForStatusReplication", 1).get(); }
@Override public long getMaxIdleThreadInMinutesAgeForStatusReplication() { return configInstance .getLongProperty(namespace + "maxIdleThreadAgeInMinutesForStatusReplication", 10) .get(); }
@Override public boolean shouldDisableDelta() { return configInstance.getBooleanProperty(namespace + "disableDelta", false).get(); }
@Override public long getResponseCacheUpdateIntervalMs() { return configInstance .getIntProperty(namespace + "responseCacheUpdateIntervalMs", (30 * 1000)) .get(); }
@Override public long getResponseCacheAutoExpirationInSeconds() { return configInstance .getIntProperty(namespace + "responseCacheAutoExpirationInSeconds", 180) .get(); }
@Override public long getEvictionIntervalTimerInMs() { return configInstance .getLongProperty(namespace + "evictionIntervalTimerInMs", (60 * 1000)) .get(); }
@Override public long getMaxIdleThreadAgeInMinutesForReplication() { return configInstance .getIntProperty(namespace + "maxIdleThreadAgeInMinutesForReplication", 15) .get(); }
public class Rewriter { private DatastoreObjectCache<RewriteRule> rules = new DatastoreObjectCache<>( RewriteRule.class, DynamicPropertyFactory.getInstance().getLongProperty("rewrite.cache", 60 * 1000)); }
/** * Load balancer that can avoid a zone as a whole when choosing server. * * <p>The key metric used to measure the zone condition is Average Active Requests, which is * aggregated per rest client per zone. It is the total outstanding requests in a zone divided by * number of available targeted instances (excluding circuit breaker tripped instances). This metric * is very effective when timeout occurs slowly on a bad zone. * * <p>The LoadBalancer will calculate and examine zone stats of all available zones. If the Average * Active Requests for any zone has reached a configured threshold, this zone will be dropped from * the active server list. In case more than one zone has reached the threshold, the zone with the * most active requests per server will be dropped. Once the the worst zone is dropped, a zone will * be chosen among the rest with the probability proportional to its number of instances. A server * will be returned from the chosen zone with a given Rule (A Rule is a load balancing strategy, for * example {@link AvailabilityFilteringRule}) For each request, the steps above will be repeated. * That is to say, each zone related load balancing decisions are made at real time with the * up-to-date statistics aiding the choice. * * @author awang * @param <T> */ public class ZoneAwareLoadBalancer<T extends Server> extends DynamicServerListLoadBalancer<T> { private ConcurrentHashMap<String, BaseLoadBalancer> balancers = new ConcurrentHashMap<String, BaseLoadBalancer>(); private static final Logger logger = LoggerFactory.getLogger(ZoneAwareLoadBalancer.class); private volatile DynamicDoubleProperty triggeringLoad; private volatile DynamicDoubleProperty triggeringBlackoutPercentage; private static final DynamicBooleanProperty ENABLED = DynamicPropertyFactory.getInstance() .getBooleanProperty("ZoneAwareNIWSDiscoveryLoadBalancer.enabled", true); void setUpServerList(List<Server> upServerList) { this.upServerList = upServerList; } public ZoneAwareLoadBalancer() { super(); } public ZoneAwareLoadBalancer( IClientConfig clientConfig, IRule rule, IPing ping, ServerList<T> serverList, ServerListFilter<T> filter) { super(clientConfig, rule, ping, serverList, filter); } public ZoneAwareLoadBalancer(IClientConfig niwsClientConfig) { super(niwsClientConfig); } @Override protected void setServerListForZones(Map<String, List<Server>> zoneServersMap) { super.setServerListForZones(zoneServersMap); if (balancers == null) { balancers = new ConcurrentHashMap<String, BaseLoadBalancer>(); } for (Map.Entry<String, List<Server>> entry : zoneServersMap.entrySet()) { String zone = entry.getKey().toLowerCase(); getLoadBalancer(zone).setServersList(entry.getValue()); } // check if there is any zone that no longer has a server // and set the list to empty so that the zone related metrics does not // contain stale data for (Map.Entry<String, BaseLoadBalancer> existingLBEntry : balancers.entrySet()) { if (!zoneServersMap.keySet().contains(existingLBEntry.getKey())) { existingLBEntry.getValue().setServersList(Collections.emptyList()); } } } @Override public Server chooseServer(Object key) { if (!ENABLED.get() || getLoadBalancerStats().getAvailableZones().size() <= 1) { logger.debug("Zone aware logic disabled or there is only one zone"); return super.chooseServer(key); } Server server = null; try { LoadBalancerStats lbStats = getLoadBalancerStats(); Map<String, ZoneSnapshot> zoneSnapshot = ZoneAvoidanceRule.createSnapshot(lbStats); logger.debug("Zone snapshots: {}", zoneSnapshot); if (triggeringLoad == null) { triggeringLoad = DynamicPropertyFactory.getInstance() .getDoubleProperty( "ZoneAwareNIWSDiscoveryLoadBalancer." + this.getName() + ".triggeringLoadPerServerThreshold", 0.2d); } if (triggeringBlackoutPercentage == null) { triggeringBlackoutPercentage = DynamicPropertyFactory.getInstance() .getDoubleProperty( "ZoneAwareNIWSDiscoveryLoadBalancer." + this.getName() + ".avoidZoneWithBlackoutPercetage", 0.99999d); } Set<String> availableZones = ZoneAvoidanceRule.getAvailableZones( zoneSnapshot, triggeringLoad.get(), triggeringBlackoutPercentage.get()); logger.debug("Available zones: {}", availableZones); if (availableZones != null && availableZones.size() < zoneSnapshot.keySet().size()) { String zone = ZoneAvoidanceRule.randomChooseZone(zoneSnapshot, availableZones); logger.debug("Zone chosen: {}", zone); if (zone != null) { BaseLoadBalancer zoneLoadBalancer = getLoadBalancer(zone); server = zoneLoadBalancer.chooseServer(key); } } } catch (Throwable e) { logger.error("Unexpected exception when choosing server using zone aware logic", e); } if (server != null) { return server; } else { logger.debug("Zone avoidance logic is not invoked."); return super.chooseServer(key); } } @VisibleForTesting BaseLoadBalancer getLoadBalancer(String zone) { zone = zone.toLowerCase(); BaseLoadBalancer loadBalancer = balancers.get(zone); if (loadBalancer == null) { // We need to create rule object for load balancer for each zone IRule rule = cloneRule(this.getRule()); loadBalancer = new BaseLoadBalancer(this.getName() + "_" + zone, rule, this.getLoadBalancerStats()); BaseLoadBalancer prev = balancers.putIfAbsent(zone, loadBalancer); if (prev != null) { loadBalancer = prev; } } return loadBalancer; } private IRule cloneRule(IRule toClone) { IRule rule; if (toClone == null) { rule = new AvailabilityFilteringRule(); } else { String ruleClass = toClone.getClass().getName(); try { rule = (IRule) ClientFactory.instantiateInstanceWithClientConfig( ruleClass, this.getClientConfig()); } catch (Exception e) { throw new RuntimeException( "Unexpected exception creating rule for ZoneAwareLoadBalancer", e); } } return rule; } @Override public void setRule(IRule rule) { super.setRule(rule); if (balancers != null) { for (String zone : balancers.keySet()) { balancers.get(zone).setRule(cloneRule(rule)); } } } }
@Override public long getDeltaRetentionTimerIntervalInMs() { return configInstance .getLongProperty(namespace + "deltaRetentionTimerIntervalInMs", (30 * 1000)) .get(); }
/** * A default implementation of eureka server configuration as required by {@link * EurekaServerConfig}. * * <p>The information required for configuring eureka server is provided in a configuration file.The * configuration file is searched for in the classpath with the name specified by the property * <em>eureka.server.props</em> and with the suffix <em>.properties</em>. If the property is not * specified, <em>eureka-server.properties</em> is assumed as the default.The properties that are * looked up uses the <em>namespace</em> passed on to this class. * * <p>If the <em>eureka.environment</em> property is specified, additionally * <em>eureka-server-<eureka.environment>.properties</em> is loaded in addition to * <em>eureka-server.properties</em>. * * @author Karthik Ranganathan */ public class DefaultEurekaServerConfig implements EurekaServerConfig { private static final String ARCHAIUS_DEPLOYMENT_ENVIRONMENT = "archaius.deployment.environment"; private static final String TEST = "test"; private static final String EUREKA_ENVIRONMENT = "eureka.environment"; private static final Logger logger = LoggerFactory.getLogger(DefaultEurekaServerConfig.class); private static final DynamicPropertyFactory configInstance = com.netflix.config.DynamicPropertyFactory.getInstance(); private static final DynamicStringProperty EUREKA_PROPS_FILE = DynamicPropertyFactory.getInstance() .getStringProperty("eureka.server.props", "eureka-server"); private String namespace = "eureka."; public DefaultEurekaServerConfig() { init(); } public DefaultEurekaServerConfig(String namespace) { this.namespace = namespace; init(); } private void init() { String env = ConfigurationManager.getConfigInstance().getString(EUREKA_ENVIRONMENT, TEST); ConfigurationManager.getConfigInstance().setProperty(ARCHAIUS_DEPLOYMENT_ENVIRONMENT, env); String eurekaPropsFile = EUREKA_PROPS_FILE.get(); try { // ConfigurationManager // .loadPropertiesFromResources(eurekaPropsFile); ConfigurationManager.loadCascadedPropertiesFromResources(eurekaPropsFile); } catch (IOException e) { logger.warn( "Cannot find the properties specified : {}. This may be okay if there are other environment specific properties or the configuration is installed with a different mechanism.", eurekaPropsFile); } } /* * (non-Javadoc) * @see com.netflix.eureka.EurekaServerConfig#getAWSAccessId() */ @Override public String getAWSAccessId() { return configInstance.getStringProperty(namespace + "awsAccessId", null).get().trim(); } /* * (non-Javadoc) * @see com.netflix.eureka.EurekaServerConfig#getAWSSecretKey() */ @Override public String getAWSSecretKey() { return configInstance.getStringProperty(namespace + "awsSecretKey", null).get().trim(); } /* * (non-Javadoc) * @see com.netflix.eureka.EurekaServerConfig#getEIPBindRebindRetries() */ @Override public int getEIPBindRebindRetries() { return configInstance.getIntProperty(namespace + "eipBindRebindRetries", 3).get(); } /* * (non-Javadoc) * @see com.netflix.eureka.EurekaServerConfig#getEIPBindingRetryInterval() */ @Override public int getEIPBindingRetryIntervalMs() { return configInstance .getIntProperty(namespace + "eipBindRebindRetryIntervalMs", (5 * 60 * 1000)) .get(); } /* * (non-Javadoc) * @see com.netflix.eureka.EurekaServerConfig#shouldEnableSelfPreservation() */ @Override public boolean shouldEnableSelfPreservation() { return configInstance.getBooleanProperty(namespace + "enableSelfPreservation", true).get(); } /* * (non-Javadoc) * @see com.netflix.eureka.EurekaServerConfig#getPeerEurekaNodesUpdateInterval() */ @Override public int getPeerEurekaNodesUpdateIntervalMs() { return configInstance .getIntProperty(namespace + "peerEurekaNodesUpdateIntervalMs", (10 * 60 * 1000)) .get(); } @Override public int getRenewalThresholdUpdateIntervalMs() { return configInstance .getIntProperty(namespace + "renewalThresholdUpdateIntervalMs", (15 * 60 * 1000)) .get(); } @Override public double getRenewalPercentThreshold() { return configInstance.getDoubleProperty(namespace + "renewalPercentThreshold", 0.85).get(); } @Override public int getNumberOfReplicationRetries() { return configInstance.getIntProperty(namespace + "numberOfReplicationRetries", 5).get(); } @Override public boolean shouldReplicateOnlyIfUP() { return configInstance.getBooleanProperty(namespace + "replicateOnlyIfUP", true).get(); } @Override public int getPeerEurekaStatusRefreshTimeIntervalMs() { return configInstance .getIntProperty(namespace + "peerEurekaStatusRefreshTimeIntervalMs", (30 * 1000)) .get(); } @Override public int getWaitTimeInMsWhenSyncEmpty() { return configInstance .getIntProperty(namespace + "waitTimeInMsWhenSyncEmpty", (1000 * 60 * 5)) .get(); } @Override public int getPeerNodeConnectTimeoutMs() { return configInstance.getIntProperty(namespace + "peerNodeConnectTimeoutMs", 200).get(); } @Override public int getPeerNodeReadTimeoutMs() { return configInstance.getIntProperty(namespace + "peerNodeReadTimeoutMs", 200).get(); } @Override public int getPeerNodeTotalConnections() { return configInstance.getIntProperty(namespace + "peerNodeTotalConnections", 1000).get(); } @Override public int getPeerNodeTotalConnectionsPerHost() { return configInstance.getIntProperty(namespace + "peerNodeTotalConnections", 500).get(); } @Override public int getPeerNodeConnectionIdleTimeoutSeconds() { return configInstance .getIntProperty(namespace + "peerNodeConnectionIdleTimeoutSeconds", 30) .get(); } @Override public boolean shouldRetryIndefinitelyToReplicateStatus() { return configInstance .getBooleanProperty(namespace + "retryIndefinitelyToReplicateStatus", true) .get(); } @Override public long getRetentionTimeInMSInDeltaQueue() { return configInstance .getLongProperty(namespace + "retentionTimeInMSInDeltaQueue", (3 * 60 * 1000)) .get(); } @Override public long getDeltaRetentionTimerIntervalInMs() { return configInstance .getLongProperty(namespace + "deltaRetentionTimerIntervalInMs", (30 * 1000)) .get(); } @Override public long getEvictionIntervalTimerInMs() { return configInstance .getLongProperty(namespace + "evictionIntervalTimerInMs", (60 * 1000)) .get(); } @Override public int getASGQueryTimeoutMs() { return configInstance.getIntProperty(namespace + "asgQueryTimeoutMs", 1000).get(); } @Override public long getASGUpdateIntervalMs() { return configInstance.getIntProperty(namespace + "asgUpdateIntervalMs", (60 * 1000)).get(); } @Override public long getResponseCacheAutoExpirationInSeconds() { return configInstance .getIntProperty(namespace + "responseCacheAutoExpirationInSeconds", 180) .get(); } @Override public long getResponseCacheUpdateIntervalMs() { return configInstance .getIntProperty(namespace + "responseCacheUpdateIntervalMs", (30 * 1000)) .get(); } @Override public boolean shouldDisableDelta() { return configInstance.getBooleanProperty(namespace + "disableDelta", false).get(); } @Override public long getMaxIdleThreadInMinutesAgeForStatusReplication() { return configInstance .getLongProperty(namespace + "maxIdleThreadAgeInMinutesForStatusReplication", 10) .get(); } @Override public int getMinThreadsForStatusReplication() { return configInstance.getIntProperty(namespace + "minThreadsForStatusReplication", 1).get(); } @Override public int getMaxThreadsForStatusReplication() { return configInstance.getIntProperty(namespace + "maxThreadsForStatusReplication", 1).get(); } @Override public int getMaxElementsInStatusReplicationPool() { return configInstance .getIntProperty(namespace + "maxElementsInStatusReplicationPool", 10000) .get(); } @Override public int getMaxElementsInReplicationPool() { return configInstance.getIntProperty(namespace + "maxElementsInReplicationPool", 120).get(); } @Override public long getMaxIdleThreadAgeInMinutesForReplication() { return configInstance .getIntProperty(namespace + "maxIdleThreadAgeInMinutesForReplication", 15) .get(); } @Override public int getMinThreadsForReplication() { return configInstance.getIntProperty(namespace + "minThreadsForReplication", 20).get(); } @Override public int getMaxThreadsForReplication() { return configInstance.getIntProperty(namespace + "maxThreadsForReplication", 60).get(); } @Override public boolean shouldSyncWhenTimestampDiffers() { return configInstance.getBooleanProperty(namespace + "syncWhenTimestampDiffers", true).get(); } }
@Override public int getMaxThreadsForReplication() { return configInstance.getIntProperty(namespace + "maxThreadsForReplication", 60).get(); }
@Override public int getASGQueryTimeoutMs() { return configInstance.getIntProperty(namespace + "asgQueryTimeoutMs", 1000).get(); }
/** * A copy of the InstrumentedHandler from Codahale Metric's library. The current version of the * library does not support the most current Jetty version, in which HttpChannelState.isDispatched() * has been removed. This class will be used until a Metric's library version is released which * supports the Jetty change. */ public class InstrumentedHandler extends HandlerWrapper { private final MetricRegistry metricRegistry; private String name; // the requests handled by this handler, excluding active private Timer requests; // the number of dispatches seen by this handler, excluding active private Timer dispatches; // the number of active requests private Counter activeRequests; // the number of active dispatches private Counter activeDispatches; // the number of requests currently suspended. private Counter activeSuspended; // the number of requests that have been asynchronously dispatched private Meter asyncDispatches; // the number of requests that expired while suspended private Meter asyncTimeouts; private Meter[] responses; private Timer getRequests; private Timer postRequests; private Timer headRequests; private Timer putRequests; private Timer deleteRequests; private Timer optionsRequests; private Timer traceRequests; private Timer connectRequests; private Timer moveRequests; private Timer otherRequests; private AsyncListener listener; private DynamicLongProperty timerReservoirSeconds = DynamicPropertyFactory.getInstance() .getLongProperty("http.metrics.handler.timerReservoirSeconds", 60); /** * Create a new instrumented handler using a given metrics registry. * * @param registry the registry for the metrics */ public InstrumentedHandler(MetricRegistry registry) { this.metricRegistry = registry; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override protected void doStart() throws Exception { super.doStart(); final String prefix = name(getHandler().getClass(), name); this.requests = timer(name(prefix, "requests")); this.dispatches = timer(name(prefix, "dispatches")); this.activeRequests = metricRegistry.counter(name(prefix, "active-requests")); this.activeDispatches = metricRegistry.counter(name(prefix, "active-dispatches")); this.activeSuspended = metricRegistry.counter(name(prefix, "active-suspended")); this.asyncDispatches = metricRegistry.meter(name(prefix, "async-dispatches")); this.asyncTimeouts = metricRegistry.meter(name(prefix, "async-timeouts")); this.responses = new Meter[] { metricRegistry.meter(name(prefix, "1xx-responses")), // 1xx metricRegistry.meter(name(prefix, "2xx-responses")), // 2xx metricRegistry.meter(name(prefix, "3xx-responses")), // 3xx metricRegistry.meter(name(prefix, "4xx-responses")), // 4xx metricRegistry.meter(name(prefix, "5xx-responses")) // 5xx }; this.getRequests = timer(name(prefix, "get-requests")); this.postRequests = timer(name(prefix, "post-requests")); this.headRequests = timer(name(prefix, "head-requests")); this.putRequests = timer(name(prefix, "put-requests")); this.deleteRequests = timer(name(prefix, "delete-requests")); this.optionsRequests = timer(name(prefix, "options-requests")); this.traceRequests = timer(name(prefix, "trace-requests")); this.connectRequests = timer(name(prefix, "connect-requests")); this.moveRequests = timer(name(prefix, "move-requests")); this.otherRequests = timer(name(prefix, "other-requests")); this.listener = new AsyncListener() { @Override public void onTimeout(AsyncEvent event) throws IOException { asyncTimeouts.mark(); } @Override public void onStartAsync(AsyncEvent event) throws IOException { event.getAsyncContext().addListener(this); } @Override public void onError(AsyncEvent event) throws IOException {} @Override public void onComplete(AsyncEvent event) throws IOException { final AsyncContextState state = (AsyncContextState) event.getAsyncContext(); final Request request = (Request) state.getRequest(); updateResponses(request); if (!(state.getHttpChannelState().getState() == State.DISPATCHED)) { activeSuspended.dec(); } } }; } private Timer timer(String name) { Timer timer = metricRegistry.getTimers().get(name); if (timer != null) { return timer; } try { return metricRegistry.register( name, new Timer(new SlidingTimeWindowReservoir(timerReservoirSeconds.get(), TimeUnit.SECONDS))); } catch (IllegalArgumentException e) { // timer already exists. this happens due to race condition. its fine. return metricRegistry.getTimers().get(name); } } @Override public void handle( String path, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) throws IOException, ServletException { activeDispatches.inc(); final long start; final HttpChannelState state = request.getHttpChannelState(); if (state.isInitial()) { // new request activeRequests.inc(); start = request.getTimeStamp(); } else { // resumed request start = System.currentTimeMillis(); activeSuspended.dec(); if (state.getState() == State.DISPATCHED) { asyncDispatches.mark(); } } try { super.handle(path, request, httpRequest, httpResponse); } finally { final long now = System.currentTimeMillis(); final long dispatched = now - start; activeDispatches.dec(); dispatches.update(dispatched, TimeUnit.MILLISECONDS); if (state.isSuspended()) { if (state.isInitial()) { state.addListener(listener); } activeSuspended.inc(); } else if (state.isInitial()) { requests.update(dispatched, TimeUnit.MILLISECONDS); updateResponses(request); } // else onCompletion will handle it. } } private Timer requestTimer(String method) { final HttpMethod m = HttpMethod.fromString(method); if (m == null) { return otherRequests; } else { switch (m) { case GET: return getRequests; case POST: return postRequests; case PUT: return putRequests; case HEAD: return headRequests; case DELETE: return deleteRequests; case OPTIONS: return optionsRequests; case TRACE: return traceRequests; case CONNECT: return connectRequests; case MOVE: return moveRequests; default: return otherRequests; } } } private void updateResponses(Request request) { final int response = request.getResponse().getStatus() / 100; if (response >= 1 && response <= 5) { responses[response - 1].mark(); } activeRequests.dec(); final long elapsedTime = System.currentTimeMillis() - request.getTimeStamp(); requests.update(elapsedTime, TimeUnit.MILLISECONDS); requestTimer(request.getMethod()).update(elapsedTime, TimeUnit.MILLISECONDS); } }
@Override public boolean shouldSyncWhenTimestampDiffers() { return configInstance.getBooleanProperty(namespace + "syncWhenTimestampDiffers", true).get(); }