diff --git a/eureka-client/runservice.sh b/eureka-client/runservice.sh deleted file mode 100755 index 06eb5e296..000000000 --- a/eureka-client/runservice.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/bash -#Copy all libraries -TEST_CLASSPATH= -for i in testlibs/WEB-INF/lib/* -do - if [ "$TEST_CLASSPATH" = "" ] ; then - TEST_CLASSPATH=$i - fi - TEST_CLASSPATH=$TEST_CLASSPATH:$i -done -TEST_CLASSPATH=$TEST_CLASSPATH:build/classes/main:conf/sampleservice - -echo CLASSPATH:$TEST_CLASSPATH -java -Deureka.region=default -Deureka.environment=test -Deureka.client.props=sample-eureka-service -cp $TEST_CLASSPATH com.netflix.eureka.SampleEurekaService - diff --git a/eureka-core/src/main/java/com/netflix/discovery/CurrentRequestVersion.java b/eureka-core/src/main/java/com/netflix/discovery/CurrentRequestVersion.java deleted file mode 100644 index 37a814b3d..000000000 --- a/eureka-core/src/main/java/com/netflix/discovery/CurrentRequestVersion.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2012 Netflix, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.netflix.discovery; - - -/** - * A thread-scoped value that holds the "current {@link Version}" for the - * request. - * - *

This is not intended as a general mechanism for passing data. - * Rather it is here to support those cases where someplace deep in - * a library we need to know about the context of the request that - * initially triggered the current request.

- * - * @author Karthik Ranganathan, Greg Kim - */ -public final class CurrentRequestVersion { - - private static final ThreadLocal CURRENT_REQ_VERSION = - new ThreadLocal(); - - private CurrentRequestVersion() { } - - /** - * Gets the current {@link Version} - * Will return null if no current version has been set. - */ - public static Version get() { - return CURRENT_REQ_VERSION.get(); - } - - /** - * Sets the current {@link Version} - */ - public static void set(Version version) { - CURRENT_REQ_VERSION.set(version); - } - -} \ No newline at end of file diff --git a/eureka-core/src/main/java/com/netflix/discovery/DefaultEurekaServerConfig.java b/eureka-core/src/main/java/com/netflix/discovery/DefaultEurekaServerConfig.java deleted file mode 100644 index a65c95ba7..000000000 --- a/eureka-core/src/main/java/com/netflix/discovery/DefaultEurekaServerConfig.java +++ /dev/null @@ -1,329 +0,0 @@ -/* - * Copyright 2012 Netflix, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.netflix.discovery; - -import java.io.IOException; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.netflix.config.ConfigurationManager; -import com.netflix.config.DynamicPropertyFactory; -import com.netflix.config.DynamicStringProperty; - -/** - * - * A default implementation of eureka server configuration as required by - * {@link EurekaServerConfig}. - * - *

- * 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 eureka.server.props and with - * the suffix .properties. If the property is not specified, - * eureka-server.properties is assumed as the default.The properties - * that are looked up uses the namespace passed on to this class. - *

- * - *

- * If the eureka.environment property is specified, additionally - * eureka-server-.properties is loaded in addition - * to eureka-server.properties. - *

- * - * @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.discovery.EurekaServerConfig#getAWSAccessId() - */ - @Override - public String getAWSAccessId() { - return configInstance - .getStringProperty(namespace + "awsAccessId", null).get() - .trim(); - } - - /* - * (non-Javadoc) - * @see com.netflix.discovery.EurekaServerConfig#getAWSSecretKey() - */ - @Override - public String getAWSSecretKey() { - return configInstance - .getStringProperty(namespace + "awsSecretKey", null).get() - .trim(); - } - - /* - * (non-Javadoc) - * @see com.netflix.discovery.EurekaServerConfig#getEIPBindRebindRetries() - */ - @Override - public int getEIPBindRebindRetries() { - return configInstance - .getIntProperty(namespace + "eipBindRebindRetries", 3).get(); - - } - - /* - * (non-Javadoc) - * @see com.netflix.discovery.EurekaServerConfig#getEIPBindingRetryInterval() - */ - @Override - public int getEIPBindingRetryIntervalMs() { - return configInstance - .getIntProperty(namespace + "eipBindRebindRetryIntervalMs", (5 * 60 * 1000)).get(); - } - - /* - * (non-Javadoc) - * @see com.netflix.discovery.EurekaServerConfig#shouldEnableSelfPreservation() - */ - @Override - public boolean shouldEnableSelfPreservation() { - return configInstance - .getBooleanProperty(namespace + "enableSelfPreservation", true).get(); - } - - /* - * (non-Javadoc) - * @see com.netflix.discovery.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(); - } - -} diff --git a/eureka-core/src/main/java/com/netflix/discovery/EurekaBootStrap.java b/eureka-core/src/main/java/com/netflix/discovery/EurekaBootStrap.java deleted file mode 100644 index 2b95373c1..000000000 --- a/eureka-core/src/main/java/com/netflix/discovery/EurekaBootStrap.java +++ /dev/null @@ -1,262 +0,0 @@ -/* - * Copyright 2012 Netflix, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.netflix.discovery; - -import java.util.Date; -import java.util.Timer; -import java.util.TimerTask; - -import javax.servlet.ServletContextEvent; -import javax.servlet.ServletContextListener; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.netflix.appinfo.ApplicationInfoManager; -import com.netflix.appinfo.CloudInstanceConfig; -import com.netflix.appinfo.DataCenterInfo.Name; -import com.netflix.appinfo.EurekaInstanceConfig; -import com.netflix.appinfo.InstanceInfo; -import com.netflix.appinfo.MyDataCenterInstanceConfig; -import com.netflix.config.ConfigurationManager; -import com.netflix.discovery.cluster.PeerEurekaNode; -import com.netflix.discovery.converters.JsonXStream; -import com.netflix.discovery.converters.XmlXStream; -import com.netflix.discovery.util.EIPManager; -import com.netflix.discovery.util.EurekaMonitors; -import com.thoughtworks.xstream.XStream; - -/** - * The class that kick starts the eureka server. - * - *

- * The eureka server is configured by using the configuration - * {@link EurekaServerConfig} specified by eureka.server.props in the - * classpath.The eureka client component is also initialized by using the - * configuration {@link EurekaInstanceConfig} specified by - * eureka.client.props. If the server runs in the AWS cloud, the eurea - * server binds it to the elastic ip as specified. - *

- * - * @author Karthik Ranganathan, Greg Kim - * - */ -public class EurekaBootStrap implements ServletContextListener { - private static final String TEST = "test"; - - private static final String ARCHAIUS_DEPLOYMENT_ENVIRONMENT = "archaius.deployment.environment"; - - private static final String EUREKA_ENVIRONMENT = "eureka.environment"; - - private static final String CLOUD = "cloud"; - - private static final String ARCHAIUS_DEPLOYMENT_DATACENTER = "archaius.deployment.datacenter"; - - private static final String EUREKA_DATACENTER = "eureka.datacenter"; - - private static final Logger logger = LoggerFactory - .getLogger(EurekaBootStrap.class); - - private static final int EIP_BIND_SLEEP_TIME_MS = 1000; - private static final Timer timer = new Timer("Eureka-EIPBinder", true); - - /* - * (non-Javadoc) - * - * @see - * javax.servlet.ServletContextListener#contextInitialized(javax.servlet - * .ServletContextEvent) - */ - public void contextInitialized(ServletContextEvent event) { - try { - initEurekaEnvironment(); - - // For backward compatibility - JsonXStream.getInstance().registerConverter( - new V1AwareInstanceInfoConverter(), - XStream.PRIORITY_VERY_HIGH); - XmlXStream.getInstance().registerConverter( - new V1AwareInstanceInfoConverter(), - XStream.PRIORITY_VERY_HIGH); - InstanceInfo info = ApplicationInfoManager.getInstance().getInfo(); - - PeerAwareInstanceRegistry registry = PeerAwareInstanceRegistry - .getInstance(); - - // Copy registry from neighboring eureka node - registry.syncUp(); - - // Only in AWS, enable the binding functionality - if (Name.Amazon.equals(info.getDataCenterInfo().getName())) { - handleEIPbinding(); - } - // Register all monitoring statistics. - EurekaMonitors.registerAllStats(); - - for (PeerEurekaNode node : registry.getReplicaNodes()) { - logger.info("Replica node URL: " + node.getServiceUrl()); - } - - } catch (Throwable e) { - throw new RuntimeException("Cannot bootstrap eureka server :", e); - } - } - - /** - * Users can override to initialize the environment themselves. - */ - protected void initEurekaEnvironment() { - logger.info("Setting the eureka configuration.."); - EurekaServerConfig eurekaServerConfig = new DefaultEurekaServerConfig(); - EurekaServerConfigurationManager.getInstance().setConfiguration( - eurekaServerConfig); - - String dataCenter = ConfigurationManager.getConfigInstance() - .getString(EUREKA_DATACENTER); - if (dataCenter == null) { - logger.info("Eureka data center value eureka.datacenter is not set, defaulting to cloud"); - ConfigurationManager.getConfigInstance().setProperty( - ARCHAIUS_DEPLOYMENT_DATACENTER, CLOUD); - } else { - ConfigurationManager.getConfigInstance().setProperty( - ARCHAIUS_DEPLOYMENT_DATACENTER, dataCenter); - } - String environment = ConfigurationManager.getConfigInstance() - .getString(EUREKA_ENVIRONMENT); - if (environment == null) { - ConfigurationManager.getConfigInstance().setProperty( - ARCHAIUS_DEPLOYMENT_ENVIRONMENT, TEST); - logger.info("Eureka environment value eureka.environment is not set, defaulting to test"); - } - EurekaInstanceConfig config; - if (CLOUD.equals(ConfigurationManager.getDeploymentContext() - .getDeploymentDatacenter())) { - config = new CloudInstanceConfig(); - } else { - config = new MyDataCenterInstanceConfig(); - } - logger.info("Initializing the eureka client..."); - - DiscoveryManager.getInstance().initComponent(config, - new DefaultEurekaClientConfig()); - } - - /* - * (non-Javadoc) - * - * @see javax.servlet.ServletContextListener#contextDestroyed(javax.servlet. - * ServletContextEvent) - */ - public void contextDestroyed(ServletContextEvent event) { - try { - logger.info(new Date().toString() - + " Shutting down Discovery service..."); - InstanceInfo info = ApplicationInfoManager.getInstance().getInfo(); - // Unregister all MBeans associated w/ DSCounters - EurekaMonitors.shutdown(); - for (int i = 0; i < EurekaServerConfigurationManager.getInstance() - .getConfiguration().getEIPBindRebindRetries(); i++) { - try { - if (Name.Amazon.equals(info.getDataCenterInfo().getName())) { - EIPManager.getInstance().unbindEIP(); - } - break; - } catch (Throwable e) { - logger.warn("Cannot unbind the EIP from the instance"); - Thread.sleep(1000); - continue; - } - } - PeerAwareInstanceRegistry.getInstance().shutdown(); - destoryEurekaEnvironment(); - - } catch (Throwable e) { - logger.error("Error shutting down eureka", e); - } - logger.info(new Date().toString() - + " Eureka Service is now shutdown..."); - } - - /** - * Users can override to clean up the environment themselves. - */ - protected void destoryEurekaEnvironment() { - - } - - /** - * Handles EIP binding process in AWS Cloud. - * - * @throws InterruptedException - */ - private void handleEIPbinding() - throws InterruptedException { - EurekaServerConfig eurekaServerConfig = EurekaServerConfigurationManager.getInstance().getConfiguration(); - int retries = eurekaServerConfig.getEIPBindRebindRetries(); - // Bind to EIP if needed - for (int i = 0; i < retries; i++) { - if (bindEIP()) { - break; - } - } - // Schedule a timer which periodically checks for EIP binding. - scheduleEIPBindTask(eurekaServerConfig); - } - - /** - * Schedules a EIP binding timer task which constantly polls for EIP in the - * same zone and binds it to itself.If the EIP is taken away for some - * reason, this task tries to get the EIP back. Hence it is advised to take - * one EIP assignment per instance in a zone. - * - * @param eurekaServerConfig - * the Eureka Server Configuration. - */ - private void scheduleEIPBindTask( - EurekaServerConfig eurekaServerConfig) { - timer.schedule(new TimerTask() { - - @Override - public void run() { - try { - bindEIP(); - } catch (Throwable ignore) { - - } - } - }, eurekaServerConfig.getEIPBindingRetryIntervalMs(), - eurekaServerConfig.getEIPBindingRetryIntervalMs()); - } - - /** - * Binds the EIP if it is not already bound. - * - * @return - * @throws InterruptedException - */ - private boolean bindEIP() throws InterruptedException { - try { - EIPManager.getInstance().bindToEIP(); - return true; - } catch (Throwable e) { - logger.error("Cannot bind to EIP", e); - Thread.sleep(EIP_BIND_SLEEP_TIME_MS); - return false; - } - } - -} diff --git a/eureka-core/src/main/java/com/netflix/discovery/EurekaServerConfig.java b/eureka-core/src/main/java/com/netflix/discovery/EurekaServerConfig.java deleted file mode 100644 index 5a1542156..000000000 --- a/eureka-core/src/main/java/com/netflix/discovery/EurekaServerConfig.java +++ /dev/null @@ -1,357 +0,0 @@ -/* - * Copyright 2012 Netflix, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.netflix.discovery; - -import com.netflix.appinfo.InstanceInfo.InstanceStatus; - -/** - * Configuration information required by the eureka server to operate. - * - *

- * Most of the required information is provided by the default configuration - * {@link DefaultServerConfig}. - * - * Note that all configurations are not effective at runtime unless and - * otherwise specified. - *

- * - * @author Karthik Ranganathan - * - */ -public interface EurekaServerConfig { - - /** - * Gets the AWS Access Id. This is primarily used for - * Elastic IP Biding. The access id should be provided with - * appropriate AWS permissions to bind the EIP. - * - * @return - */ - String getAWSAccessId(); - - /** - * Gets the AWS Secret Key. This is primarily used for - * Elastic IP Biding. The access id should be provided with - * appropriate AWS permissions to bind the EIP. - * - * @return - */ - String getAWSSecretKey(); - - /** - * Gets the number of times the server should try to bind to the candidate - * EIP. - * - * @return the number of times the server should try to bind to the - * candidate EIP. - */ - int getEIPBindRebindRetries(); - - /** - * Gets the interval with which the server should check if the EIP is bound - * and should try to bind in the case if it is already not bound. - * - * @return the time in milliseconds. - */ - int getEIPBindingRetryIntervalMs(); - - /** - * Checks to see if the eureka server is enabled for self preservation. - * - *

- * When enabled, the server keeps track of the number of renewals - * it should receive from the server. Any time, the number of renewals drops - * below the threshold percentage as defined by - * {@link #getRenewalPercentThreshold()}, the server turns off expirations - * to avert danger.This will help the server in maintaining the registry - * information in case of network problems between client and the server. - * - * @return true to enable self preservation, false otherwise. - */ - boolean shouldEnableSelfPreservation(); - - /** - * The minimum percentage of renewals that is expected from the clients in - * the period specified by {@link #getRenewalThresholdUpdateIntervalMs()}. If - * the renewals drop below the threshold, the expirations are disabled if - * the {@link #shouldEnableSelfPreservation()} is enabled. - * - * @return value between 0 and 1 indicating the percentage. For example, - * 85% will be specified as 0.85. - */ - double getRenewalPercentThreshold(); - - /** - * The interval with which the threshold as specified in - * {@link #getRenewalPercentThreshold()} needs to be updated. - * - * @return time in milliseconds indicating the interval. - */ - int getRenewalThresholdUpdateIntervalMs(); - - /** - * The interval with which the information about the changes in peer eureka - * nodes is updated. The user can use the DNS mechanism or dynamic - * configuration provided by {@link https://github.com/Netflix/archaius} to - * change the information dynamically. - * - * @return timer in milliseconds indicating the interval. - */ - int getPeerEurekaNodesUpdateIntervalMs(); - - /** - * Get the number of times the replication events should be retried with - * peers. - * - * @return the number of retries. - */ - int getNumberOfReplicationRetries(); - - /** - * Checks whether the replication events should only be sent to peer eureka - * nodes if their status is {@link InstanceStatus#UP} in the instance's - * {@link InstanceRegistry}. - * - *

- * This check will avoid unnecessary connection attempts to peer eureka - * nodes. The connection attempts for a non existent instance can build up - * file descriptors in an AWS environment because of the way the AWS - * firewall works. - *

- * - * @return true to replicate if the peer node's status is - * {@link InstanceStatus#UP}, false otherwise. - */ - boolean shouldReplicateOnlyIfUP(); - - /** - * Gets the interval with which the status information about peer nodes is - * updated. - * - * @return time in milliseconds indicating the interval. - */ - int getPeerEurekaStatusRefreshTimeIntervalMs(); - - /** - * Gets the time to wait when the eureka server starts up unable to get - * instances from peer nodes. It is better not to start serving rightaway - * during these scenarios as the information that is stored in the registry - * may not be complete. - * - * When the instance registry starts up empty, it builds over time when the - * clients start to send heartbeats and the server requests the clients for - * registration information. - * - * @return time in milliseconds. - */ - int getWaitTimeInMsWhenSyncEmpty(); - - /** - * Gets the timeout value for connecting to peer eureka nodes for - * replication. - * - * @return timeout value in milliseconds. - */ - int getPeerNodeConnectTimeoutMs(); - - /** - * Gets the timeout value for reading information from peer eureka nodes for - * replication. - * - * @return timeout value in milliseconds. - */ - int getPeerNodeReadTimeoutMs(); - - /** - * Gets the total number of HTTP connections allowed to peer eureka - * nodes for replication. - * - * @return total number of allowed HTTP connections. - */ - int getPeerNodeTotalConnections(); - - /** - * Gets the total number of HTTP connections allowed to a - * particular peer eureka node for replication. - * - * @return total number of allowed HTTP connections for a peer - * node. - */ - int getPeerNodeTotalConnectionsPerHost(); - - /** - * Gets the idle time after which the HTTP connection should be - * cleaned up. - * - * @return idle time in seconds. - */ - int getPeerNodeConnectionIdleTimeoutSeconds(); - - /** - * Check to see if the {@link InstanceStatus} status updates should be - * retried indefinitely in case of network problems. - * - *

- * This is specially important if the status is updated by the external - * process. - *

- * - * @return true, to retry indefinitely, false otherwise. - */ - boolean shouldRetryIndefinitelyToReplicateStatus(); - - /** - * Get the time for which the delta information should be cached for the - * clients to retrieve the value without missing it. - * - * @return time in milliseconds - */ - long getRetentionTimeInMSInDeltaQueue(); - - /** - * Get the time interval with which the clean up task should wake up and - * check for expired delta information. - * - * @return time in milliseconds. - */ - long getDeltaRetentionTimerIntervalInMs(); - - /** - * Get the time interval with which the task that expires instances should - * wake up and run. - * - * @return time in milliseconds. - */ - long getEvictionIntervalTimerInMs(); - - /** - * Get the timeout value for querying the AWS for ASG - * information. - * - * @return timeout value in milliseconds. - */ - int getASGQueryTimeoutMs(); - - /** - * Get the time interval with which the ASG information must be - * queried from AWS - * - * @return time in milliseconds. - */ - long getASGUpdateIntervalMs(); - - /** - * Gets the time for which the registry payload should be kept in the cache - * if it is not invalidated by change events. - * - * @return time in seconds. - */ - long getResponseCacheAutoExpirationInSeconds(); - - /** - * Gets the time interval with which the payload cache of the client should - * be updated. - * - * @return time in milliseconds. - */ - long getResponseCacheUpdateIntervalMs(); - - /** - * Checks to see if the delta information can be served to client or not. - * - * @return true if the delta information is allowed to be served, false - * otherwise. - */ - boolean shouldDisableDelta(); - - /** - * Get the idle time for which the status replication threads can stay - * alive. - * - * @return time in minutes. - */ - long getMaxIdleThreadInMinutesAgeForStatusReplication(); - - /** - * Get the minimum number of threads to be used for status replication. - * - * @return minimum number of threads to be used for status replication. - */ - int getMinThreadsForStatusReplication(); - - /** - * Get the maximum number of threads to be used for status replication. - * - * @return maximum number of threads to be used for status replication. - */ - int getMaxThreadsForStatusReplication(); - - /** - * Get the maximum number of replication events that can be allowed to back - * up in the status replication pool. - *

- * Depending on the memory allowed, timeout and the replication traffic, - * this value can vary. - *

- * - * @return the maximum number of replication events that can be allowed to - * back up. - */ - int getMaxElementsInStatusReplicationPool(); - - /** - * Get the maximum number of replication events that can be allowed to back - * up in the replication pool. This replication pool is responsible for all - * events except status updates. - *

- * Depending on the memory allowed, timeout and the replication traffic, - * this value can vary. - *

- * - * @return the maximum number of replication events that can be allowed to - * back up. - */ - int getMaxElementsInReplicationPool(); - - /** - * Get the idle time for which the replication threads can stay alive. - * - * @return time in minutes. - */ - long getMaxIdleThreadAgeInMinutesForReplication(); - - /** - * Get the minimum number of threads to be used for replication. - * - * @return minimum number of threads to be used for replication. - */ - int getMinThreadsForReplication(); - - /** - * Get the maximum number of threads to be used for replication. - * - * @return maximum number of threads to be used for replication. - */ - int getMaxThreadsForReplication(); - - /** - * Checks whether to synchronize instances when timestamp differs. - * - * @return true, to synchronize, false otherwise. - */ - boolean shouldSyncWhenTimestampDiffers(); -} diff --git a/eureka-core/src/main/java/com/netflix/discovery/EurekaServerConfigurationManager.java b/eureka-core/src/main/java/com/netflix/discovery/EurekaServerConfigurationManager.java deleted file mode 100644 index 82fe044e3..000000000 --- a/eureka-core/src/main/java/com/netflix/discovery/EurekaServerConfigurationManager.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2012 Netflix, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.netflix.discovery; - -/** - * - * The class that caches the configuration of the instance of - * {@link EurekaServerConfig} that the server started with. - * - * @author Karthik Ranganathan. - * - */ -public class EurekaServerConfigurationManager { - private EurekaServerConfig config; - private static final EurekaServerConfigurationManager instance = new EurekaServerConfigurationManager(); - - private EurekaServerConfigurationManager() { - } - - public static EurekaServerConfigurationManager getInstance() { - return instance; - } - - public void setConfiguration(EurekaServerConfig config) { - this.config = config; - } - - public EurekaServerConfig getConfiguration() { - return this.config; - } -} diff --git a/eureka-core/src/main/java/com/netflix/discovery/InstanceRegistry.java b/eureka-core/src/main/java/com/netflix/discovery/InstanceRegistry.java deleted file mode 100644 index 372230ad3..000000000 --- a/eureka-core/src/main/java/com/netflix/discovery/InstanceRegistry.java +++ /dev/null @@ -1,780 +0,0 @@ -/* - * Copyright 2012 Netflix, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.netflix.discovery; - -import static com.netflix.discovery.util.EurekaMonitors.CANCEL; -import static com.netflix.discovery.util.EurekaMonitors.CANCEL_NOT_FOUND; -import static com.netflix.discovery.util.EurekaMonitors.EXPIRED; -import static com.netflix.discovery.util.EurekaMonitors.GET_ALL_CACHE_MISS; -import static com.netflix.discovery.util.EurekaMonitors.GET_ALL_CACHE_MISS_DELTA; -import static com.netflix.discovery.util.EurekaMonitors.REGISTER; -import static com.netflix.discovery.util.EurekaMonitors.RENEW; -import static com.netflix.discovery.util.EurekaMonitors.RENEW_NOT_FOUND; -import static com.netflix.discovery.util.EurekaMonitors.STATUS_UPDATE; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Timer; -import java.util.TimerTask; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantReadWriteLock; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.common.cache.CacheBuilder; -import com.netflix.appinfo.InstanceInfo; -import com.netflix.appinfo.InstanceInfo.ActionType; -import com.netflix.appinfo.InstanceInfo.InstanceStatus; -import com.netflix.appinfo.LeaseInfo; -import com.netflix.discovery.lease.Lease; -import com.netflix.discovery.lease.LeaseManager; -import com.netflix.discovery.resources.ResponseCache; -import com.netflix.discovery.shared.Application; -import com.netflix.discovery.shared.Applications; -import com.netflix.discovery.shared.LookupService; -import com.netflix.discovery.shared.Pair; -import com.netflix.discovery.util.AwsAsgUtil; -import com.netflix.discovery.util.MeasuredRate; -import com.netflix.servo.annotations.DataSourceType; -import com.netflix.servo.monitor.Monitors; - -/** - * Handles all registry requests from eureka clients. - * - *

- * Primary operations that are performed are the - * Registers,Renewals,Cancels,Expirations and Status Changes. The - * registry also stores only the delta operations - *

- * - * @author Karthik Ranganathan - * - */ -public abstract class InstanceRegistry implements LeaseManager, -LookupService { - - private static final Logger logger = LoggerFactory - .getLogger(InstanceRegistry.class); - private static final EurekaServerConfig eurekaConfig = EurekaServerConfigurationManager - .getInstance().getConfiguration(); - private final ConcurrentHashMap>> _registry = new ConcurrentHashMap>>(); - private Timer evictionTimer = new Timer("Eureka-EvictionTimer", true); - private volatile MeasuredRate renewsLastMin; - protected ConcurrentMap overriddenInstanceStatusMap = CacheBuilder - .newBuilder().initialCapacity(500) - .expireAfterAccess(5, TimeUnit.MINUTES) - . build().asMap(); - - // CircularQueues here for debugging/statistics purposes only - private CircularQueue> recentRegisteredQueue; - private CircularQueue> recentCanceledQueue; - private Timer deltaRetentionTimer = new Timer("Eureka-DeltaRetentionTimer", - true); - private ConcurrentLinkedQueue recentlyChangedQueue = new ConcurrentLinkedQueue(); - private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock(); - private final Lock read = readWriteLock.readLock(); - private final Lock write = readWriteLock.writeLock(); - - protected InstanceRegistry() { - - recentCanceledQueue = new CircularQueue>(1000); - recentRegisteredQueue = new CircularQueue>(1000); - deltaRetentionTimer.schedule(getDeltaRetentionTask(), - eurekaConfig.getDeltaRetentionTimerIntervalInMs(), - eurekaConfig.getDeltaRetentionTimerIntervalInMs()); - - } - - /* - * (non-Javadoc) - * - * @see com.netflix.discovery.lease.LeaseManager#register(java.lang.Object, - * int, long, boolean) - */ - public void register(InstanceInfo r, int leaseDuration, - boolean isReplication) { - try { - read.lock(); - Map> gMap = _registry.get(r - .getAppName()); - REGISTER.increment(isReplication); - if (gMap == null) { - final ConcurrentHashMap> gNewMap = new ConcurrentHashMap>(); - gMap = _registry.putIfAbsent(r.getAppName(), gNewMap); - if (gMap == null) - gMap = gNewMap; - } - Lease existingLease = gMap.get(r.getId()); - Lease lease = new Lease(r, - leaseDuration); - gMap.put(r.getId(), lease); - synchronized (recentRegisteredQueue) { - recentRegisteredQueue.add(new Pair(Long - .valueOf(System.currentTimeMillis()), r.getAppName() - + "(" + r.getId() + ")")); - } - // This is where the initial state transfer of overridden status - // happens - if (!InstanceStatus.UNKNOWN.equals(r.getOverriddenStatus())) { - logger.debug( - "Found overridden status {} for instance {}. Adding to the instance map", - r.getOverriddenStatus(), r.getId()); - if (!overriddenInstanceStatusMap.containsKey(r.getId())) { - logger.debug( - "Not found overridden id {} and hence adding it", - r.getId()); - overriddenInstanceStatusMap.put(r.getId(), - r.getOverriddenStatus()); - } - } - // Set the status based on the overridden status rules - r.setStatusWithoutDirty(getOverriddenInstanceStatus(r, existingLease, - isReplication)); - - if (r != null) { - r.setActionType(ActionType.ADDED); - recentlyChangedQueue.add(new RecentlyChangedItem(lease)); - r.setLastUpdatedTimestamp(); - } - invalidateCache(r.getAppName()); - logger.debug("Registered instance id {} with status {}", r.getId(), - r.getStatus().toString()); - logger.debug("DS: Registry: registered " + r.getAppName() + " - " - + r.getId()); - } finally { - read.unlock(); - } - } - - /** - * Cancels the registration of an instance. - * - *

- * This is normally invoked by a client when it shuts down informing the - * server to remove the instance from traffic. - *

- * - * @param appName - * the application name of the application. - * @param id - * the unique identifier of the instance. - * @param isReplication - * true if this is a replication event from other nodes, false - * otherwise. - * @return true if the instance was removed from the - * {@link InstanceRegistry} successfully, false otherwise. - */ - public boolean cancel(String appName, String id, boolean isReplication) { - try { - read.lock(); - CANCEL.increment(isReplication); - Map> gMap = _registry.get(appName); - Lease leaseToCancel = null; - if (gMap != null) { - leaseToCancel = gMap.remove(id); - } - synchronized (recentCanceledQueue) { - recentCanceledQueue.add(new Pair(Long - .valueOf(System.currentTimeMillis()), appName + "(" - + id + ")")); - } - InstanceStatus instanceStatus = overriddenInstanceStatusMap - .remove(id); - if (instanceStatus != null) { - logger.debug( - "Removed instance id {} from the overridden map which has value {}", - id, instanceStatus.name()); - } - if (leaseToCancel == null) { - CANCEL_NOT_FOUND.increment(isReplication); - logger.warn("DS: Registry: cancel failed because Lease is not registered for: " - + appName + ":" + id); - return false; - } else { - leaseToCancel.cancel(); - InstanceInfo instanceInfo = leaseToCancel.getHolder(); - if (instanceInfo != null) { - instanceInfo.setActionType(ActionType.DELETED); - recentlyChangedQueue.add(new RecentlyChangedItem( - leaseToCancel)); - instanceInfo.setLastUpdatedTimestamp(); - } - invalidateCache(appName); - logger.debug("DS: Registry: canceled lease: " + appName + " - " - + id); - return true; - } - } finally { - read.unlock(); - } - } - - /* - * (non-Javadoc) - * - * @see com.netflix.discovery.lease.LeaseManager#renew(java.lang.String, - * java.lang.String, long, boolean) - */ - public boolean renew(String appName, String id, boolean isReplication) { - RENEW.increment(isReplication); - Map> gMap = _registry.get(appName); - Lease leaseToRenew = null; - if (gMap != null) { - leaseToRenew = gMap.get(id); - } - if (leaseToRenew == null) { - RENEW_NOT_FOUND.increment(isReplication); - logger.warn("DS: Registry: lease doesn't exist, registering resource: " - + appName + " - " + id); - return false; - } else { - InstanceInfo instanceInfo = leaseToRenew.getHolder(); - if (instanceInfo != null) { - // touchASGCache(instanceInfo.getASGName()); - InstanceStatus overriddenInstanceStatus = this - .getOverriddenInstanceStatus(instanceInfo, - leaseToRenew, isReplication); - // InstanceStatus overriddenInstanceStatus = - // instanceInfo.getStatus(); - if ((!isReplication) - && (!instanceInfo.getStatus().equals( - overriddenInstanceStatus))) { - Object[] args = { instanceInfo.getStatus().name(), - instanceInfo.getOverriddenStatus().name(), - instanceInfo.getId() }; - logger.debug( - "The overridden instance status {} is different from instance status {] for instance {}. Hence setting the status to overriddentstatus", - args); - instanceInfo.setStatus(overriddenInstanceStatus); - } - } - renewsLastMin.increment(); - leaseToRenew.renew(); - return true; - } - } - - /** - * Stores overridden status if it is not already there. This happens during - * a reconciliation process during renewal requests. - * - * @param id - * the unique identifier of the instance. - * @param overriddenStatus - * Overridden status if any. - */ - public void storeOverriddenStatusIfRequired(String id, - InstanceStatus overriddenStatus) { - InstanceStatus instanceStatus = overriddenInstanceStatusMap.get(id); - if ((instanceStatus == null) - || (!overriddenStatus.equals(instanceStatus))) { - // We might not have the overridden status if the server got - // restarted -this will help us maintain the overridden state - // from the replica - logger.debug( - "Adding overridden status for instance id {} and the value is {}", - id, overriddenStatus.name()); - overriddenInstanceStatusMap.put(id, overriddenStatus); - } - } - - /** - * Updates the status of an instance. Normally happens to put an instance - * between {@link InstanceStatus#OUT_OF_SERVICE} and - * {@link InstanceStatus#UP} to put the instance in and out of traffic. - * - * @param appName - * the application name of the instance. - * @param id - * the unique identifier of the instance. - * @param newStatus - * the new {@link InstanceStatus}. - * @param isReplication - * true if this is a replication event from other nodes, false - * otherwise. - * @return true if the status was successfully updated, false otherwise. - */ - public boolean statusUpdate(String appName, String id, - InstanceStatus newStatus, boolean isReplication) { - - try { - read.lock(); - STATUS_UPDATE.increment(isReplication); - Map> gMap = _registry.get(appName); - Lease lease = null; - if (gMap != null) { - lease = gMap.get(id); - } - if (lease == null) { - return false; - } else { - lease.renew(); - InstanceInfo info = lease.getHolder(); - if ((info != null) && !(info.getStatus().equals(newStatus))) { - // This is NAC overriden status - overriddenInstanceStatusMap.put(id, newStatus); - // Set it for transfer of overridden status to replica on - // replica start up - info.setOverriddenStatus(newStatus); - info.setStatus(newStatus); - if (info != null) { - info.setActionType(ActionType.MODIFIED); - recentlyChangedQueue - .add(new RecentlyChangedItem(lease)); - info.setLastUpdatedTimestamp(); - } - invalidateCache(appName); - } - return true; - } - } finally { - read.unlock(); - } - } - - /* - * (non-Javadoc) - * - * @see com.netflix.discovery.lease.LeaseManager#evict() - */ - public void evict() { - - if (!isLeaseExpirationEnabled()) { - logger.debug("DS: lease expiration is currently disabled."); - return; - } - logger.debug("Running the evict task"); - for (Iterator>>> iter = _registry - .entrySet().iterator(); iter.hasNext();) { - Entry>> groupEntry = iter - .next(); - - Map> leaseMap = groupEntry.getValue(); - if (leaseMap != null) { - for (Iterator>> subIter = leaseMap - .entrySet().iterator(); subIter.hasNext();) { - Entry> leaseEntry = subIter - .next(); - Lease lease = leaseEntry.getValue(); - if (lease.isExpired() && lease.getHolder() != null) { - String appName = lease.getHolder().getAppName(); - String id = lease.getHolder().getId(); - EXPIRED.increment(); - logger.warn("DS: Registry: expired lease for " - + appName + " - " + id); - cancel(appName, id, false); - } - } - } - } - } - - /* - * (non-Javadoc) - * - * @see - * com.netflix.discovery.shared.LookupService#getApplication(java.lang.String - * ) - */ - public Application getApplication(String appName) { - Application app = null; - - Map> leaseMap = _registry.get(appName); - - if (leaseMap != null && leaseMap.size() > 0) { - for (Iterator>> iter = leaseMap - .entrySet().iterator(); iter.hasNext();) { - Entry> entry = iter.next(); - - if (isLeaseExpirationEnabled() && entry.getValue().isExpired()) { - continue; - } - - if (app == null) { - app = new Application(appName); - } - app.addInstance(decorateInstanceInfo(entry.getValue())); - } - } - - return app; - } - - /** - * Get the registry information about all {@link Applications}. - * - * @return all applications. - */ - public Applications getApplications() { - GET_ALL_CACHE_MISS.increment(); - Applications apps = new Applications(); - apps.setVersion(1L); - for (Iterator>>> iter = _registry - .entrySet().iterator(); iter.hasNext();) { - Entry>> entry = iter.next(); - - Application app = null; - - if (entry.getValue() != null) { - for (Iterator>> subIter = entry - .getValue().entrySet().iterator(); subIter.hasNext();) { - - Lease lease = subIter.next().getValue(); - - if (app == null) { - app = new Application(lease.getHolder().getAppName()); - } - - app.addInstance(decorateInstanceInfo(lease)); - } - } - if (app != null) { - apps.addApplication(app); - } - } - apps.setAppsHashCode(apps.getReconcileHashCode()); - return apps; - } - - /** - * Get the registry information about the delta changes. The deltas are - * cached for a window specified by - * {@link EurekaServerConfig#getRetentionTimeInMSInDeltaQueue()}. Subsequent - * requests for delta information may return the same information and client - * must make sure this does not adversely affect them. - * - * @return all application deltas. - */ - public Applications getApplicationDeltas() { - GET_ALL_CACHE_MISS_DELTA.increment(); - Applications apps = new Applications(); - apps.setVersion(ResponseCache.getVersionDelta().get()); - Map applicationInstancesMap = new HashMap(); - try { - write.lock(); - Iterator iter = this.recentlyChangedQueue - .iterator(); - logger.debug("The number of elements in the delta queue is :" - + this.recentlyChangedQueue.size()); - while (iter.hasNext()) { - Lease lease = iter.next().getLeaseInfo(); - InstanceInfo instanceInfo = lease.getHolder(); - Object[] args = { instanceInfo.getId(), - instanceInfo.getStatus().name(), - instanceInfo.getActionType().name() }; - logger.debug( - "The instance id %s is found with status %s and actiontype %s", - args); - Application app = applicationInstancesMap.get(instanceInfo - .getAppName()); - if (app == null) { - app = new Application(instanceInfo.getAppName()); - applicationInstancesMap.put(instanceInfo.getAppName(), app); - apps.addApplication(app); - } - app.addInstance(decorateInstanceInfo(lease)); - } - Applications allApps = getApplications(); - apps.setAppsHashCode(allApps.getReconcileHashCode()); - return apps; - } finally { - write.unlock(); - } - } - - /** - * Gets the {@link InstanceInfo} information. - * - * @param appName - * the application name for which the information is requested. - * @param id - * the unique identifier of the instance. - * @return the information about the instance. - */ - public InstanceInfo getInstanceByAppAndId(String appName, String id) { - Map> leaseMap = _registry.get(appName); - Lease lease = null; - if (leaseMap != null) { - lease = leaseMap.get(id); - } - if (lease != null - && (!isLeaseExpirationEnabled() || !lease.isExpired())) { - return decorateInstanceInfo(lease); - } else { - return null; - } - } - - /* - * (non-Javadoc) - * - * @see - * com.netflix.discovery.shared.LookupService#getInstancesById(java.lang - * .String) - */ - public List getInstancesById(String id) { - List list = Collections.emptyList(); - - for (Iterator>>> iter = _registry - .entrySet().iterator(); iter.hasNext();) { - - Map> leaseMap = iter.next().getValue(); - if (leaseMap != null) { - Lease lease = leaseMap.get(id); - - if (lease == null - || (isLeaseExpirationEnabled() && lease.isExpired())) { - continue; - } - - if (lease != null && list == Collections.EMPTY_LIST) { - list = new ArrayList(); - } - - if (lease != null) { - list.add(decorateInstanceInfo(lease)); - } - } - } - return list; - } - - public abstract boolean isLeaseExpirationEnabled(); - - private InstanceInfo decorateInstanceInfo(Lease lease) { - InstanceInfo info = lease.getHolder(); - - // client app settings - int renewalInterval = LeaseInfo.DEFAULT_LEASE_RENEWAL_INTERVAL; - int leaseDuration = LeaseInfo.DEFAULT_LEASE_DURATION; - - // TODO: clean this up - if (info.getLeaseInfo() != null) { - renewalInterval = info.getLeaseInfo().getRenewalIntervalInSecs(); - leaseDuration = info.getLeaseInfo().getDurationInSecs(); - } - - info.setLeaseInfo(LeaseInfo.Builder.newBuilder() - .setRegistrationTimestamp(lease.getRegistrationTimestamp()) - .setRenewalTimestamp(lease.getLastRenewalTimestamp()) - .setRenewalIntervalInSecs(renewalInterval) - .setDurationInSecs(leaseDuration) - .setEvictionTimestamp(lease.getEvictionTimestamp()).build()); - - info.setIsCoordinatingDiscoveryServer(); - return info; - } - - @com.netflix.servo.annotations.Monitor(name = "numOfRenewsInLastMin", description = "Number of total heartbeats received in the last minute", type = DataSourceType.GAUGE) - public long getNumOfRenewsInLastMin() { - return renewsLastMin.getCount(); - } - - public List> getLastNRegisteredInstances() { - List> list = new ArrayList>(); - - synchronized (recentRegisteredQueue) { - for (Iterator> iter = recentRegisteredQueue - .iterator(); iter.hasNext();) { - list.add(iter.next()); - } - } - Collections.reverse(list); - return list; - } - - public List> getLastNCanceledInstances() { - List> list = new ArrayList>(); - synchronized (recentCanceledQueue) { - for (Iterator> iter = recentCanceledQueue - .iterator(); iter.hasNext();) { - list.add(iter.next()); - } - } - Collections.reverse(list); - return list; - } - - private void invalidateCache(String appName) { - // invalidate cache - ResponseCache.getInstance().invalidate(appName); - } - - private static final class RecentlyChangedItem { - private long lastUpdateTime; - private Lease leaseInfo; - - public RecentlyChangedItem(Lease lease) { - this.leaseInfo = lease; - lastUpdateTime = System.currentTimeMillis(); - } - - public long getLastUpdateTime() { - return this.lastUpdateTime; - } - - public Lease getLeaseInfo() { - return this.leaseInfo; - } - } - - protected void postInit() { - renewsLastMin = new MeasuredRate(1000 * 60 * 1); - evictionTimer.schedule(new TimerTask() { - - @Override - public void run() { - try { - evict(); - } catch (Throwable e) { - logger.error("Could not run the evict task", e); - } - - } - }, eurekaConfig.getEvictionIntervalTimerInMs(), - eurekaConfig.getEvictionIntervalTimerInMs()); - } - - @com.netflix.servo.annotations.Monitor(name = "numOfElementsinInstanceCache", description = "Number of elements in the instance Cache", type = DataSourceType.GAUGE) - public long getNumberofElementsininstanceCache() { - return overriddenInstanceStatusMap.size(); - } - - private class CircularQueue extends ConcurrentLinkedQueue { - int size = 0; - - public CircularQueue(int size) { - this.size = size; - } - - @Override - public boolean add(E e) { - this.makeSpaceIfnotAvailable(); - return super.add(e); - - } - - private void makeSpaceIfnotAvailable() { - if (this.size() == size) { - this.remove(); - } - } - - public boolean offer(E e) { - this.makeSpaceIfnotAvailable(); - return super.offer(e); - } - } - - private InstanceStatus getOverriddenInstanceStatus(InstanceInfo r, - Lease existingLease, boolean isReplication) { - // Instance is DOWN or STARTING - believe that, but when the instance - // says UP, question that - // The client instance sends STARTING or DOWN (because of heartbeat - // failures), then we accept what - // the client says. The same is the case with replica as well. - // The OUT_OF_SERVICE from the client or replica needs to be confirmed - // as well since the service may be - // currently in SERVICE - if ((!InstanceStatus.UP.equals(r.getStatus())) - && (!InstanceStatus.OUT_OF_SERVICE.equals(r.getStatus()))) { - logger.debug( - "Trusting the instance status {} from replica or instance for instance", - r.getStatus(), r.getId()); - return r.getStatus(); - } - // Overrides are the status like OUT_OF_SERVICE and UP set by NAC - InstanceStatus overridden = overriddenInstanceStatusMap.get(r.getId()); - // If there are instance specific overrides, then they win - otherwise - // the ASG status - if (overridden != null) { - logger.debug( - "The instance specific override for instance {} and the value is {}", - r.getId(), overridden.name()); - return overridden; - } - // If the ASGName is present- check for its status - boolean isASGDisabled = false; - if (r.getASGName() != null) { - isASGDisabled = !AwsAsgUtil.getInstance().isASGEnabled( - r.getASGName()); - logger.debug("The ASG name is specified {} and the value is {}", - r.getASGName(), isASGDisabled); - if (isASGDisabled) { - return InstanceStatus.OUT_OF_SERVICE; - } else { - return InstanceStatus.UP; - } - } - // This is for backward compatibility until all applications have ASG - // names, otherwise while starting up - // the client status may override status replicated from other servers - if (!isReplication) { - InstanceStatus existingStatus = null; - if (existingLease != null) { - existingStatus = existingLease.getHolder().getStatus(); - } - // Allow server to have its way when the status is UP or - // OUT_OF_SERVICE - if ((existingStatus != null) - && (InstanceStatus.OUT_OF_SERVICE.equals(existingStatus) || InstanceStatus.UP - .equals(existingStatus))) { - logger.debug( - "There is already an existing lease with status {} for instance {}", - existingLease.getHolder().getStatus().name(), - existingLease.getHolder().getId()); - return existingLease.getHolder().getStatus(); - } - } - logger.debug( - "Returning the default instance status {} for instance {},", - r.getStatus(), r.getId()); - return r.getStatus(); - } - - private TimerTask getDeltaRetentionTask() { - return new TimerTask() { - - @Override - public void run() { - Iterator it = recentlyChangedQueue - .iterator(); - while (it.hasNext()) { - if (it.next().getLastUpdateTime() < System - .currentTimeMillis() - - eurekaConfig.getRetentionTimeInMSInDeltaQueue()) { - it.remove(); - } else { - break; - } - } - } - - }; - } - -} diff --git a/eureka-core/src/main/java/com/netflix/discovery/PeerAwareInstanceRegistry.java b/eureka-core/src/main/java/com/netflix/discovery/PeerAwareInstanceRegistry.java deleted file mode 100644 index dd8522729..000000000 --- a/eureka-core/src/main/java/com/netflix/discovery/PeerAwareInstanceRegistry.java +++ /dev/null @@ -1,912 +0,0 @@ -/* - * Copyright 2012 Netflix, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.netflix.discovery; - -import java.net.URI; -import java.net.URISyntaxException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; -import java.util.Timer; -import java.util.TimerTask; -import java.util.concurrent.ArrayBlockingQueue; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.RejectedExecutionException; -import java.util.concurrent.ThreadFactory; -import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicReference; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.CacheLoader; -import com.google.common.cache.LoadingCache; -import com.google.common.collect.ComputationException; -import com.google.common.util.concurrent.ThreadFactoryBuilder; -import com.netflix.appinfo.AmazonInfo; -import com.netflix.appinfo.AmazonInfo.MetaDataKey; -import com.netflix.appinfo.ApplicationInfoManager; -import com.netflix.appinfo.InstanceInfo; -import com.netflix.appinfo.InstanceInfo.InstanceStatus; -import com.netflix.discovery.cluster.PeerEurekaNode; -import com.netflix.discovery.lease.Lease; -import com.netflix.discovery.resources.ASGResource.ASGStatus; -import com.netflix.discovery.shared.Application; -import com.netflix.discovery.shared.Applications; -import com.netflix.discovery.shared.LookupService; -import com.netflix.discovery.util.EurekaMonitors; -import com.netflix.discovery.util.MeasuredRate; -import com.netflix.servo.DefaultMonitorRegistry; -import com.netflix.servo.annotations.DataSourceType; -import com.netflix.servo.monitor.Counter; -import com.netflix.servo.monitor.Monitors; -import com.netflix.servo.monitor.Stopwatch; - -/** - * Handles replication of all operations to {@link InstanceRegistry} to peer - * Eureka nodes to keep them all in sync. - * - *

- * Primary operations that are replicated are the - * Registers,Renewals,Cancels,Expirations and Status Changes - *

- * - *

- * When the eureka server starts up it tries to fetch all the registry - * information from the peer eureka nodes.If for some reason this operation - * fails, the server does not allow the user to get the registry information for - * a period specified in - * {@link EurekaServerConfig#getWaitTimeInMsWhenSyncEmpty()}. - *

- * - *

- * One important thing to note about renewals.If the renewal drops more - * than the specified threshold as specified in - * {@link EurekaServerConfig#getRenewalPercentThreshold()} within a period of - * {@link EurekaServerConfig#getRenewalThresholdUpdateIntervalMs()}, eureka - * perceives this as a danger and stops expiring instances. - *

- * - * @author Karthik Ranganathan, Greg Kim - * - */ -public class PeerAwareInstanceRegistry extends InstanceRegistry { - private static final Logger logger = LoggerFactory - .getLogger(PeerAwareInstanceRegistry.class); - - private static final EurekaServerConfig eurekaServerConfig = EurekaServerConfigurationManager - .getInstance().getConfiguration(); - private static final String DICOVERY_FAILED_REPLICATION_AFTER_RETRY = "FailedReplicationAfterRetry"; - - private static final int REPL_RETRY_SLEEP_TIME_IN_MS = 40; - - private long startupTime = 0; - - private boolean peerInstancesTransferEmptyOnStartup = true; - - private static final Timer timerReplicaNodes = new Timer( - "Eureka-PeerNodesUpdater", true); - - enum Action { - Heartbeat, Register, Cancel, StatusUpdate; - - private com.netflix.servo.monitor.Timer timer = Monitors.newTimer(this - .name()); - - public com.netflix.servo.monitor.Timer getTimer() { - return this.timer; - } - - } - - private final static Comparator APP_COMPARATOR = new Comparator() { - public int compare(Application l, Application r) { - return l.getName().compareTo(r.getName()); - } - }; - - private final MeasuredRate numberOfReplicationsLastMin = new MeasuredRate( - 1000 * 60 * 1); - private final ThreadPoolExecutor replicationExecutorPool; - - private volatile int numberOfRenewsPerMinThreshold; - - private AtomicReference> peerEurekaNodes; - - private Timer timer = new Timer( - "ReplicaAwareInstanceRegistry - RenewalThresholdUpdater", true); - private static final LoadingCache peerEurekaStatusCache = CacheBuilder - .newBuilder() - .initialCapacity(10) - .expireAfterWrite( - eurekaServerConfig - .getPeerEurekaStatusRefreshTimeIntervalMs(), - TimeUnit.MILLISECONDS) - . build(new CacheLoader() { - public Boolean load(String serviceUrl) { - try { - return isPeerAliveInMyRegistery(serviceUrl); - } catch (Throwable e) { - throw new ComputationException(e); - } - } - - }); - - private static ConcurrentMap peerEurekaStatusMap = new ConcurrentHashMap() { - - private static final long serialVersionUID = 1L; - - @Override - public Boolean get(Object key) { - String myKey = (String) key; - try { - return peerEurekaStatusCache.get(myKey); - } catch (ExecutionException e) { - throw new RuntimeException( - "Cannot get other discovery instances ", e); - } - } - }; - private static final PeerAwareInstanceRegistry instance = new PeerAwareInstanceRegistry(); - - private Counter failedReplicationAfterRetry = Monitors - .newCounter(DICOVERY_FAILED_REPLICATION_AFTER_RETRY); - - PeerAwareInstanceRegistry() { - // Make it an atomic reference since this could be updated in the - // background. - peerEurekaNodes = new AtomicReference>(); - peerEurekaNodes.set(new ArrayList()); - try { - Monitors.registerObject(this); - } catch (Throwable e) { - logger.warn( - "Cannot register the JMX monitor for the InstanceRegistry :", - e); - } - ThreadFactory threadFactory = new ThreadFactoryBuilder() - .setDaemon(false).setNameFormat("Eureka-Replication-Thread") - .build(); - // Thread pool used for replication - replicationExecutorPool = new ThreadPoolExecutor(eurekaServerConfig - .getMinThreadsForReplication(), eurekaServerConfig - .getMaxThreadsForReplication(), eurekaServerConfig - .getMaxIdleThreadAgeInMinutesForReplication(), - TimeUnit.MINUTES, new ArrayBlockingQueue( - eurekaServerConfig.getMaxElementsInReplicationPool()), - threadFactory) { - }; - init(); - } - - public static PeerAwareInstanceRegistry getInstance() { - return instance; - } - - /** - * Set up replica nodes and the task that updates the threshold - * periodically. - */ - private void init() { - setupPeerEurekaNodes(); - scheduleRenewalThresholdUpdateTask(); - } - - /** - * Schedule the task that updates renewal threshold periodically. - * The renewal threshold would be used to determine if the renewals drop - * dramatically because of network partition and to protect expiring too - * many instances at a time. - * - */ - private void scheduleRenewalThresholdUpdateTask() { - timer.schedule(new TimerTask() { - - @Override - public void run() { - updateRenewalThreshold(); - - } - - }, eurekaServerConfig.getRenewalThresholdUpdateIntervalMs(), - eurekaServerConfig.getRenewalThresholdUpdateIntervalMs()); - } - - /** - * Set up a schedule task to update peer eureka node information - * periodically to determine if a node has been removed or added to the - * list. - */ - private void setupPeerEurekaNodes() { - try { - updatePeerEurekaNodes(); - timerReplicaNodes.schedule(new TimerTask() { - - @Override - public void run() { - try { - updatePeerEurekaNodes(); - } catch (Throwable e) { - logger.error("Cannot update the replica Nodes", e); - } - - } - }, eurekaServerConfig.getPeerEurekaNodesUpdateIntervalMs(), - eurekaServerConfig.getPeerEurekaNodesUpdateIntervalMs()); - - } catch (Exception e) { - throw new IllegalStateException(e); - } - } - - /** - * Update information about peer eureka nodes. - */ - private void updatePeerEurekaNodes() { - InstanceInfo myInfo = ApplicationInfoManager.getInstance().getInfo(); - List replicaUrls = DiscoveryManager.getInstance() - .getDiscoveryClient() - .getDiscoveryServiceUrls(DiscoveryClient.getZone(myInfo)); - List replicaNodes = new ArrayList(); - for (String replicaUrl : replicaUrls) { - if (!isThisMe(replicaUrl)) { - logger.info("Adding replica node: " + replicaUrl); - replicaNodes.add(new PeerEurekaNode(replicaUrl)); - } - } - if (replicaNodes.isEmpty()) { - logger.warn("The replica size seems to be empty. Check the route 53 DNS Registry"); - return; - } - if (!replicaNodes.equals(peerEurekaNodes.get())) { - List previousServiceUrls = new ArrayList(); - for (PeerEurekaNode node : peerEurekaNodes.get()) { - previousServiceUrls.add(node.getServiceUrl()); - } - List currentServiceUrls = new ArrayList(); - for (PeerEurekaNode node : replicaNodes) { - currentServiceUrls.add(node.getServiceUrl()); - } - logger.info( - "Updating the replica nodes as they seem to have changed from {} to {} ", - previousServiceUrls, currentServiceUrls); - peerEurekaNodes.set(replicaNodes); - } - } - - /** - * Populates the registry information from a peer eureka node. This - * operation fails over to other nodes until the list is exhausted if the - * communication fails. - */ - public void syncUp() { - // Copy entire entry from neighboring DS node - LookupService lookupService = DiscoveryManager.getInstance() - .getLookupService(); - - Applications apps = lookupService.getApplications(); - int count = 0; - for (Application app : apps.getRegisteredApplications()) { - for (InstanceInfo instance : app.getInstances()) { - try { - register(instance, -1, true); - count++; - } catch (Throwable t) { - logger.error("During DS init copy", t); - } - } - } - // Renewals happen every 30 seconds and for a minute it should be a - // factor of 2. - numberOfRenewsPerMinThreshold = (int) ((count * 2) * eurekaServerConfig - .getRenewalPercentThreshold()); - logger.info("Got " - + count - + " instances from neighboring DS node. Changing status to UP."); - logger.info("Renew threshold is: " + numberOfRenewsPerMinThreshold); - this.startupTime = System.currentTimeMillis(); - if (count > 0) { - this.peerInstancesTransferEmptyOnStartup = false; - } - ApplicationInfoManager.getInstance().setInstanceStatus( - InstanceStatus.UP); - super.postInit(); - } - - /** - * Checks to see if the registry access is allowed or the server is in a - * situation where it does not all getting registry information. The server - * does not return registry information for a period specified in - * {@link EurekaServerConfig#getWaitTimeInMsWhenSyncEmpty()}, if it cannot - * get the registry information from the peer eureka nodes at start up. - * - * @return false - if the instances count from a replica transfer returned - * zero and if the wait time has not elapsed, o otherwise returns - * true - */ - public boolean shouldAllowAccess() { - if (this.peerInstancesTransferEmptyOnStartup) { - if (System.currentTimeMillis() > this.startupTime - + eurekaServerConfig.getWaitTimeInMsWhenSyncEmpty()) { - return true; - } else { - return false; - } - } - return true; - } - - /** - * Gets the list of peer eureka nodes which is the list to replicate - * information to. - * - * @return the list of replica nodes. - */ - public List getReplicaNodes() { - return Collections.unmodifiableList(peerEurekaNodes.get()); - } - - /* - * (non-Javadoc) - * - * @see com.netflix.discovery.InstanceRegistry#cancel(java.lang.String, - * java.lang.String, long, boolean) - */ - @Override - public boolean cancel(final String appName, final String id, - final boolean isReplication) { - if (super.cancel(appName, id, isReplication)) { - replicateToPeers(Action.Cancel, appName, id, null, null, - isReplication); - return true; - } - return false; - } - - /** - * Registers the information about the {@link InstanceInfo} and replicates - * this information to all peer eureka nodes. If this is replication event - * from other replica nodes then it is not replicated. - * - * @param info - * the {@link InstanceInfo} to be registered and replicated. - * @param isReplication - * true if this is a replication event from other replica nodes, - * false otherwise. - */ - public void register(final InstanceInfo info, final boolean isReplication) { - int leaseDuration = Lease.DEFAULT_DURATION_IN_SECS; - if (info.getLeaseInfo() != null - && info.getLeaseInfo().getDurationInSecs() > 0) { - leaseDuration = info.getLeaseInfo().getDurationInSecs(); - } - super.register(info, leaseDuration, isReplication); - replicateToPeers(Action.Register, info.getAppName(), info.getId(), - info, null, isReplication); - } - - /* - * (non-Javadoc) - * - * @see com.netflix.discovery.InstanceRegistry#renew(java.lang.String, - * java.lang.String, long, boolean) - */ - public boolean renew(final String appName, final String id, - final boolean isReplication) { - if (super.renew(appName, id, isReplication)) { - replicateToPeers(Action.Heartbeat, appName, id, null, null, - isReplication); - return true; - } - return false; - } - - /* - * (non-Javadoc) - * - * @see - * com.netflix.discovery.InstanceRegistry#statusUpdate(java.lang.String, - * java.lang.String, com.netflix.appinfo.InstanceInfo.InstanceStatus, long, - * boolean) - */ - public boolean statusUpdate(final String appName, final String id, - final InstanceStatus newStatus, final boolean isReplication) { - if (super.statusUpdate(appName, id, newStatus, isReplication)) { - replicateToPeers(Action.StatusUpdate, appName, id, null, newStatus, - isReplication); - return true; - } - return false; - } - - /** - * Replicate the ASG status updates to peer eureka nodes. If this - * event is a replication from other nodes, then it is not replicated to - * other nodes. - * - * @param asgName - * the asg name for which the status needs to be replicated. - * @param newStatus - * the {@link ASGStatus} information that needs to be replicated. - * @param isReplication - * true if this is a replication event from other nodes, false - * otherwise. - */ - public void statusUpdate(final String asgName, final ASGStatus newStatus, - final boolean isReplication) { - // If this is replicated from an other node, do not try to replicate - // again. - if (isReplication) { - return; - } - for (final PeerEurekaNode node : peerEurekaNodes.get()) { - String serviceUrl = node.getServiceUrl(); - if (!isPeerAlive(serviceUrl) - && eurekaServerConfig.shouldReplicateOnlyIfUP()) { - logger.warn( - "The discovery node {} seems to be down and hence not replicating it there", - serviceUrl); - } - - try { - replicationExecutorPool.execute(new Runnable() { - public void run() { - replicateASGInfoToReplicaNodes(asgName, newStatus, node); - } - - }); - } catch (RejectedExecutionException e) { - logger.error("ReplicaAwareInstanceRegistry: RejectedExecutionException: ASGStatusUpdate " - + " - " + node.getServiceUrl()); - EurekaMonitors.REJECTED_REPLICATIONS.increment(); - } catch (Throwable t) { - logger.error("ReplicaAwareInstanceRegistry: ASGStatusUpdate", t); - EurekaMonitors.FAILED_REPLICATIONS.increment(); - } - } - - } - - /* - * (non-Javadoc) - * - * @see com.netflix.discovery.InstanceRegistry#isLeaseExpirationEnabled() - */ - @Override - public boolean isLeaseExpirationEnabled() { - boolean leaseExpirationEnabled = (getNumOfRenewsInLastMin() > numberOfRenewsPerMinThreshold); - boolean isSelfPreservationModeEnabled = isSelfPreservationModeEnabled(); - if ((!leaseExpirationEnabled)) { - if (isSelfPreservationModeEnabled) { - logger.error("The lease expiration has been disabled since the number of renewals per minute " - + " is lower than the minimum threshold. Number of Renewals Last Minute : " - + getNumOfRenewsInLastMin() - + ". The Threshold is " - + eurekaServerConfig.getRenewalPercentThreshold() - + " of total instances : " - + numberOfRenewsPerMinThreshold); - } else { - logger.warn("The self preservation mode is disabled!. Hence allowing the instances to expire."); - leaseExpirationEnabled = true; - } - } - return leaseExpirationEnabled; - } - - /** - * Checks to see if the self-preservation mode is enabled. - * - *

- * The self-preservation mode is enabled if the expected number of renewals - * per minute {@link #getNumOfRenewsInLastMin()} is lesser than the expected - * threshold which is determined by {@link #getNumOfRenewsPerMinThreshold()} - * . Eureka perceives this as a danger and stops expiring instances as this - * is most likely because of a network event. The mode is disabled only when - * the renewals get back to above the threshold or if the flag - * {@link EurekaServerConfig#shouldEnableSelfPreservation()} is set to - * false. - *

- * - * @return true if the self-preservation mode is enabled, false otherwise. - */ - public boolean isSelfPreservationModeEnabled() { - return eurekaServerConfig.shouldEnableSelfPreservation(); - } - - /** - * Perform all cleanup and shutdown operations. - */ - void shutdown() { - try { - this.replicationExecutorPool.shutdown(); - DefaultMonitorRegistry.getInstance().unregister( - Monitors.newObjectMonitor(this)); - } catch (Throwable t) { - logger.error("Cannot shutdown ReplicaAwareInstanceRegistry", t); - } - } - - @Override - public InstanceInfo getNextServerFromEureka(String virtualHostname, boolean secure) { - // TODO Auto-generated method stub - return null; - } - - /** - * Updates the renewal threshold based on the current number of - * renewals. The threshold is a percentage as specified in - * {@link EurekaServerConfig#getRenewalPercentThreshold()} of renewals - * received per minute {@link #getNumOfRenewsInLastMin()}. - */ - private void updateRenewalThreshold() { - try { - LookupService lookupService = DiscoveryManager.getInstance() - .getLookupService(); - Applications apps = lookupService.getApplications(); - int count = 0; - for (Application app : apps.getRegisteredApplications()) { - for (InstanceInfo instance : app.getInstances()) { - ++count; - } - } - // Update threshold only if the threshold is greater than the - // current expected threshold. - if ((count * 2) > (eurekaServerConfig.getRenewalPercentThreshold() * numberOfRenewsPerMinThreshold)) { - numberOfRenewsPerMinThreshold = (int) ((count * 2) * eurekaServerConfig - .getRenewalPercentThreshold()); - logger.info("Updated the renewal threshold to : {}", - numberOfRenewsPerMinThreshold); - } - } catch (Throwable e) { - logger.error("Cannot update renewal threshold", e); - } - } - - /** - * Gets the list of all {@link Applications} from the registry in sorted - * lexical order of {@link Application#getName()}. - * - * @return the list of {@link Applications} in lexical order. - */ - public List getSortedApplications() { - List apps = new ArrayList(getApplications() - .getRegisteredApplications()); - Collections.sort(apps, APP_COMPARATOR); - return apps; - } - - /** - * Gets the number of renewals in the last minute. - * - * @return a long value representing the number of renewals in the - * last minute. - */ - @com.netflix.servo.annotations.Monitor(name = "numOfReplicationsInLastMin", description = "Number of total replications received in the last minute", type = com.netflix.servo.annotations.DataSourceType.GAUGE) - public long getNumOfReplicationsInLastMin() { - return numberOfReplicationsLastMin.getCount(); - } - - /** - * Checks if the number of renewals is lesser than threshold. - * - * @return 0 if the renewals are greater than threshold, 1 otherwise. - */ - @com.netflix.servo.annotations.Monitor(name = "isBelowRenewThreshold", description = "0 = false, 1 = true", type = com.netflix.servo.annotations.DataSourceType.GAUGE) - public int isBelowRenewThresold() { - if ((getNumOfRenewsInLastMin() < numberOfRenewsPerMinThreshold) - && ((this.startupTime > 0) && (System.currentTimeMillis() > this.startupTime - + (eurekaServerConfig.getWaitTimeInMsWhenSyncEmpty())))) { - return 1; - } else { - return 0; - } - } - - /** - * Gets the threshold for the renewals per minute. - * - * @return the integer representing the threshold for the renewals per - * minute. - */ - @com.netflix.servo.annotations.Monitor(name = "numOfRenewsPerMinThreshold", type = DataSourceType.GAUGE) - public int getNumOfRenewsPerMinThreshold() { - return numberOfRenewsPerMinThreshold; - } - - /** - * Gets the number of items in the queue pending replication to other - * peers.This gives an indication of replication latency to peer replica - * nodes. - * - * @return the long value representing the number of items in the queue - * pending replication to other peers. - */ - @com.netflix.servo.annotations.Monitor(name = "itemsInReplicationPipeline", type = DataSourceType.GAUGE) - public long getNumOfItemsInReplicationPipeline() { - return replicationExecutorPool.getQueue().size(); - } - - /** - * Gets the number of active threads used for replicating to peer eureka - * nodes. This gives an indication of the headroom available to handle - * additional replication traffic. - * - * @return the long value represeting the number of active threads used for - * replicating to peer eureka nodes. - */ - @com.netflix.servo.annotations.Monitor(name = "numOfActiveThreadsInReplicationPipeline", type = DataSourceType.GAUGE) - public long getNumOfActiveThreadsInReplicationPipeline() { - return replicationExecutorPool.getActiveCount(); - } - - /** - * Sets the renewal threshold to the given threshold. - * - * @param newThreshold - * new renewal threshold to be set. - */ - public void setNumOfRenewsPerMinThreshold(int newThreshold) { - numberOfRenewsPerMinThreshold = newThreshold; - } - - /** - * Checks if the given service url contains the current host which is trying - * to replicate. Only after the EIP binding is done the host has a chance to - * identify itself in the list of replica nodes and needs to take itself out - * of replication traffic. - * - * @param url - * the service url of the replica node that the check is made. - * @return true, if the url represents the current node which is trying to - * replicate, false otherwise. - */ - private boolean isThisMe(String url) { - InstanceInfo myInfo = ApplicationInfoManager.getInstance().getInfo(); - try { - URI uri = new URI(url); - return (uri.getHost().equals(myInfo.getHostName())); - } catch (URISyntaxException e) { - logger.error("Error in syntax", e); - return false; - } - } - - /** - * Replicates all eureka actions to peer eureka nodes except for replication - * traffic to this node. - * - */ - private void replicateToPeers(final Action action, final String appName, - final String id, final InstanceInfo info /* optional */, - final InstanceStatus newStatus /* optional */, - final boolean isReplication) { - Stopwatch tracer = action.getTimer().start(); - try { - - if (isReplication) { - numberOfReplicationsLastMin.increment(); - } - // If it is a replication already, do not replicate again as this - // will create a poison replication - if (peerEurekaNodes == Collections.EMPTY_LIST || isReplication) { - return; - } - - for (final PeerEurekaNode node : peerEurekaNodes.get()) { - try { - replicationExecutorPool.execute(new Runnable() { - public void run() { - int retryCounter = eurekaServerConfig - .getNumberOfReplicationRetries(); - // If the url represents this host, do not replicate - // to yourself. - if (isThisMe(node.getServiceUrl())) { - return; - } - replicateInstanceActionsToPeers(action, appName, - id, info, newStatus, node, retryCounter); - } - - }); - } catch (RejectedExecutionException e) { - logger.error("ReplicaAwareInstanceRegistry: RejectedExecutionException: " - + action + " - " + node.getServiceUrl()); - EurekaMonitors.REJECTED_REPLICATIONS.increment(); - } catch (Throwable t) { - logger.error("ReplicaAwareInstanceRegistry: " + action, t); - EurekaMonitors.FAILED_REPLICATIONS.increment(); - } - } - } finally { - tracer.stop(); - } - } - - /** - * Replicates all instance changes to peer eureka nodes except for - * replication traffic to this node. - * - */ - private void replicateInstanceActionsToPeers(final Action action, - final String appName, final String id, final InstanceInfo info, - final InstanceStatus newStatus, final PeerEurekaNode node, - int retryCounter) { - String serviceUrl = node.getServiceUrl(); - try { - // Do not replicate if the peer is not alive and if the flag is set - - if (!isPeerAlive(serviceUrl) - && eurekaServerConfig.shouldReplicateOnlyIfUP() - // Do replicate if this is the information about Eureka - // itself. - && !(ApplicationInfoManager.getInstance().getInfo() - .getAppName().equals(appName))) { - // Do not retry - retryCounter = 0; - logger.warn( - "The discovery node {} seems to be down and hence not replicating it there", - serviceUrl); - // Clear the queue so that back log does not build up. - node.disableStatusReplication(); - return; - } else { - node.enableStatusReplication(); - } - CurrentRequestVersion.set(Version.V2); - switch (action) { - case Cancel: - node.cancel(appName, id); - break; - case Heartbeat: - InstanceStatus overriddenStatus = overriddenInstanceStatusMap - .get(id); - InstanceInfo infoFromRegistry = getInstanceByAppAndId(appName, - id); - if (!node.heartbeat(appName, id, infoFromRegistry, - overriddenStatus)) { - logger.warn( - "Cannot find instance id {} and hence replicating the instance with status {}", - infoFromRegistry.getId(), infoFromRegistry - .getStatus().toString()); - if (infoFromRegistry != null) { - node.register(infoFromRegistry); - } else { - logger.warn("ReplicaAwareInstanceRegistry: renew: missing entry!"); - } - } - break; - case Register: - node.register(info); - break; - case StatusUpdate: - node.statusUpdate(appName, id, newStatus); - break; - } - } catch (Throwable t) { - Object[] args = { action.name(), serviceUrl, id, retryCounter-- }; - logger.warn( - "ReplicaAwareInstanceRegistry: Failed replicating action {} for the server {} and instance id {}. Counting down from retry attempt {} ", - args); - EurekaMonitors.FAILED_REPLICATIONS.increment(); - if (retryCounter > 0) { - try { - Thread.sleep(REPL_RETRY_SLEEP_TIME_IN_MS); - } catch (InterruptedException ignore) { - } - replicateInstanceActionsToPeers(action, appName, id, info, - newStatus, node, retryCounter); - } else { - failedReplicationAfterRetry = Monitors - .newCounter(DICOVERY_FAILED_REPLICATION_AFTER_RETRY); - failedReplicationAfterRetry.increment(); - Object[] args_1 = { action.name(), serviceUrl, id }; - logger.error( - "ReplicaAwareInstanceRegistry: Failed replicating action {} for the server {} and instance id {}. No more retries left.", - args_1); - - } - - } - } - - /** - * Replicates all ASG status changes to peer eureka nodes except for - * replication traffic to this node. - * - */ - private void replicateASGInfoToReplicaNodes(final String asgName, - final ASGStatus newStatus, final PeerEurekaNode node) { - boolean success = false; - int retryCounter = eurekaServerConfig.getNumberOfReplicationRetries(); - int ctr = 0; - CurrentRequestVersion.set(Version.V2); - while ((!success) && (ctr++ < retryCounter)) { - try { - if (node.statusUpdate(asgName, newStatus)) { - success = true; - } else { - Thread.sleep(REPL_RETRY_SLEEP_TIME_IN_MS); - } - } catch (Throwable e) { - logger.error("ReplicaAwareInstanceRegistry: ASGStatusUpdate", e); - EurekaMonitors.FAILED_REPLICATIONS.increment(); - try { - Thread.sleep(REPL_RETRY_SLEEP_TIME_IN_MS); - } catch (InterruptedException e1) { - } - - } - - } - } - - /** - * Check if a peer eureka instance is alive. - * - * @param serviceUrl - * - The service url of the peer eureka node. - * @return - true if alive, false otherwise. - */ - private boolean isPeerAlive(String serviceUrl) { - Stopwatch t = Monitors.newTimer("DISCOVERY:checkReplicaAlive").start(); - boolean isReplicaAlive = peerEurekaStatusMap.get(serviceUrl); - try { - if (!isReplicaAlive) { - return isPeerAliveInMyRegistery(serviceUrl); - } - return isReplicaAlive; - } catch (Throwable e) { - return true; - } finally { - t.stop(); - } - } - - /** - * Checks if the peer that the action is replicated to is alive in the local - * registry. - * - * @param serviceUrl - * the service URL of the peer. - * @return true if it is alive, false otherwise. - * @throws URISyntaxException - */ - private static boolean isPeerAliveInMyRegistery(String serviceUrl) - throws URISyntaxException { - String myName = ApplicationInfoManager.getInstance().getInfo() - .getAppName(); - URI uri = new URI(serviceUrl); - Application app = PeerAwareInstanceRegistry.getInstance() - .getApplication(myName); - List instanceInfoList = app.getInstances(); - for (InstanceInfo instanceInfo : instanceInfoList) { - if (((AmazonInfo) instanceInfo.getDataCenterInfo()).get( - MetaDataKey.publicHostname).equalsIgnoreCase(uri.getHost())) { - return true; - } - } - return false; - } - -} diff --git a/eureka-core/src/main/java/com/netflix/discovery/StatusFilter.java b/eureka-core/src/main/java/com/netflix/discovery/StatusFilter.java deleted file mode 100644 index be6873922..000000000 --- a/eureka-core/src/main/java/com/netflix/discovery/StatusFilter.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright 2012 Netflix, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.netflix.discovery; - -import java.io.IOException; - -import javax.servlet.Filter; -import javax.servlet.FilterChain; -import javax.servlet.FilterConfig; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletResponse; - -import com.netflix.appinfo.ApplicationInfoManager; -import com.netflix.appinfo.InstanceInfo; -import com.netflix.appinfo.InstanceInfo.InstanceStatus; - -/** - * Filter to check whether the eureka server is ready to take requests based on - * its {@link InstanceStatus}. - */ -public class StatusFilter implements Filter { - - private static final int SC_TEMPORARY_REDIRECT = 307; - - /* - * (non-Javadoc) - * - * @see javax.servlet.Filter#destroy() - */ - public void destroy() { - // TODO Auto-generated method stub - - } - - /* - * (non-Javadoc) - * - * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, - * javax.servlet.ServletResponse, javax.servlet.FilterChain) - */ - public void doFilter(ServletRequest request, ServletResponse response, - FilterChain chain) throws IOException, ServletException { - InstanceInfo myInfo = ApplicationInfoManager.getInstance().getInfo(); - InstanceStatus status = myInfo.getStatus(); - if (status != InstanceStatus.UP - && response instanceof HttpServletResponse) { - HttpServletResponse httpRespone = (HttpServletResponse) response; - httpRespone.sendError(SC_TEMPORARY_REDIRECT, - "Current node is currently not ready to serve requests -- current status: " - + status + " - try another DS node: "); - } - chain.doFilter(request, response); - } - - /* - * (non-Javadoc) - * - * @see javax.servlet.Filter#init(javax.servlet.FilterConfig) - */ - public void init(FilterConfig arg0) throws ServletException { - } - -} diff --git a/eureka-core/src/main/java/com/netflix/discovery/V1AwareInstanceInfoConverter.java b/eureka-core/src/main/java/com/netflix/discovery/V1AwareInstanceInfoConverter.java deleted file mode 100644 index 2924b5250..000000000 --- a/eureka-core/src/main/java/com/netflix/discovery/V1AwareInstanceInfoConverter.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2012 Netflix, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.netflix.discovery; - -import com.netflix.appinfo.InstanceInfo; -import com.netflix.appinfo.InstanceInfo.InstanceStatus; -import com.netflix.discovery.converters.Converters.InstanceInfoConverter; - -/** - * Support for {@link Version#V1}. {@link Version#V2} introduces a new status - * {@link InstanceStatus#OUT_OF_SERVICE}. - * - * @author Karthik Ranganathan, Greg Kim - * - */ -public class V1AwareInstanceInfoConverter extends InstanceInfoConverter { - - @Override - public String getStatus(InstanceInfo info) { - Version version = CurrentRequestVersion.get(); - if (version == null || version == Version.V1) { - InstanceStatus status = info.getStatus(); - switch (status) { - case DOWN: - case STARTING: - case UP: - break; - default: - // otherwise return DOWN - status = InstanceStatus.DOWN; - break; - } - return status.name(); - } else { - return super.getStatus(info); - } - } - -} diff --git a/eureka-core/src/main/java/com/netflix/discovery/Version.java b/eureka-core/src/main/java/com/netflix/discovery/Version.java deleted file mode 100644 index 194b1c4b7..000000000 --- a/eureka-core/src/main/java/com/netflix/discovery/Version.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2012 Netflix, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.netflix.discovery; - -/** - * Supported versions for Eureka. - * - *

The latest versions are always recommended.

- * - * @author Karthik Ranganathan, Greg Kim - * - */ -public enum Version { - V1, V2; - - public static Version toEnum(String v){ - for(Version version : Version.values()){ - if(version.name().equalsIgnoreCase(v)){ - return version; - } - } - //Defaults to v2 - return V2; - } -} diff --git a/eureka-core/src/main/java/com/netflix/discovery/cluster/PeerEurekaNode.java b/eureka-core/src/main/java/com/netflix/discovery/cluster/PeerEurekaNode.java deleted file mode 100644 index f510dd7a6..000000000 --- a/eureka-core/src/main/java/com/netflix/discovery/cluster/PeerEurekaNode.java +++ /dev/null @@ -1,471 +0,0 @@ -/* - * Copyright 2012 Netflix, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.netflix.discovery.cluster; - -import java.util.Date; -import java.util.concurrent.ArrayBlockingQueue; -import java.util.concurrent.ThreadFactory; -import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.TimeUnit; - -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response.Status; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.common.util.concurrent.ThreadFactoryBuilder; -import com.netflix.appinfo.InstanceInfo; -import com.netflix.appinfo.InstanceInfo.InstanceStatus; -import com.netflix.discovery.CurrentRequestVersion; -import com.netflix.discovery.EurekaServerConfig; -import com.netflix.discovery.EurekaServerConfigurationManager; -import com.netflix.discovery.PeerAwareInstanceRegistry; -import com.netflix.discovery.Version; -import com.netflix.discovery.resources.ASGResource.ASGStatus; -import com.netflix.discovery.shared.EurekaJerseyClient; -import com.netflix.discovery.shared.EurekaJerseyClient.JerseyClient; -import com.netflix.servo.annotations.DataSourceType; -import com.netflix.servo.monitor.Monitors; -import com.netflix.servo.monitor.Stopwatch; -import com.netflix.servo.monitor.Timer; -import com.sun.jersey.api.client.ClientResponse; -import com.sun.jersey.api.client.WebResource; -import com.sun.jersey.client.apache4.ApacheHttpClient4; - -/** - * The PeerEurekaNode represents a peer node to which information - * should be shared from this node. - * - *

- * This class handles replicating all update operations like - * Register,Renew,Cancel,Expiration and Status Changes to the eureka - * node it represents. - *

- * - * @author Karthik Ranganathan, Greg Kim - * - */ -public class PeerEurekaNode { - - private static final Logger logger = LoggerFactory - .getLogger(PeerEurekaNode.class); - - private static final int RETRY_SLEEP_TIME_MS = 100; - - public static final String HEADER_REPLICATION = "x-netflix-discovery-replication"; - private static final EurekaServerConfig config = EurekaServerConfigurationManager - .getInstance().getConfiguration(); - private final Timer registerTimer = Monitors.newTimer("Register"); - private final Timer cancelTimer = Monitors.newTimer("Cancel"); - private final Timer renewTimer = Monitors.newTimer("Renew"); - private final Timer asgStatusUpdateTimer = Monitors - .newTimer("ASGStatusUpdate"); - private final Timer instanceStatusUpdateTimer = Monitors - .newTimer("InstanceStatusUpdate"); - private final String serviceUrl; - private final String name; - private JerseyClient jerseyClient; - private ApacheHttpClient4 jerseyApacheClient; - private ThreadPoolExecutor statusReplicationPool; - private volatile boolean statusReplication = true; - - public PeerEurekaNode(String serviceUrl) { - this.serviceUrl = serviceUrl.intern(); - this.name = getClass().getSimpleName() + ": " + serviceUrl + "apps/: "; - - ThreadFactory threadFactory = new ThreadFactoryBuilder() - .setDaemon(false) - .setNameFormat("Eureka-ReplicaNode-Thread-" + serviceUrl) - .build(); - - statusReplicationPool = new ThreadPoolExecutor( - config.getMinThreadsForStatusReplication(), - config.getMaxThreadsForStatusReplication(), - config.getMaxIdleThreadInMinutesAgeForStatusReplication(), - TimeUnit.MINUTES, new ArrayBlockingQueue( - config.getMaxElementsInStatusReplicationPool()), - threadFactory) { - }; - - synchronized (this.serviceUrl) { - - if (jerseyApacheClient == null) { - try { - jerseyClient = EurekaJerseyClient.createJerseyClient( - config.getPeerNodeConnectTimeoutMs(), - config.getPeerNodeReadTimeoutMs(), - config.getPeerNodeTotalConnections(), - config.getPeerNodeTotalConnectionsPerHost(), - config.getPeerNodeConnectionIdleTimeoutSeconds()); - jerseyApacheClient = jerseyClient.getClient(); - } catch (Throwable e) { - throw new RuntimeException( - "Cannot Create new Replica Node :" + name); - } - } - } - try { - - Monitors.registerObject(serviceUrl, this); - - } catch (Throwable e) { - logger.warn( - "Cannot register the JMX monitor for the InstanceRegistry :", - e); - } - - } - - /** - * Sends the registration information of {@link InstanceInfo} receiving by - * this node to the peer node represented by this class. - * - * @param info - * the instance information {@link InstanceInfo} of any instance - * that is send to this instance. - * @throws Exception - */ - public void register(InstanceInfo info) throws Exception { - Stopwatch tracer = registerTimer.start(); - String urlPath = "apps/" + info.getAppName(); - ClientResponse response = null; - - try { - response = jerseyApacheClient.resource(serviceUrl).path(urlPath) - .header(HEADER_REPLICATION, "true") - .type(MediaType.APPLICATION_JSON_TYPE) - .post(ClientResponse.class, info); - - } finally { - if (response != null) { - response.close(); - } - if (tracer != null) { - tracer.stop(); - } - } - } - - /** - * Send the cancellation information of an instance to the node represented - * by this class. - * - * @param appName - * the application name of the instance. - * @param id - * the unique identifier of the instance. - * @throws Exception - */ - public void cancel(String appName, String id) throws Exception { - ClientResponse response = null; - Stopwatch tracer = cancelTimer.start(); - - try { - String urlPath = "apps/" + appName + "/" + id; - response = jerseyApacheClient.resource(serviceUrl).path(urlPath) - .header(HEADER_REPLICATION, "true") - .delete(ClientResponse.class); - if (response.getStatus() == 404) { - logger.warn(name + appName + "/" + id - + " : delete: missing entry."); - } - - } finally { - if (response != null) { - response.close(); - } - if (tracer != null) { - tracer.stop(); - } - } - } - - /** - * Send the heartbeat information of an instance to the node represented by - * this class. If the instance does not exist the node, the instance - * registration information is sent again to the peer node. - * - * @param appName - * the application name of the instance. - * @param id - * the unique identifier of the instance. - * @param info - * the instance info {@link InstanceInfo} of the instance. - * @param overriddenStatus - * the overridden status information if any of the instance. - * @return true, if the instance exists in the peer node, false otherwise. - * @throws Exception - */ - public boolean heartbeat(String appName, String id, InstanceInfo info, - InstanceStatus overriddenStatus) throws Exception { - ClientResponse response = null; - Stopwatch tracer = renewTimer.start(); - try { - String urlPath = "apps/" + appName + "/" + id; - WebResource r = jerseyApacheClient - .resource(serviceUrl) - .path(urlPath) - .queryParam("status", info.getStatus().toString()) - .queryParam("lastDirtyTimestamp", - info.getLastDirtyTimestamp().toString()); - if (overriddenStatus != null) { - r.queryParam("overriddenstatus", overriddenStatus.name()); - } - response = r.header(HEADER_REPLICATION, "true").put( - ClientResponse.class); - - if (response.getStatus() == 404) { - logger.warn(name + appName + "/" + id - + " : heartbeat: missing entry."); - return false; - } else if (response.getStatus() == Status.OK.getStatusCode()) { - syncInstancesIfTimestampDiffers(id, info, response); - } - } finally { - if (response != null) { - response.close(); - } - if (tracer != null) { - tracer.stop(); - } - } - return true; - } - - /** - * Synchronize {@link InstanceInfo} information if the timestamp between this node and the peer eureka nodes vary. - */ - private void syncInstancesIfTimestampDiffers(String id, InstanceInfo info, - ClientResponse response) { - try { - if (config.shouldSyncWhenTimestampDiffers() - && response.hasEntity()) { - InstanceInfo infoFromPeer = response - .getEntity(InstanceInfo.class); - if (infoFromPeer != null) { - Object[] args = { - id, - new Date(info.getLastDirtyTimestamp()), - new Date( - infoFromPeer - .getLastDirtyTimestamp()) }; - - logger.warn( - "Peer wants us to take the instance information from it, since the timestamp differs,Id : {} My Timestamp : {}, Peer's timestamp: {}", - args); - Object[] args1 = { id, info.getOverriddenStatus(), - infoFromPeer.getOverriddenStatus() }; - logger.warn( - "Overridden Status info -id {}, mine {}, peer's {}", - args1); - if ((infoFromPeer.getStatus() != null) - && !(InstanceStatus.UNKNOWN - .equals(infoFromPeer.getStatus()))) - PeerAwareInstanceRegistry.getInstance() - .storeOverriddenStatusIfRequired( - id, - infoFromPeer - .getOverriddenStatus()); - PeerAwareInstanceRegistry.getInstance().register( - infoFromPeer, true); - - } - - } - } catch (Throwable e) { - logger.warn( - "Exception when trying to get information from peer :", - e); - } - } - - /** - * Send the status information of of the ASG represented by the instance. - * - *

- * ASG (Autoscaling group) names are available for instances in AWS and the - * ASG information is used for determining if the instance should be - * registered as {@link InstanceStatus#DOWN} or {@link InstanceStatus#UP}. - * - * @param asgName - * the asg name if any of this instance. - * @param newStatus - * the new status of the ASG. - * @return true if the status update succeeds, false otherwise. - * @throws Exception - */ - public boolean statusUpdate(String asgName, ASGStatus newStatus) - throws Exception { - ClientResponse response = null; - Stopwatch tracer = asgStatusUpdateTimer.start(); - try { - String urlPath = "asg/" + asgName + "/status"; - response = jerseyApacheClient.resource(serviceUrl).path(urlPath) - .queryParam("value", newStatus.name()) - .header(HEADER_REPLICATION, "true") - .put(ClientResponse.class); - - if (response.getStatus() != 200) { - logger.error(name + asgName + " : statusUpdate: failed!"); - } else { - return true; - } - tracer.stop(); - return false; - } finally { - if (response != null) { - response.close(); - } - if (tracer != null) { - tracer.stop(); - } - } - } - - /** - * - * Send the status update of the instance. - * - * @param appName - * the application name of the instance. - * @param id - * the unique identifier of the instance. - * @param newStatus - * the new status of the instance. - * @return true if the udpate succeeded, false otherwise. - * @throws Throwable - */ - public boolean statusUpdate(final String appName, final String id, - final InstanceStatus newStatus) throws Throwable { - statusReplicationPool.execute(new Runnable() { - - @Override - public void run() { - CurrentRequestVersion.set(Version.V2); - boolean success = false; - while (!success) { - ClientResponse response = null; - Stopwatch tracer = instanceStatusUpdateTimer.start(); - try { - String urlPath = "apps/" + appName + "/" + id - + "/status"; - response = jerseyApacheClient.resource(serviceUrl) - .path(urlPath) - .queryParam("value", newStatus.name()) - .header(HEADER_REPLICATION, "true") - .put(ClientResponse.class); - if (response.getStatus() != 200) { - logger.error(name + appName + "/" + id - + " : statusUpdate: failed!"); - } - success = true; - } catch (Throwable e) { - logger.error(name + appName + "/" + id - + " : statusUpdate: failed!", e); - try { - Thread.sleep(RETRY_SLEEP_TIME_MS); - } catch (InterruptedException e1) { - - } - if ((!config.shouldRetryIndefinitelyToReplicateStatus()) - || (!statusReplication)) { - success = true; - } - - } finally { - if (response != null) { - response.close(); - } - if (tracer != null) { - tracer.stop(); - } - } - - } - - } - - }); - return true; - } - - /** - * Get the service Url of the peer eureka node. - * - * @return the service Url of the peer eureka node. - */ - public String getServiceUrl() { - return serviceUrl; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result - + ((serviceUrl == null) ? 0 : serviceUrl.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - PeerEurekaNode other = (PeerEurekaNode) obj; - if (serviceUrl == null) { - if (other.serviceUrl != null) - return false; - } else if (!serviceUrl.equals(other.serviceUrl)) - return false; - return true; - } - - /** - * Get the number of items in the replication pipeline yet to be replicated. - * - * @return the long value representing the number of items in the - * replication pipeline yet to be replicated.. - */ - @com.netflix.servo.annotations.Monitor(name = "itemsInReplicationPipeline", type = DataSourceType.GAUGE) - public long getNumOfItemsInReplicationPipeline() { - return statusReplicationPool.getQueue().size(); - } - - /** - * Disables the status replication and clears the internal queue. - */ - public void disableStatusReplication() { - if (statusReplicationPool.getQueue().size() > 0) { - logger.info("Clearing the internal status queue for {}", serviceUrl); - statusReplicationPool.getQueue().clear(); - } - this.statusReplication = false; - } - - /** - * Enable the status replication. - */ - public void enableStatusReplication() { - this.statusReplication = true; - } - -} diff --git a/eureka-core/src/main/java/com/netflix/discovery/lease/Lease.java b/eureka-core/src/main/java/com/netflix/discovery/lease/Lease.java deleted file mode 100644 index 60748cd45..000000000 --- a/eureka-core/src/main/java/com/netflix/discovery/lease/Lease.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright 2012 Netflix, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.netflix.discovery.lease; - -import com.netflix.appinfo.InstanceInfo; -import com.netflix.discovery.InstanceRegistry; - -/** - * Describes a time-based availability of a {@link T}. Purpose is to avoid - * accumulation of instances in {@link InstanceRegistry} as result of ungraceful - * shutdowns that is not uncommon in AWS environments. - * - * If a lease elapses without renewals, it will eventually expire consequently - * marking the associated {@link T} for immediate eviction - this is similar to - * an explicit cancellation except that there is no communication between the - * {@link T} and {@link LeaseManager}. - * - * @author Karthik Ranganathan, Greg Kim - */ -public class Lease { - - enum Action { - Register, Cancel, Renew - }; - - public final static int DEFAULT_DURATION_IN_SECS = 90; - - private T holder; - private long evictionTimestamp; - private long registrationTimestamp; - private long lastUpdateTimestamp; - private long duration; - - public Lease(T r, int durationInSecs) { - holder = r; - registrationTimestamp = System.currentTimeMillis(); - lastUpdateTimestamp = registrationTimestamp; - duration = (durationInSecs * 1000); - - } - - /** - * Renew the lease, use renewal duration if it was specified by the - * associated {@link T} during registration, otherwise default duration is - * {@link #DEFAULT_DURATION_IN_SECS} - */ - public void renew() { - lastUpdateTimestamp = System.currentTimeMillis() + duration; - - } - - /** - * Cancels the lease by updating the eviction time. - */ - public void cancel() { - if (evictionTimestamp <= 0) { - evictionTimestamp = System.currentTimeMillis(); - } - } - - /** - * Checks if the lease of a given {@link InstanceInfo} has expired or not. - */ - public boolean isExpired() { - return (evictionTimestamp > 0 || System.currentTimeMillis() > (lastUpdateTimestamp + duration)); - } - - /** - * Gets the milliseconds since epoch when the lease was registered. - * - * @return the milliseconds since epoch when the lease was registered. - */ - public long getRegistrationTimestamp() { - return registrationTimestamp; - } - - /** - * Gets the milliseconds since epoch when the lease was last renewed. - * - * @return the milliseconds since epoch when the lease was last renewed. - */ - public long getLastRenewalTimestamp() { - return lastUpdateTimestamp; - } - - /** - * Gets the milliseconds since epoch when the lease was evicted. - * - * @return the milliseconds since epoch when the lease was evicted. - */ - public long getEvictionTimestamp() { - return evictionTimestamp; - } - - /** - * Returns the holder of the lease. - */ - public T getHolder() { - return holder; - } - -} diff --git a/eureka-core/src/main/java/com/netflix/discovery/lease/LeaseManager.java b/eureka-core/src/main/java/com/netflix/discovery/lease/LeaseManager.java deleted file mode 100644 index cf7a47a89..000000000 --- a/eureka-core/src/main/java/com/netflix/discovery/lease/LeaseManager.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright 2012 Netflix, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.netflix.discovery.lease; - -import com.netflix.discovery.InstanceRegistry; - -/** - * This class is responsible for creating/renewing and evicting a lease - * for a particular instance. - * - *

- * Leases determine what instances receive traffic. When there is no renewal - * request from the client, the lease gets expired and the instances are evicted - * out of {@link InstanceRegistry}. This is key to instances receiving traffic - * or not. - *

- * - * @author Karthik Ranganathan, Greg Kim - * - * @param - */ -public interface LeaseManager { - - /** - * Assign a new {@link Lease} to the passed in {@link T} - * - * @param r - * - T to register - * @param leaseDuration - * @param isReplication - * - whether this is a replicated entry from another eureka node. - */ - void register(T r, int leaseDuration, boolean isReplication); - - /** - * Cancel the {@link Lease} associated w/ the passed in appName - * and id - * - * @param appName - * - unique id of the application. - * @param id - * - unique id within appName. - * @param isReplication - * - whether this is a replicated entry from another eureka node. - * @return true, if the operation was successful, false otherwise. - */ - boolean cancel(String appName, String id, boolean isReplication); - - /** - * Renew the {@link Lease} associated w/ the passed in appName - * and id - * - * @param id - * - unique id within appName - * @param isReplication - * - whether this is a replicated entry from another ds node - * @return whether the operation of successful - */ - boolean renew(String appName, String id, boolean isReplication); - - /** - * Evict {@link T}s with expired {@link Lease}(s). - */ - void evict(); -} diff --git a/eureka-core/src/main/java/com/netflix/discovery/resources/ASGResource.java b/eureka-core/src/main/java/com/netflix/discovery/resources/ASGResource.java deleted file mode 100644 index 80d562a52..000000000 --- a/eureka-core/src/main/java/com/netflix/discovery/resources/ASGResource.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright 2012 Netflix, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.netflix.discovery.resources; - -import javax.ws.rs.HeaderParam; -import javax.ws.rs.PUT; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; -import javax.ws.rs.QueryParam; -import javax.ws.rs.core.Response; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.netflix.appinfo.InstanceInfo.InstanceStatus; -import com.netflix.discovery.PeerAwareInstanceRegistry; -import com.netflix.discovery.cluster.PeerEurekaNode; -import com.netflix.discovery.util.AwsAsgUtil; - -/** - * A jersey resource for handling updates to {@link ASGStatus}. - * - *

- * The ASG status is used in AWS environments to automatically - * enable/disable instance registration based on the status of the ASG. This is - * particularly useful in red/black deployment scenarios where it is - * easy to switch to a new version and incase of problems switch back to the old - * versions of the deployment. - *

- * - *

- * During such a scenario, when an ASG is disabled and the instances go away and - * get refilled by an ASG - which is normal in AWS environments,the instances - * automatically go in the {@link InstanceStatus#OUT_OF_SERVICE} state when they - * are refilled by the ASG and if the ASG is disabled by as indicated by a flag - * in the ASG as described in {@link AwsAsgUtil#isASGEnabled(String)} - *

- * - * @author Karthik Ranganathan - * - */ -@Path("/{version}/asg") -@Produces({ "application/xml", "application/json" }) -public class ASGResource { - - private static final Logger logger = LoggerFactory - .getLogger(ASGResource.class); - - public enum ASGStatus { - - ENABLED, DISABLED; - - public static ASGStatus toEnum(String s) { - for (ASGStatus e : ASGStatus.values()) { - if (e.name().equalsIgnoreCase(s)) { - return e; - } - } - throw new RuntimeException( - "Cannot find ASG enum for the given string " + s); - } - } - - /** - * Changes the status information of the ASG. - * - * @param asgName - * the name of the ASG for which the status needs to be changed. - * @param newStatus - * the new status {@link ASGStatus} of the ASG. - * @param isReplication - * a header parameter containing information whether this is - * replicated from other nodes. - * - * @return response which indicates if the operation succeeded or not. - */ - @PUT - @Path("{asgName}/status") - public Response statusUpdate(@PathParam("asgName") String asgName, - @QueryParam("value") String newStatus, - @HeaderParam(PeerEurekaNode.HEADER_REPLICATION) String isReplication) { - try { - logger.info("Trying to update ASG Status for ASG {} to {}", - asgName, newStatus); - ASGStatus asgStatus = ASGStatus.valueOf(newStatus.toUpperCase()); - AwsAsgUtil.getInstance().setStatus(asgName, - (ASGStatus.DISABLED.equals(asgStatus) ? false : true)); - PeerAwareInstanceRegistry.getInstance().statusUpdate(asgName, - asgStatus, Boolean.valueOf(isReplication)); - logger.debug("Updated ASG Status for ASG {} to {}", asgName, - asgStatus); - - } catch (Throwable e) { - logger.error("Cannot update the status" + newStatus - + " for the ASG " + asgName, e); - return Response.serverError().build(); - } - return Response.ok().build(); - } - -} diff --git a/eureka-core/src/main/java/com/netflix/discovery/resources/ApplicationResource.java b/eureka-core/src/main/java/com/netflix/discovery/resources/ApplicationResource.java deleted file mode 100755 index 58309ba4a..000000000 --- a/eureka-core/src/main/java/com/netflix/discovery/resources/ApplicationResource.java +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright 2012 Netflix, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.netflix.discovery.resources; - -import javax.ws.rs.Consumes; -import javax.ws.rs.GET; -import javax.ws.rs.HeaderParam; -import javax.ws.rs.POST; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; -import javax.ws.rs.core.Response; -import javax.ws.rs.core.Response.Status; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.netflix.appinfo.InstanceInfo; -import com.netflix.discovery.CurrentRequestVersion; -import com.netflix.discovery.PeerAwareInstanceRegistry; -import com.netflix.discovery.Version; -import com.netflix.discovery.cluster.PeerEurekaNode; -import com.netflix.discovery.resources.ResponseCache.Key; -import com.netflix.discovery.resources.ResponseCache.KeyType; -import com.netflix.discovery.shared.Application; - -/** - * A jersey resource that handles request related to a particular - * {@link Application}. - * - * @author Karthik Ranganathan, Greg Kim - * - */ -@Produces({ "application/xml", "application/json" }) -public class ApplicationResource { - private static final Logger logger = LoggerFactory - .getLogger(ApplicationResource.class); - - private static final PeerAwareInstanceRegistry registry = PeerAwareInstanceRegistry - .getInstance(); - - String appName; - - public ApplicationResource(String appName) { - this.appName = appName.toUpperCase(); - } - - /** - * Gets information about a particular {@link Application}. - * - * @param version - * the version of the request. - * @param acceptHeader - * the accept header of the request to indicate whether to serve - * JSON or XML data. - * @return the response containing information about a particular - * application. - */ - @GET - public Response getApplication(@PathParam("version") String version, - @HeaderParam("Accept") final String acceptHeader) { - if (!PeerAwareInstanceRegistry.getInstance().shouldAllowAccess()) { - return Response.status(Status.FORBIDDEN).build(); - } - CurrentRequestVersion.set(Version.toEnum(version)); - KeyType keyType = KeyType.JSON; - if (acceptHeader == null || !acceptHeader.contains("json")) { - keyType = KeyType.XML; - } - - Key cacheKey = new Key(appName, keyType, CurrentRequestVersion.get()); - - String payLoad = ResponseCache.getInstance().get(cacheKey); - - if (payLoad != null) { - logger.debug("Found: {}", appName); - return Response.ok(payLoad).build(); - } else { - logger.debug("Not Found: {}", appName); - return Response.status(Status.NOT_FOUND).build(); - } - } - - /** - * Gets information about a particular instance of an application. - * - * @param id - * the unique identifier of the instance. - * @return information about a particular instance. - */ - @Path("{id}") - public InstanceResource getInstanceInfo(@PathParam("id") String id) { - return new InstanceResource(this, id); - } - - /** - * Registers information about a particular instance for an - * {@link Application}. - * - * @param info - * {@link InstanceInfo} information of the instance. - * @param isReplication - * a header parameter containing information whether this is - * replicated from other nodes. - */ - @POST - @Consumes({ "application/json", "application/xml" }) - public void addInstance(InstanceInfo info, - @HeaderParam(PeerEurekaNode.HEADER_REPLICATION) String isReplication) { - registry.register(info, "true".equals(isReplication)); - } - - /** - * Returns the application name of a particular application. - * - * @return the application name of a particular application. - */ - String getName() { - return appName; - } - -} \ No newline at end of file diff --git a/eureka-core/src/main/java/com/netflix/discovery/resources/ApplicationsResource.java b/eureka-core/src/main/java/com/netflix/discovery/resources/ApplicationsResource.java deleted file mode 100755 index 3fa6bc631..000000000 --- a/eureka-core/src/main/java/com/netflix/discovery/resources/ApplicationsResource.java +++ /dev/null @@ -1,191 +0,0 @@ -/* - * Copyright 2012 Netflix, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.netflix.discovery.resources; - -import java.net.URI; - -import javax.ws.rs.GET; -import javax.ws.rs.HeaderParam; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; -import javax.ws.rs.core.Context; -import javax.ws.rs.core.Response; -import javax.ws.rs.core.Response.Status; -import javax.ws.rs.core.UriInfo; - -import com.netflix.discovery.CurrentRequestVersion; -import com.netflix.discovery.EurekaServerConfig; -import com.netflix.discovery.EurekaServerConfigurationManager; -import com.netflix.discovery.PeerAwareInstanceRegistry; -import com.netflix.discovery.Version; -import com.netflix.discovery.resources.ResponseCache.Key; -import com.netflix.discovery.resources.ResponseCache.KeyType; -import com.netflix.discovery.shared.Application; -import com.netflix.discovery.shared.Applications; -import com.netflix.discovery.util.EurekaMonitors; - -/** - * A jersey resource that handles request related to all - * {@link Applications}. - * - * @author Karthik Ranganathan, Greg Kim - * - */ -@Path("/{version}/apps") -@Produces({ "application/xml", "application/json" }) -public class ApplicationsResource { - private static final String HEADER_ACCEPT = "Accept"; - private static final String HEADER_ACCEPT_ENCODING = "Accept-Encoding"; - private static final String HEADER_CONTENT_ENCODING = "Content-Encoding"; - private static final String HEADER_GZIP_VALUE = "gzip"; - private static final String HEADER_JSON_VALUE = "json"; - private static final EurekaServerConfig eurekaConfig = EurekaServerConfigurationManager - .getInstance().getConfiguration(); - - /** - * Gets information about a particular {@link Application}. - * - * @param version - * the version of the request. - * @param appId - * the unique application identifier (which is the name) of the - * application. - * @return information about a particular application. - */ - @Path("{appId}") - public ApplicationResource getApplicationResource( - @PathParam("version") String version, - @PathParam("appId") String appId) { - CurrentRequestVersion.set(Version.toEnum(version)); - return new ApplicationResource(appId); - } - - /** - * Get information about all {@link Applications}. - * - * @param version - * the version of the request. - * @param acceptHeader - * the accept header of the request to indicate whether to serve - * JSON or XML data. - * - * @param acceptEncoding - * the accept header of the request to indicate whether to serve - * compressed or uncompressed data. - * @param uriInfo - * the {@link URI} information of the request made. - * @return response containing information about all {@link Applications} - * from the {@link InstanceRegistry}. - */ - @GET - public Response getContainers(@PathParam("version") String version, - @HeaderParam(HEADER_ACCEPT) String acceptHeader, - @HeaderParam(HEADER_ACCEPT_ENCODING) String acceptEncoding, - @Context UriInfo uriInfo) { - - EurekaMonitors.GET_ALL.increment(); - // Check if the server allows the access to the registry. The server can - // restrict access if it is not - // ready to serve traffic depending on various reasons. - if (!PeerAwareInstanceRegistry.getInstance().shouldAllowAccess()) { - return Response.status(Status.FORBIDDEN).build(); - } - CurrentRequestVersion.set(Version.toEnum(version)); - KeyType keyType = KeyType.JSON; - if (acceptHeader == null || !acceptHeader.contains(HEADER_JSON_VALUE)) { - keyType = KeyType.XML; - } - Key cacheKey = new Key(ResponseCache.ALL_APPS, keyType, - CurrentRequestVersion.get()); - if (acceptEncoding != null - && acceptEncoding.contains(HEADER_GZIP_VALUE)) { - return Response.ok(ResponseCache.getInstance().getGZIP(cacheKey)) - .header(HEADER_CONTENT_ENCODING, HEADER_GZIP_VALUE).build(); - } else { - return Response.ok(ResponseCache.getInstance().get(cacheKey)) - .build(); - } - } - - /** - * Get information about all delta changes in {@link Applications}. - * - *

- * The delta changes represent the registry information change for a period - * as configured by - * {@link EurekaServerConfig#getRetentionTimeInMSInDeltaQueue()}. The - * changes that can happen in a registry include - * Registrations,Cancels,Status Changes and Expirations. Normally - * the changes to the registry are infrequent and hence getting just the - * delta will be much more efficient than getting the complete registry. - *

- * - *

- * Since the delta information is cached over a period of time, the requests - * may return the same data multiple times within the window configured by - * {@link EurekaServerConfig#getRetentionTimeInMSInDeltaQueue()}.The clients - * are expected to handle this duplicate information. - *

- * - * @param version - * the version of the request. - * @param acceptHeader - * the accept header of the request to indicate whether to serve - * JSON or XML data. - * - * @param acceptEncoding - * the accept header of the request to indicate whether to serve - * compressed or uncompressed data. - * @param uriInfo - * the {@link URI} information of the request made. - * @return response containing the delta information of the - * {@link InstanceRegistry}.z - */ - @Path("delta") - @GET - public Response getContainerDifferential( - @PathParam("version") String version, - @HeaderParam(HEADER_ACCEPT) String acceptHeader, - @HeaderParam(HEADER_ACCEPT_ENCODING) String acceptEncoding, - @Context UriInfo uriInfo) { - // If the delta flag is disabled in discovery or if the lease expiration - // has been disabled, redirect clients to get all instances - if ((eurekaConfig.shouldDisableDelta()) - || (!PeerAwareInstanceRegistry.getInstance() - .isLeaseExpirationEnabled() || (!PeerAwareInstanceRegistry - .getInstance().shouldAllowAccess()))) { - return Response.status(Status.FORBIDDEN).build(); - } - EurekaMonitors.GET_ALL_DELTA.increment(); - CurrentRequestVersion.set(Version.toEnum(version)); - KeyType keyType = KeyType.JSON; - if (acceptHeader == null || !acceptHeader.contains(HEADER_JSON_VALUE)) { - keyType = KeyType.XML; - } - Key cacheKey = new Key(ResponseCache.ALL_APPS_DELTA, keyType, - CurrentRequestVersion.get()); - if (acceptEncoding != null - && acceptEncoding.contains(HEADER_GZIP_VALUE)) { - return Response.ok(ResponseCache.getInstance().getGZIP(cacheKey)) - .header(HEADER_CONTENT_ENCODING, HEADER_GZIP_VALUE).build(); - } else { - return Response.ok(ResponseCache.getInstance().get(cacheKey)) - .build(); - } - } -} diff --git a/eureka-core/src/main/java/com/netflix/discovery/resources/InstanceResource.java b/eureka-core/src/main/java/com/netflix/discovery/resources/InstanceResource.java deleted file mode 100644 index 708e167a7..000000000 --- a/eureka-core/src/main/java/com/netflix/discovery/resources/InstanceResource.java +++ /dev/null @@ -1,256 +0,0 @@ -/* - * Copyright 2012 Netflix, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.netflix.discovery.resources; - -import java.util.Date; - -import javax.ws.rs.DELETE; -import javax.ws.rs.GET; -import javax.ws.rs.HeaderParam; -import javax.ws.rs.PUT; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; -import javax.ws.rs.QueryParam; -import javax.ws.rs.core.Response; -import javax.ws.rs.core.Response.Status; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.netflix.appinfo.InstanceInfo; -import com.netflix.appinfo.InstanceInfo.InstanceStatus; -import com.netflix.discovery.EurekaServerConfigurationManager; -import com.netflix.discovery.PeerAwareInstanceRegistry; -import com.netflix.discovery.cluster.PeerEurekaNode; - -/** - * A jersey resource that handles operations for a particular instance. - * - * @author Karthik Ranganathan, Greg Kim - * - */ -@Produces({ "application/xml", "application/json" }) -public class InstanceResource { - private final static Logger logger = LoggerFactory - .getLogger(InstanceResource.class); - - private final static PeerAwareInstanceRegistry registry = PeerAwareInstanceRegistry - .getInstance(); - - String id; - ApplicationResource app; - - public InstanceResource(ApplicationResource app, String id) { - this.id = id; - this.app = app; - } - - /** - * Get requests returns the information about the instance's - * {@link InstanceInfo}. - * - * @return response containing information about the the instance's - * {@link InstanceInfo}. - */ - @GET - public Response getInstanceInfo() { - InstanceInfo appInfo = registry - .getInstanceByAppAndId(app.getName(), id); - if (appInfo != null) { - logger.debug("Found: {} - {}", app.getName(), id); - return Response.ok(appInfo).build(); - } else { - logger.debug("Not Found: {} - {}", app.getName(), id); - return Response.status(Status.NOT_FOUND).build(); - } - } - - /** - * A put request for renewing lease from a client instance. - * - * @param isReplication - * a header parameter containing information whether this is - * replicated from other nodes. - * @param overriddenStatus - * overridden status if any. - * @param status - * the {@link InstanceStatus} of the instance. - * @param lastDirtyTimestamp - * last timestamp when this instance information was updated. - * @return response indicating whether the operation was a success or - * failure. - */ - @PUT - public Response renewLease( - @HeaderParam(PeerEurekaNode.HEADER_REPLICATION) String isReplication, - @QueryParam("overriddenstatus") String overriddenStatus, - @QueryParam("status") String status, - @QueryParam("lastDirtyTimestamp") String lastDirtyTimestamp) { - boolean isFromReplicaNode = "true".equals(isReplication); - boolean isSuccess = registry - .renew(app.getName(), id, isFromReplicaNode); - - // Not found in the registry, immediately ask for a register - if (!isSuccess) { - logger.debug("Not Found (Renew): {} - {}", app.getName(), id); - return Response.status(Status.NOT_FOUND).build(); - } - // Check if we need to sync based on dirty time stamp, the client - // instance might have changed some value - Response response = null; - if (lastDirtyTimestamp != null - && EurekaServerConfigurationManager.getInstance() - .getConfiguration().shouldSyncWhenTimestampDiffers()) { - response = this.validateDirtyTimestamp( - Long.valueOf(lastDirtyTimestamp), isFromReplicaNode); - // Store the overridden status since the validation found out the - // node that - // replicates wins - if (response.getStatus() == Response.Status.NOT_FOUND - .getStatusCode() - && (overriddenStatus != null) - && !(InstanceStatus.UNKNOWN.equals(overriddenStatus)) - && isFromReplicaNode) { - registry.storeOverriddenStatusIfRequired(overriddenStatus, - InstanceStatus.valueOf(overriddenStatus)); - } - return response; - } - logger.debug("Found (Renew): {} - {}" + app.getName(), id); - return Response.ok().build(); - } - - /** - * Handles {@link InstanceStatus} updates. - * - *

- * The status updates are normally done for administrative purposes to - * change the instance status between {@link InstanceStatus#UP} and - * {@link InstanceStatus#OUT_OF_SERVICE} to select or remove instances for - * receiving traffic. - *

- * - * @param newStatus - * the new status of the instance. - * @param isReplication - * a header parameter containing information whether this is - * replicated from other nodes. - * @return response indicating whether the operation was a success or - * failure. - */ - @PUT - @Path("status") - public Response statusUpdate(@QueryParam("value") String newStatus, - @HeaderParam(PeerEurekaNode.HEADER_REPLICATION) String isReplication) { - try { - boolean isSuccess = registry.statusUpdate(app.getName(), id, - InstanceStatus.valueOf(newStatus), - "true".equals(isReplication)); - - if (isSuccess) { - logger.info("Status updated: " + app.getName() + " - " + id - + " - " + newStatus); - return Response.ok().build(); - } else { - logger.warn("Unable to update status: " + app.getName() + " - " - + id + " - " + newStatus); - return Response.status(Status.NOT_ACCEPTABLE).build(); - } - } catch (Throwable e) { - logger.error("Error updating instance {} for status {}", id, - newStatus); - return Response.serverError().build(); - } - } - - /** - * Handles cancellation of leases for this particular instance. - * - * @param isReplication - * a header parameter containing information whether this is - * replicated from other nodes. - * @return response indicating whether the operation was a success or - * failure. - */ - @DELETE - public Response cancelLease( - @HeaderParam(PeerEurekaNode.HEADER_REPLICATION) String isReplication) { - boolean isSuccess = registry.cancel(app.getName(), id, - "true".equals(isReplication)); - - if (isSuccess) { - logger.info("Found (Cancel): " + app.getName() + " - " + id); - return Response.ok().build(); - } else { - logger.info("Not Found (Cancel): " + app.getName() + " - " + id); - return Response.status(Status.NOT_FOUND).build(); - } - } - - private boolean shouldSyncStatus(String status, boolean isReplication) { - InstanceInfo appInfo = registry - .getInstanceByAppAndId(app.getName(), id); - InstanceStatus instanceStatusFromRegistry = null; - if (appInfo != null) { - instanceStatusFromRegistry = appInfo.getStatus(); - } - InstanceStatus instanceStatusFromReplica = (status != null ? InstanceStatus - .valueOf(status) : null); - if (instanceStatusFromReplica != null) { - // Do sync up only for replication - because the client could have - // different state when the server - // state is updated by an external tool - if ((!instanceStatusFromRegistry.equals(instanceStatusFromReplica)) - && isReplication) { - Object[] args = { id, instanceStatusFromRegistry.name(), - instanceStatusFromReplica.name() }; - logger.warn( - "The instance status for {} is {} from registry, whereas it is {} from replica. Requesting a re-register from replica.", - args); - - return true; - } - } - return false; - - } - - private Response validateDirtyTimestamp(Long lastDirtyTimestamp, - boolean isReplication) { - InstanceInfo appInfo = registry - .getInstanceByAppAndId(app.getName(), id); - if (appInfo != null) { - if ((lastDirtyTimestamp != null) - && (!lastDirtyTimestamp.equals(appInfo - .getLastDirtyTimestamp()))) { - Object[] args = { id, appInfo.getLastDirtyTimestamp(), - lastDirtyTimestamp, isReplication }; - logger.warn( - "Time to sync, since the last dirty timestamp differs -" - + " Instance id : {},Registry : {} Incoming: {} Replication: {}", - args); - if (lastDirtyTimestamp > appInfo.getLastDirtyTimestamp()) { - return Response.status(Status.NOT_FOUND).build(); - } else if (appInfo.getLastDirtyTimestamp() > lastDirtyTimestamp) { - return Response.ok(appInfo).build(); - } - } - - } - return Response.ok().build(); - } -} diff --git a/eureka-core/src/main/java/com/netflix/discovery/resources/InstancesResource.java b/eureka-core/src/main/java/com/netflix/discovery/resources/InstancesResource.java deleted file mode 100644 index 68b50f4c9..000000000 --- a/eureka-core/src/main/java/com/netflix/discovery/resources/InstancesResource.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright 2012 Netflix, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.netflix.discovery.resources; - -import java.util.List; - -import javax.ws.rs.GET; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; -import javax.ws.rs.core.Response; -import javax.ws.rs.core.Response.Status; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.netflix.appinfo.InstanceInfo; -import com.netflix.discovery.CurrentRequestVersion; -import com.netflix.discovery.InstanceRegistry; -import com.netflix.discovery.PeerAwareInstanceRegistry; -import com.netflix.discovery.Version; - -/** - * A jersey resource that gets information about a particular instance. - * - * @author Karthik Ranganathan, Greg Kim - * - */ -@Produces({ "application/xml", "application/json" }) -@Path("/{version}/instances") -public class InstancesResource { - private static final Logger logger = LoggerFactory - .getLogger(InstancesResource.class); - - private final InstanceRegistry registry = PeerAwareInstanceRegistry - .getInstance(); - - @GET - @Path("{id}") - public Response getById(@PathParam("version") String version, - @PathParam("id") String id) { - CurrentRequestVersion.set(Version.toEnum(version)); - List list = registry.getInstancesById(id); - if (list != null && list.size() > 0) { - return Response.ok(list.get(0)).build(); - } else { - logger.info("Not Found: " + id); - return Response.status(Status.NOT_FOUND).build(); - } - } -} diff --git a/eureka-core/src/main/java/com/netflix/discovery/resources/ResponseCache.java b/eureka-core/src/main/java/com/netflix/discovery/resources/ResponseCache.java deleted file mode 100644 index 55ce7f50f..000000000 --- a/eureka-core/src/main/java/com/netflix/discovery/resources/ResponseCache.java +++ /dev/null @@ -1,424 +0,0 @@ -/* - * Copyright 2012 Netflix, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.netflix.discovery.resources; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.util.Timer; -import java.util.TimerTask; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicLong; -import java.util.zip.GZIPOutputStream; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.CacheLoader; -import com.google.common.cache.LoadingCache; -import com.netflix.discovery.CurrentRequestVersion; -import com.netflix.discovery.EurekaServerConfig; -import com.netflix.discovery.EurekaServerConfigurationManager; -import com.netflix.discovery.InstanceRegistry; -import com.netflix.discovery.PeerAwareInstanceRegistry; -import com.netflix.discovery.Version; -import com.netflix.discovery.converters.JsonXStream; -import com.netflix.discovery.converters.XmlXStream; -import com.netflix.discovery.shared.Application; -import com.netflix.discovery.shared.Applications; -import com.netflix.servo.DefaultMonitorRegistry; -import com.netflix.servo.annotations.DataSourceType; -import com.netflix.servo.monitor.Monitors; -import com.netflix.servo.monitor.Stopwatch; - -/** - * The class that is responsible for caching registry information that will be - * queried by the clients. - * - *

- * The cache is maintained in compressed and non-compressed form for three - * categories of requests - all applications, delta changes and for individual - * applications. The compressed form is probably the most efficient in terms of - * network traffic especially when querying all applications. - * - * The cache also maintains separate pay load for JSON and XML - * formats and for multiple versions too. The cache is updated periodically to - * reflect the latest information configured by - * {@link EurekaServerConfig#getResponseCacheUpdateIntervalMs()}. - *

- * - * @author Karthik Ranganathan, Greg Kim - */ -public class ResponseCache { - - private static final Logger logger = LoggerFactory - .getLogger(ResponseCache.class); - private static final EurekaServerConfig eurekaConfig = EurekaServerConfigurationManager - .getInstance().getConfiguration(); - - public final static String ALL_APPS = "ALL_APPS"; - public final static String ALL_APPS_DELTA = "ALL_APPS_DELTA"; - - private final com.netflix.servo.monitor.Timer serializeAllAppsTimer = Monitors - .newTimer("serialize-all"); - private final com.netflix.servo.monitor.Timer serializeDeltaAppsTimer = Monitors - .newTimer("serialize-all-delta"); - private final com.netflix.servo.monitor.Timer serializeOneApptimer = Monitors - .newTimer("serialize-one"); - private final com.netflix.servo.monitor.Timer compressPayloadTimer = Monitors - .newTimer("compress-payload"); - - private static final Timer timer = new Timer("Eureka -CacheFillTimer", true); - private static final AtomicLong versionDelta = new AtomicLong(0); - private final static String EMPTY_PAYLOAD = ""; - - public enum KeyType { - JSON, XML - }; - - private final ConcurrentMap readOnlyCacheMap = new ConcurrentHashMap(); - private final LoadingCache readWriteCacheMap = CacheBuilder - .newBuilder() - .initialCapacity(1000) - .expireAfterWrite( - eurekaConfig.getResponseCacheAutoExpirationInSeconds(), - TimeUnit.SECONDS).build(new CacheLoader() { - - @Override - public Value load(Key key) throws Exception { - return generatePayload(key); - } - }); - - private static final ResponseCache s_instance = new ResponseCache(); - - private ResponseCache() { - timer.schedule(getCacheUpdateTask(), - eurekaConfig.getResponseCacheUpdateIntervalMs(), - eurekaConfig.getResponseCacheUpdateIntervalMs()); - - try { - Monitors.registerObject(this); - - } catch (Throwable e) { - logger.warn( - "Cannot register the JMX monitor for the InstanceRegistry :", - e); - } - } - - private TimerTask getCacheUpdateTask() { - return new TimerTask() { - - @Override - public void run() { - try { - updateClientCache(); - } catch (Throwable e) { - logger.error( - "Cannot update client cache from response cache: ", - e); - } - } - }; - } - - public static ResponseCache getInstance() { - return s_instance; - } - - /** - * Get the cached information about applications. - * - *

- * If the cached information is not available it is generated on the first - * request. After the first request, the information is then updated - * periodically by a background thread. - *

- * - * @param key - * the key for which the cached information needs to be obtained. - * @return payload which contains information about the applications. - */ - public String get(final Key key) { - Value payload = getValue(key); - if (payload == null || payload.getPayload() == EMPTY_PAYLOAD) { - return null; - } else { - return payload.getPayload(); - } - } - - /** - * Get the compressed information about the applications. - * - * @param key - * the key for which the compressed cached information needs to - * be obtained. - * @return compressed payload which contains information about the - * applications. - */ - public byte[] getGZIP(Key key) { - Value payload = getValue(key); - if (payload == null) - return null; - return payload.getGzipped(); - } - - /** - * Invalidate the cache of a particular application. - * - * @param appName - * the application name of the application. - */ - public void invalidate(String appName) { - for (KeyType type : KeyType.values()) { - for (Version v : Version.values()) { - invalidate(new Key(appName, type, v), - new Key(ALL_APPS, type, v), new Key(ALL_APPS_DELTA, - type, v)); - } - } - } - - /** - * Invalidate the cache information given the list of keys. - * - * @param keys - * the list of keys for which the cache information needs to be - * invalidated. - */ - public void invalidate(Key... keys) { - for (Key key : keys) { - Object[] args = { key.getName(), key.getVersion(), key.getType() }; - logger.debug("Invalidating the response cache key : {} {} {}", args); - readWriteCacheMap.invalidate(key); - } - } - - /** - * Gets the version number of the cached data. - * - * @return teh version number of the cached data. - */ - public static AtomicLong getVersionDelta() { - return versionDelta; - } - - /** - * Get the number of items in the response cache. - * - * @return int value representing the number of items in response cache. - */ - @com.netflix.servo.annotations.Monitor(name = "responseCacheSize", type = DataSourceType.GAUGE) - public int getCurrentSize() { - return readWriteCacheMap.asMap().size(); - } - - /** - * Get the payload in both compressed and uncompressed form. - */ - private Value getValue(final Key key) { - Value payload = null; - try { - final Value currentPayload = readOnlyCacheMap.get(key); - if (currentPayload != null) { - payload = currentPayload; - } else { - payload = readWriteCacheMap.get(key); - readOnlyCacheMap.put(key, payload); - } - } catch (Throwable t) { - logger.error("Cannot get value for key :" + key, t); - } - return payload; - } - - /** - * Generate pay load with both JSON and XML formats for all applications. - */ - private String getPayLoad(Key key, Applications apps) { - if (key.getType() == KeyType.JSON) { - return JsonXStream.getInstance().toXML(apps); - } else { - return XmlXStream.getInstance().toXML(apps); - } - } - - /** - * Generate pay load with both JSON and XML formats for a given application. - */ - private String getPayLoad(Key key, Application app) { - if (app == null) { - return EMPTY_PAYLOAD; - } - - if (key.getType() == KeyType.JSON) { - return JsonXStream.getInstance().toXML(app); - } else { - return XmlXStream.getInstance().toXML(app); - } - } - - /** - * Update the read only cache periodically to the latest pay load. - */ - private void updateClientCache() { - logger.debug("Updating the client cache from response cache"); - for (ResponseCache.Key key : readOnlyCacheMap.keySet()) { - Object[] args = { key.getName(), key.getVersion(), key.getType() }; - logger.debug( - "Updating the client cache from response cache for key : {} {} {}", - args); - try { - CurrentRequestVersion.set(key.getVersion()); - Value cacheValue = readWriteCacheMap.get(key); - Value currentCacheValue = readOnlyCacheMap.get(key); - if (cacheValue != currentCacheValue) { - readOnlyCacheMap.put(key, cacheValue); - } - } catch (Throwable th) { - logger.error( - "Error while updating the client cache from response cache", - th); - } - } - } - - /* - * Generate pay load for the given key. - */ - private Value generatePayload(Key key) { - Stopwatch tracer = null; - InstanceRegistry registry = PeerAwareInstanceRegistry.getInstance(); - try { - String payload = null; - if (ALL_APPS.equals(key.getName())) { - tracer = this.serializeAllAppsTimer.start(); - payload = getPayLoad(key, registry.getApplications()); - } else if (ALL_APPS_DELTA.equals(key.getName())) { - tracer = this.serializeDeltaAppsTimer.start(); - versionDelta.incrementAndGet(); - payload = getPayLoad(key, registry.getApplicationDeltas()); - } else { - tracer = this.serializeOneApptimer.start(); - payload = getPayLoad(key, - registry.getApplication(key.getName())); - } - return new Value(payload); - } finally { - if (tracer != null) { - tracer.stop(); - } - } - } - - /** - * The key for the cached payload. - */ - public static class Key { - private final String appName; - private final KeyType requestType; - private final Version requestVersion; - private final String hashKey; - - public Key(String app, KeyType type, Version v) { - appName = app; - requestType = type; - requestVersion = v; - hashKey = appName + requestType.name() + requestVersion.name(); - } - - public String getName() { - return appName; - } - - public String getHashKey() { - return hashKey; - } - - public KeyType getType() { - return requestType; - } - - public Version getVersion() { - return requestVersion; - } - - @Override - public int hashCode() { - String hashKey = getHashKey(); - return hashKey.hashCode(); - } - - @Override - public boolean equals(Object other) { - if (other instanceof Key) { - return getHashKey().equals(((Key) other).getHashKey()); - } else { - return false; - } - } - } - - /** - * The class that stores payload in both compressed and uncompressed form. - * - */ - private class Value { - private final String payload; - private byte[] gzipped; - - public Value(String payload) { - this.payload = payload; - if (payload != EMPTY_PAYLOAD) { - Stopwatch tracer = compressPayloadTimer.start(); - try { - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - GZIPOutputStream out = new GZIPOutputStream(bos); - byte[] rawBytes = payload.getBytes(); - out.write(rawBytes); - // Finish creation of gzip file - out.finish(); - out.close(); - bos.close(); - this.gzipped = bos.toByteArray(); - } catch (IOException e) { - this.gzipped = null; - } finally { - if (tracer != null) { - tracer.stop(); - } - } - } else { - this.gzipped = null; - } - } - - public String getPayload() { - return this.payload; - } - - public byte[] getGzipped() { - return this.gzipped; - } - - } - -} \ No newline at end of file diff --git a/eureka-core/src/main/java/com/netflix/discovery/resources/StatusResource.java b/eureka-core/src/main/java/com/netflix/discovery/resources/StatusResource.java deleted file mode 100644 index 748cc470c..000000000 --- a/eureka-core/src/main/java/com/netflix/discovery/resources/StatusResource.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright 2012 Netflix, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.netflix.discovery.resources; - -import java.net.URI; -import java.text.SimpleDateFormat; -import java.util.Date; - -import javax.ws.rs.GET; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.netflix.appinfo.ApplicationInfoManager; -import com.netflix.appinfo.InstanceInfo; -import com.netflix.discovery.PeerAwareInstanceRegistry; -import com.netflix.discovery.cluster.PeerEurekaNode; -import com.netflix.discovery.shared.Application; -import com.netflix.discovery.util.StatusInfo; -import com.netflix.discovery.util.StatusInfo.Builder; - -/** - * An utility class for exposing information about peer nodes. - * - * @author Karthik Ranganathan, Greg Kim - */ -@Path("/{version}/status") -@Produces({ "application/xml", "application/json" }) -public class StatusResource { - private static final Logger logger = LoggerFactory - .getLogger(StatusResource.class); - private final static String DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss Z"; - - private final static PeerAwareInstanceRegistry registry = PeerAwareInstanceRegistry - .getInstance(); - - @GET - public StatusInfo getStatusInfo() { - Builder builder = Builder.newBuilder(); - // Add application level status - StringBuilder upReplicas = new StringBuilder(); - StringBuilder downReplicas = new StringBuilder(); - - StringBuilder replicaHostNames = new StringBuilder(); - String myAppName = ApplicationInfoManager.getInstance().getInfo() - .getAppName(); - - for (PeerEurekaNode node : registry.getReplicaNodes()) { - if (replicaHostNames.length() > 0) { - replicaHostNames.append(", "); - } - replicaHostNames.append(node.getServiceUrl()); - if (isReplicaAvailable(myAppName, node.getServiceUrl())) { - upReplicas.append(node.getServiceUrl()).append(','); - } else { - downReplicas.append(node.getServiceUrl()).append(','); - } - } - - builder.add("registered-replicas", replicaHostNames.toString()); - builder.add("available-replicas", upReplicas.toString()); - builder.add("unavailable-replicas", downReplicas.toString()); - - return builder.build(); - } - - private boolean isReplicaAvailable(String myAppName, String url) { - - try { - String givenHostName = new URI(url).getHost(); - Application app = PeerAwareInstanceRegistry.getInstance() - .getApplication(myAppName); - for (InstanceInfo info : app.getInstances()) { - if (info.getHostName().equals(givenHostName)) { - return true; - } - } - givenHostName = new URI(url).getHost(); - } catch (Throwable e) { - logger.error("Could not determine if the replica is available ", e); - } - return false; - } - - public static String getCurrentTimeAsString() { - SimpleDateFormat format = new SimpleDateFormat(DATE_FORMAT); - return format.format(new Date()); - } -} diff --git a/eureka-core/src/main/java/com/netflix/discovery/util/AwsAsgUtil.java b/eureka-core/src/main/java/com/netflix/discovery/util/AwsAsgUtil.java deleted file mode 100644 index 77690cb48..000000000 --- a/eureka-core/src/main/java/com/netflix/discovery/util/AwsAsgUtil.java +++ /dev/null @@ -1,309 +0,0 @@ -/* - * Copyright 2012 Netflix, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.netflix.discovery.util; - -import java.util.Arrays; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.Timer; -import java.util.TimerTask; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.amazonaws.ClientConfiguration; -import com.amazonaws.auth.BasicAWSCredentials; -import com.amazonaws.services.autoscaling.AmazonAutoScaling; -import com.amazonaws.services.autoscaling.AmazonAutoScalingClient; -import com.amazonaws.services.autoscaling.model.AutoScalingGroup; -import com.amazonaws.services.autoscaling.model.DescribeAutoScalingGroupsRequest; -import com.amazonaws.services.autoscaling.model.DescribeAutoScalingGroupsResult; -import com.amazonaws.services.autoscaling.model.SuspendedProcess; -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.CacheLoader; -import com.google.common.cache.LoadingCache; -import com.netflix.appinfo.InstanceInfo; -import com.netflix.discovery.DiscoveryManager; -import com.netflix.discovery.EurekaServerConfig; -import com.netflix.discovery.EurekaServerConfigurationManager; -import com.netflix.discovery.PeerAwareInstanceRegistry; -import com.netflix.discovery.shared.Application; -import com.netflix.discovery.shared.Applications; -import com.netflix.servo.DefaultMonitorRegistry; -import com.netflix.servo.annotations.DataSourceType; -import com.netflix.servo.monitor.Monitors; -import com.netflix.servo.monitor.Stopwatch; - -/** - * A utility class for querying and updating information about amazon - * autoscaling groups using the AWS APIs. - * - * @author Karthik Ranganathan - * - */ - -public class AwsAsgUtil { - private final Logger logger = LoggerFactory.getLogger(AwsAsgUtil.class); - private static final String PROP_ADD_TO_LOAD_BALANCER = "AddToLoadBalancer"; - private static final EurekaServerConfig eurekaConfig = EurekaServerConfigurationManager - .getInstance().getConfiguration(); - private static final AmazonAutoScaling client = new AmazonAutoScalingClient( - new BasicAWSCredentials(eurekaConfig.getAWSAccessId(), - eurekaConfig.getAWSSecretKey()), - new ClientConfiguration().withConnectionTimeout(eurekaConfig - .getASGQueryTimeoutMs())); - // Cache for the AWS ASG information - private final LoadingCache asgCache = CacheBuilder - .newBuilder().initialCapacity(500) - .expireAfterAccess(5, TimeUnit.MINUTES) - .build(new CacheLoader() { - - @Override - public Boolean load(String key) throws Exception { - return isASGEnabledinAWS(key); - } - }); - - private static final Timer timer = new Timer("Eureka-ASGCacheRefresh", true); - - private static final AwsAsgUtil awsAsgUtil = new AwsAsgUtil(); - - private AwsAsgUtil() { - String region = DiscoveryManager.getInstance().getEurekaClientConfig().getRegion(); - client.setEndpoint("autoscaling."+ region + ".amazonaws.com"); - timer.schedule(getASGUpdateTask(), - eurekaConfig.getASGUpdateIntervalMs(), - eurekaConfig.getASGUpdateIntervalMs()); - - try { - - Monitors.registerObject(this); - - } catch (Throwable e) { - logger.warn("Cannot register the JMX monitor :", e); - } - } - - public static AwsAsgUtil getInstance() { - return awsAsgUtil; - } - - /** - * Return the status of the ASG whether is enabled or disabled for service. - * The value is picked up from the cache except the very first time. - * - * @param asgName - * - The name of the ASG - * @return - true if enabled, false otherwise - */ - public boolean isASGEnabled(String asgName) { - try { - return asgCache.get(asgName); - } catch (ExecutionException e) { - logger.error("Error getting cache value for asg : " + asgName, e); - } - return true; - } - - /** - * Sets the status of the ASG - * - * @param asgName - * - The name of the ASG - * @param enabled - * - true to enable, false to disable - */ - public void setStatus(String asgName, boolean enabled) { - asgCache.put(asgName, enabled); - } - - /** - * Check if the ASG is disabled. The amazon flag "AddToLoadBalancer" is - * queried to figure out if it is or not. - * - * @param asgName - * - The name of the ASG for which the status needs to be queried - * @return - true if the ASG is disabled, false otherwise - */ - private boolean isAddToLoadBalancerSuspended(String asgName) { - AutoScalingGroup asg = retrieveAutoScalingGroup(asgName); - if (asg == null) { - logger.warn( - "The ASG information for {} could not be found. So returning false.", - asgName); - return false; - } - return isAddToLoadBalancerSuspended(asg); - } - - /** - * Checks if the load balancer addition is disabled or not. - * - * @param asg - * - The ASG object for which the status needs to be checked - * @return - true, if the load balancer addition is suspended, false - * otherwise. - */ - private boolean isAddToLoadBalancerSuspended(AutoScalingGroup asg) { - List suspendedProcesses = asg.getSuspendedProcesses(); - for (SuspendedProcess process : suspendedProcesses) { - if (PROP_ADD_TO_LOAD_BALANCER.equals(process.getProcessName())) { - return true; - } - } - return false; - } - - /** - * Queries AWS to get the autoscaling information given the asgName. - * - * @param asgName - * - The name of the ASG. - * @return - The auto scaling group information. - */ - private AutoScalingGroup retrieveAutoScalingGroup(String asgName) { - // You can pass one name or a list of names in the request - DescribeAutoScalingGroupsRequest request = new DescribeAutoScalingGroupsRequest() - .withAutoScalingGroupNames(asgName); - DescribeAutoScalingGroupsResult result = client - .describeAutoScalingGroups(request); - List asgs = result.getAutoScalingGroups(); - if (asgs.isEmpty()) { - return null; - } else { - return asgs.get(0); - } - } - - /** - * Queries AWS to see if the load balancer flag is suspended. - * - * @param key - * - The name of the ASG for which the flag needs to be checked. - * @return - true, if the load balancer falg is not suspended, false - * otherwise. - */ - private Boolean isASGEnabledinAWS(Object key) { - String myKey = (String) key; - try { - Stopwatch t = Monitors.newTimer("Discovery:loadASGInfo").start(); - boolean returnValue = !isAddToLoadBalancerSuspended(myKey); - t.stop(); - return returnValue; - } catch (Throwable e) { - logger.error("Could not get ASG information from AWS: ", e); - } - return Boolean.TRUE; - } - - /** - * Gets the number of elements in the ASG cache. - * - * @return the long value representing the number of elements in the ASG - * cache. - */ - @com.netflix.servo.annotations.Monitor(name = "numOfElementsinASGCache", description = "Number of elements in the ASG Cache", type = DataSourceType.GAUGE) - public long getNumberofElementsinASGCache() { - return asgCache.size(); - } - - /** - * Gets the number of ASG queries done in the period. - * - * @return the long value representing the number of ASG queries done in the - * period. - */ - @com.netflix.servo.annotations.Monitor(name = "numOfASGQueries", description = "Number of queries made to AWS to retrieve ASG information", type = DataSourceType.COUNTER) - public long getNumberofASGQueries() { - return asgCache.stats().loadCount(); - } - - /** - * Gets the number of ASG queries that failed because of some reason. - * - * @return the long value representing the number of ASG queries that failed - * because of some reason. - */ - @com.netflix.servo.annotations.Monitor(name = "numOfASGQueryFailures", description = "Number of queries made to AWS to retrieve ASG information and that failed", type = DataSourceType.COUNTER) - public long getNumberofASGQueryFailures() { - return asgCache.stats().loadExceptionCount(); - } - - /** - * Gets the task that updates the ASG information periodically. - * - * @return TimerTask that updates the ASG information periodically. - */ - private TimerTask getASGUpdateTask() { - return new TimerTask() { - - @Override - public void run() { - try { - // First get the active ASG names - Set asgNames = getASGNames(); - logger.debug("Trying to refresh the keys for {}", - Arrays.toString(asgNames.toArray())); - for (String key : asgNames) { - try { - asgCache.refresh(key); - } catch (Throwable e) { - logger.error("Error updating the ASG cache for " - + key, e); - } - - } - - } catch (Throwable e) { - logger.error("Error updating the ASG cache", e); - } - - } - - }; - } - - /** - * Get the names of all the ASG to which query AWS for. - * - *

- * The names are obtained from the {@link InstanceRegistry} which is then - * used for querying the AWS. - *

- * - * @return the set of ASG names. - */ - private Set getASGNames() { - Set asgNames = new HashSet(); - Applications apps = PeerAwareInstanceRegistry.getInstance() - .getApplications(); - for (Application app : apps.getRegisteredApplications()) { - for (InstanceInfo instanceInfo : app.getInstances()) { - String asgName = instanceInfo.getASGName(); - if (asgName != null) { - asgNames.add(asgName); - } - } - - } - return asgNames; - } - -} \ No newline at end of file diff --git a/eureka-core/src/main/java/com/netflix/discovery/util/EIPManager.java b/eureka-core/src/main/java/com/netflix/discovery/util/EIPManager.java deleted file mode 100644 index 330afcfd4..000000000 --- a/eureka-core/src/main/java/com/netflix/discovery/util/EIPManager.java +++ /dev/null @@ -1,316 +0,0 @@ -/* - * Copyright 2012 Netflix, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.netflix.discovery.util; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.amazonaws.auth.BasicAWSCredentials; -import com.amazonaws.services.ec2.AmazonEC2; -import com.amazonaws.services.ec2.AmazonEC2Client; -import com.amazonaws.services.ec2.model.AssociateAddressRequest; -import com.amazonaws.services.ec2.model.DisassociateAddressRequest; -import com.netflix.appinfo.AmazonInfo; -import com.netflix.appinfo.AmazonInfo.MetaDataKey; -import com.netflix.appinfo.ApplicationInfoManager; -import com.netflix.appinfo.DataCenterInfo.Name; -import com.netflix.appinfo.InstanceInfo; -import com.netflix.discovery.DiscoveryManager; -import com.netflix.discovery.EurekaServerConfig; -import com.netflix.discovery.EurekaServerConfigurationManager; -import com.netflix.discovery.PeerAwareInstanceRegistry; -import com.netflix.discovery.shared.Application; -import com.netflix.servo.monitor.Monitors; - -/** - * An AWS specific elastic ip binding utility for binding eureka - * servers for a well known IP address. - * - *

- * Eureka clients talk to Eureka servers bound with well known - * IP addresses since that is the most reliable mechanism to - * discover the Eureka servers. When Eureka servers come up they bind - * themselves to a well known elastic ip - *

- * - *

- * This binding mechanism gravitates towards one eureka server per zone for - * resilience.Atleast one elastic ip should be slotted for each eureka server in - * a zone. If more than eureka server is launched per zone and there are not - * enough elastic ips slotted, the ips keeps switching back and forth between - * the eureka servers in the zone. - *

- * - * @author Karthik Ranganathan, Greg Kim - * - */ -public class EIPManager { - private static final String US_EAST_1 = "us-east-1"; - // private static final String PROP_EIP = "netflix.discovery.eip."; - private static final Logger logger = LoggerFactory - .getLogger(EIPManager.class); - private EurekaServerConfig eurekaConfig = EurekaServerConfigurationManager - .getInstance().getConfiguration(); - - private static final EIPManager s_instance = new EIPManager(); - - public static EIPManager getInstance() { - return s_instance; - } - - private EIPManager() { - try { - - Monitors.registerObject(this); - - } catch (Throwable e) { - logger.warn( - "Cannot register the JMX monitor for the InstanceRegistry :", - e); - } - } - - /** - * Binds an EIP to this instance. if an EIP is already bound to this - * instance this method simply returns. Otherwise, this method tries to find - * an unused EIP based on the registry information. If it cannot find any - * unused EIP this method simply picks an EIP of an instance with the - * earliest registration timestamp. - * - */ - public void bindToEIP() { - InstanceInfo myInfo = ApplicationInfoManager.getInstance().getInfo(); - String myInstanceId = ((AmazonInfo) myInfo.getDataCenterInfo()) - .get(MetaDataKey.instanceId); - String myZone = ((AmazonInfo) myInfo.getDataCenterInfo()) - .get(MetaDataKey.availabilityZone); - String myPublicIP = ((AmazonInfo) myInfo.getDataCenterInfo()) - .get(MetaDataKey.publicIpv4); - - String selectedEIP = getCandidateEIP(myInstanceId, myZone, myPublicIP); - - if (selectedEIP == null) { - // The EIP is already bound to this instance - logger.debug("No need to bind to EIP"); - return; - } else { - try { - AmazonEC2 ec2Service = getEC2Service(); - AssociateAddressRequest request = new AssociateAddressRequest( - myInstanceId, selectedEIP); - ec2Service.associateAddress(request); - logger.info("\n\n\nAssociated " + myInstanceId - + " running in zone: " + myZone + " to elastic IP: " - + selectedEIP); - } catch (Throwable t) { - throw new RuntimeException("Failed to bind elastic IP: " - + selectedEIP + " to " + myInstanceId, t); - } - } - } - - /** - * Unbind the EIP that this instance is associated with. - */ - public void unbindEIP() { - InstanceInfo myInfo = ApplicationInfoManager.getInstance().getInfo(); - String myPublicIP = null; - if (myInfo != null - && myInfo.getDataCenterInfo().getName() == Name.Amazon) { - myPublicIP = ((AmazonInfo) myInfo.getDataCenterInfo()) - .get(MetaDataKey.publicIpv4); - try { - AmazonEC2 ec2Service = getEC2Service(); - DisassociateAddressRequest dissociateRequest = new DisassociateAddressRequest() - .withPublicIp(myPublicIP); - ec2Service.disassociateAddress(dissociateRequest); - logger.info("Dissociated the EIP {} from this instance", - myPublicIP); - } catch (Throwable e) { - throw new RuntimeException("Cannot dissociate address" - + myPublicIP + "from this instance", e); - } - } - - } - - /** - * Get the EIP for this instance to bind to. - * - *

- * if an EIP is already bound to this instance this method simply returns. - * Otherwise, this method tries to find an unused EIP based on the registry - * information. If it cannot find any unused EIP this method simply picks an - * EIP of an instance with the earliest registration timestamp. - *

- * - * @param myInstanceId - * the instance id for this instance - * @param myZone - * the zone where this instance is in. - * @param myPublicIP - * the public ip of this instance - * @return null if the EIP is already bound, valid EIP otherwise. - */ - public String getCandidateEIP(String myInstanceId, String myZone, - String myPublicIP) { - - if (myZone == null) { - myZone = "us-east-1d"; - myPublicIP = "us-east-1d"; - } - Collection eipCandidates = (DiscoveryManager.getInstance() - .getEurekaClientConfig().shouldUseDnsForFetchingServiceUrls() ? getEIPsForZoneFromDNS(myZone) - : getEIPsForZoneFromConfig(myZone)); - - if (eipCandidates == null || eipCandidates.size() == 0) { - throw new RuntimeException( - "Could not get any elastic ips from the EIP pool for zone :" - + myZone); - } - List availableEIPList = new ArrayList(); - for (String eip : eipCandidates) { - String eipTrimmed = eip.trim(); - if (myPublicIP.equals(eipTrimmed)) { - // Already associated to an EIP? - logger.debug("Already bound to an EIP : " + eip); - return null; - } - availableEIPList.add(eipTrimmed); - } - // Look for unused EIPs - InstanceInfo instanceInfo = ApplicationInfoManager.getInstance() - .getInfo(); - Application app = PeerAwareInstanceRegistry.getInstance() - .getApplication(instanceInfo.getAppName()); - - if (app != null) { - for (InstanceInfo i : app.getInstances()) { - AmazonInfo amazonInfo = (AmazonInfo) i.getDataCenterInfo(); - String publicIP = amazonInfo.get(MetaDataKey.publicIpv4); - String instanceId = amazonInfo.get(MetaDataKey.instanceId); - if ((instanceId - .equals(myInstanceId)) - && (availableEIPList.contains(publicIP))) { - // This can happen if the server restarts and we haven't - // fully been dissociated with the previous shutdown - logger.warn( - "The instance id {} is already bound to EIP {}. Hence returning that.", - myInstanceId, publicIP); - return publicIP; - } - for (Iterator it = availableEIPList.iterator(); it.hasNext(); ) { - String eip = it.next(); - // if there is already an EIP association, remove it from the list - if (eip.trim().equals(publicIP)) { - logger.info("Removing the EIP {} as it is already used by instance {}", eip, instanceId); - it.remove(); - } - } - } - } - if (availableEIPList == null || availableEIPList.isEmpty()) { - throw new RuntimeException("Cannot find a free EIP to bind"); - } - return eipCandidates.iterator().next(); - } - - /** - * Get the list of EIPs from the configuration. - * - * @param myZone - * - the zone in which the instance resides. - * @return collection of EIPs to choose from for binding. - */ - private Collection getEIPsForZoneFromConfig(String myZone) { - List ec2Urls = DiscoveryManager.getInstance() - .getEurekaClientConfig().getEurekaServerServiceUrls(myZone); - return getEIPsFromServiceUrls(ec2Urls); - } - - /** - * Get the list of EIPs from the ec2 urls. - * - * @param ec2Urls - * the ec2urls for which the EIP needs to be obtained. - * @return collection of EIPs. - */ - private Collection getEIPsFromServiceUrls(List ec2Urls) { - List returnedUrls = new ArrayList(); - String region = DiscoveryManager.getInstance().getEurekaClientConfig().getRegion(); - String regionPhrase=""; - if (!US_EAST_1.equals(region)) { - regionPhrase = "." + region; - } - for (String cname : ec2Urls) { - int beginIndex = cname.indexOf("ec2-") + 4; - int endIndex = cname.indexOf(regionPhrase + ".compute"); - String eipStr = cname.substring(beginIndex, endIndex); - String eip = eipStr.replaceAll("\\-", "."); - returnedUrls.add(eip); - } - return returnedUrls; - } - - /** - * Get the list of EIPS from the DNS. - * - *

- * This mechanism looks for the EIP pool in the zone the instance is in by - * looking up the DNS name {zone}.{region}.{domainName}. The - * zone is fetched from the {@link InstanceInfo} object;the region is picked - * up from the specified configuration - * {@link EurekaServerConfig#getRegion()};the domain name is picked up from - * the specified configuration {@link EurekaServerConfig#getDomainName()}. - *

- * - * @param myZone - * the zone where this instance exist in. - * @return the collection of EIPs that exist in the zone this instance is - * in. - */ - private Collection getEIPsForZoneFromDNS(String myZone) { - List ec2Urls = DiscoveryManager.getInstance() - .getDiscoveryClient().getServiceUrlsFromDNS(myZone, true); - return getEIPsFromServiceUrls(ec2Urls); - } - - /** - * Gets the EC2 service object to call AWS APIs. - * - * @return the EC2 service object to call AWS APIs. - */ - private AmazonEC2 getEC2Service() { - eurekaConfig = EurekaServerConfigurationManager.getInstance() - .getConfiguration(); - AmazonEC2 ec2Service = new AmazonEC2Client(new BasicAWSCredentials( - eurekaConfig.getAWSAccessId(), eurekaConfig.getAWSSecretKey())); - - String region = DiscoveryManager.getInstance().getEurekaClientConfig() - .getRegion(); - region = region.trim().toLowerCase(); - ec2Service.setEndpoint("ec2." + region + ".amazonaws.com"); - return ec2Service; - } -} diff --git a/eureka-core/src/main/java/com/netflix/discovery/util/EurekaMonitors.java b/eureka-core/src/main/java/com/netflix/discovery/util/EurekaMonitors.java deleted file mode 100644 index aca08559f..000000000 --- a/eureka-core/src/main/java/com/netflix/discovery/util/EurekaMonitors.java +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Copyright 2012 Netflix, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.netflix.discovery.util; - -import java.util.concurrent.atomic.AtomicLong; - -import com.netflix.appinfo.AmazonInfo; -import com.netflix.appinfo.AmazonInfo.MetaDataKey; -import com.netflix.appinfo.ApplicationInfoManager; -import com.netflix.appinfo.DataCenterInfo; -import com.netflix.appinfo.DataCenterInfo.Name; -import com.netflix.servo.DefaultMonitorRegistry; -import com.netflix.servo.annotations.DataSourceType; -import com.netflix.servo.monitor.Monitors; - -/** - * The enum that encapsulates all statistics monitored by Eureka. - * - *

- * Eureka Monitoring is done using {@link https://github.com/Netflix/servo}. The - * users who wants to take advantage of the monitoring should read up on - * Servo - *

- * - * @author Karthik Ranganathan, Greg Kim - * - */ -public enum EurekaMonitors { - RENEW("renewCounter", "Number of total renews seen since startup"), CANCEL( - "cancelCounter", "Number of total cancels seen since startup"), GET_ALL_CACHE_MISS( - "getAllCacheMissCounter", - "Number of total registery queries seen since startup"), GET_ALL_CACHE_MISS_DELTA( - "getAllCacheMissDeltaCounter", - "Number of total registery queries for delta seen since startup"), GET_ALL_DELTA( - "getAllDeltaCounter", "Number of total deltas since startup"), GET_ALL( - "getAllCounter", - "Number of total registry queries seen since startup"), REGISTER( - "registerCounter", "Number of total registers seen since startup"), EXPIRED( - "expiredCounter", "Number of total expired leases since startup"), STATUS_UPDATE( - "statusUpdateCounter", - "Number of total admin status updates since startup"), CANCEL_NOT_FOUND( - "cancelNotFoundCounter", - "Number of total cancel requests on non-existing instance since startup"), RENEW_NOT_FOUND( - "renewNotFoundexpiredCounter", - "Number of total renew on non-existing instance since startup"), REJECTED_REPLICATIONS( - "numOfRejectedReplications", - "Number of replications rejected because of full queue"), FAILED_REPLICATIONS( - "numOfFailedReplications", - "Number of failed replications - likely from timeouts"); - - private final String name; - - private final String myZoneCounterName; - - private final String description; - - private EurekaMonitors(String name, String description) { - this.name = name; - this.description = description; - - DataCenterInfo dcInfo = ApplicationInfoManager.getInstance().getInfo() - .getDataCenterInfo(); - if (dcInfo.getName() == Name.Amazon) { - myZoneCounterName = ((AmazonInfo) dcInfo) - .get(MetaDataKey.availabilityZone) + "." + name; - } else { - myZoneCounterName = "dcmaster." + name; - } - } - - @com.netflix.servo.annotations.Monitor(name = "count", type = DataSourceType.COUNTER) - private final AtomicLong counter = new AtomicLong(); - - @com.netflix.servo.annotations.Monitor(name = "count-minus-replication", type = DataSourceType.COUNTER) - private final AtomicLong myZoneCounter = new AtomicLong(); - - /** - * Increment the counter for the given statistic. - */ - public void increment() { - increment(false); - } - - /** - * Increment the counter for the given statistic based on whether this is - * because of replication from other eureka servers or it is a eureka client - * initiated action. - * - * @param isReplication - * true if this a replication, false otherwise. - */ - public void increment(boolean isReplication) { - counter.incrementAndGet(); - - if (!isReplication) { - myZoneCounter.incrementAndGet(); - } - } - - /** - * Gets the statistic name of this monitor. - * - * @return the statistic name. - */ - public String getName() { - return name; - } - - /** - * Gets the zone specific statistic name of this monitor. Applies only for - * AWS cloud. - * - * @return the zone specific statistic name. - */ - public String getZoneSpecificName() { - return myZoneCounterName; - } - - /** - * Gets the description of this statistic means. - * - * @return the description of this statistic means. - */ - public String getDescription() { - return description; - } - - /** - * Gets the actual counter value for this statistic. - * - * @return the long value representing the number of times this statistic - * has occurred. - */ - public long getCount() { - return counter.get(); - } - - /** - * Gets the zone specific counter value for this statistic. This is - * application only for AWS cloud environment. - * - * @return the long value representing the number of times this statistic - * has occurred. - */ - public long getZoneSpecificCount() { - return myZoneCounter.get(); - } - - /** - * Register all statistics with Servo. - */ - public static void registerAllStats() { - for (EurekaMonitors c : EurekaMonitors.values()) { - Monitors.registerObject(c.getName(), c); - } - } - - /** - * Unregister all statistics from Servo. - */ - public static void shutdown() { - for (EurekaMonitors c : EurekaMonitors.values()) { - DefaultMonitorRegistry.getInstance().unregister( - Monitors.newObjectMonitor(c.name(), c)); - } - } -} diff --git a/eureka-core/src/main/java/com/netflix/discovery/util/MeasuredRate.java b/eureka-core/src/main/java/com/netflix/discovery/util/MeasuredRate.java deleted file mode 100644 index fd37a9fef..000000000 --- a/eureka-core/src/main/java/com/netflix/discovery/util/MeasuredRate.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright 2012 Netflix, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.netflix.discovery.util; - -import java.util.Timer; -import java.util.TimerTask; -import java.util.concurrent.atomic.AtomicLong; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Utility class for getting a count in last X milliseconds - * - * @author Karthik Ranganathan,Greg Kim - */ -public class MeasuredRate { - private static final Logger logger = LoggerFactory - .getLogger(MeasuredRate.class); - private final AtomicLong lastBucket = new AtomicLong(0); - private final AtomicLong currentBucket = new AtomicLong(0); - private final long sampleInterval; - private Timer timer = new Timer("Eureka-MeasureRateTimer", true); - - /** - * @param sampleInterval - * in milliseconds - */ - public MeasuredRate(long sampleInterval) { - this.sampleInterval = sampleInterval; - timer.schedule(new TimerTask() { - - @Override - public void run() { - try { - // Zero out the current bucket. - lastBucket.set(currentBucket.getAndSet(0)); - } catch (Throwable e) { - logger.error("Cannot reset the Measured Rate", e); - } - } - }, sampleInterval, sampleInterval); - } - - /** - * Returns the count in the last sample interval. - */ - public long getCount() { - return lastBucket.get(); - } - - /** - * Increments the count in the current sample interval. - */ - public void increment() { - currentBucket.incrementAndGet(); - } -} diff --git a/eureka-core/src/main/java/com/netflix/discovery/util/StatusInfo.java b/eureka-core/src/main/java/com/netflix/discovery/util/StatusInfo.java deleted file mode 100644 index 31ee89115..000000000 --- a/eureka-core/src/main/java/com/netflix/discovery/util/StatusInfo.java +++ /dev/null @@ -1,139 +0,0 @@ -package com.netflix.discovery.util; - -import java.lang.management.ManagementFactory; -import java.text.DecimalFormat; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.HashMap; -import java.util.Map; - -import com.netflix.appinfo.ApplicationInfoManager; -import com.netflix.appinfo.InstanceInfo; -import com.netflix.config.ConfigurationManager; -import com.netflix.discovery.provider.Serializer; -import com.thoughtworks.xstream.annotations.XStreamAlias; -import com.thoughtworks.xstream.annotations.XStreamOmitField; - -/** - * An utility class for exposing status information of an instance. - * - * @author Greg Kim - */ -@Serializer("com.netflix.discovery.converters.EntityBodyConverter") -@XStreamAlias("status") -public class StatusInfo { - private final static String DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss Z"; - - public static final class Builder { - - @XStreamOmitField - private StatusInfo result; - - private Builder() { - result = new StatusInfo(); - } - - public static Builder newBuilder() { - return new Builder(); - } - - public Builder isHealthy(boolean b) { - result.isHeathly = Boolean.valueOf(b); - return this; - } - - /** - * Add any application specific status data. - */ - public Builder add(String key, String value) { - if (result.applicationStats == null) { - result.applicationStats = new HashMap(); - } - result.applicationStats.put(key, value); - return this; - } - - /** - * Build the {@link StatusInfo}. General information are automatically - * built here too. - */ - public StatusInfo build() { - result.generalStats.put("server-uptime", getUpTime()); - result.generalStats.put("environment", ConfigurationManager - .getDeploymentContext().getDeploymentEnvironment()); - - Runtime runtime = Runtime.getRuntime(); - int totalMem = (int) (runtime.totalMemory() / 1048576); - int freeMem = (int) (runtime.freeMemory() / 1048576); - int usedPercent = (int) (((float) totalMem - freeMem) / (totalMem) * 100.0); - - result.generalStats.put("num-of-cpus", - String.valueOf(runtime.availableProcessors())); - result.generalStats.put("total-avail-memory", - String.valueOf(totalMem) + "mb"); - result.generalStats.put("current-memory-usage", - String.valueOf(totalMem - freeMem) + "mb" + " (" - + usedPercent + "%)"); - - result.instanceInfo = ApplicationInfoManager.getInstance() - .getInfo(); - - return result; - } - } - - private Map generalStats = new HashMap(); - private Map applicationStats; - private InstanceInfo instanceInfo; - private Boolean isHeathly; - - private StatusInfo() { - } - - public InstanceInfo getInstanceInfo() { - return instanceInfo; - } - - public boolean isHealthy() { - return isHeathly.booleanValue(); - } - - public Map getGeneralStats() { - return generalStats; - } - - public Map getApplicationStats() { - return applicationStats; - } - - /** - * Output the amount of time that has elapsed since the given date in the - * format x days, xx:xx. - * - * @return A string representing the formatted interval. - */ - public static String getUpTime() { - long diff = ManagementFactory.getRuntimeMXBean().getUptime(); - diff /= 1000 * 60; - long minutes = diff % 60; - diff /= 60; - long hours = diff % 24; - diff /= 24; - long days = diff; - StringBuilder buf = new StringBuilder(); - if (days == 1) - buf.append("1 day "); - else if (days > 1) - buf.append(Long.valueOf(days).toString()).append(" days "); - DecimalFormat format = new DecimalFormat(); - format.setMinimumIntegerDigits(2); - buf.append(format.format(hours)).append(":") - .append(format.format(minutes)); - return buf.toString(); - } - - public static String getCurrentTimeAsString() { - SimpleDateFormat format = new SimpleDateFormat(DATE_FORMAT); - return format.format(new Date()); - } -} diff --git a/eureka-server/main/conf/eureka-client-prod.properties b/eureka-server/main/conf/eureka-client-prod.properties deleted file mode 100644 index 14e58718b..000000000 --- a/eureka-server/main/conf/eureka-client-prod.properties +++ /dev/null @@ -1,14 +0,0 @@ -eureka.us-east-1.availabilityZones=us-east-1c,us-east-1d,us-east-1e -eureka.serviceUrl.us-east-1c=http://ec2-204-236-228-165.compute-1.amazonaws.com:7001/discovery/v2/,http://ec2-75-101-165-111.compute-1.amazonaws.com:7001/discovery/v2/ -eureka.serviceUrl.us-east-1d=http://ec2-204-236-228-170.compute-1.amazonaws.com:7001/discovery/v2/ -eureka.serviceUrl.us-east-1e=http://ec2-50-19-255-91.compute-1.amazonaws.com:7001/discovery/v2/ - -eureka.us-west-1.availabilityZones=us-west-1a,us-west-1b,us-west-1c -eureka.serviceUrl.us-west-1a=http://ec2-50-18-51-248.us-west-1.compute.amazonaws.com:7001/discovery/v2/ -eureka.serviceUrl.us-west-1b=http://ec2-50-18-51-249.us-west-1.compute.amazonaws.com:7001/discovery/v2/ -eureka.serviceUrl.us-west-1c=http://ec2-50-18-51-250.us-west-1.compute.amazonaws.com:7001/discovery/v2/ - -eureka.eu-west-1.availabilityZones=eu-west-1a,eu-west-1b,eu-west-1c -eureka.serviceUrl.eu-west-1a=http://ec2-46-137-103-193.eu-west-1.compute.amazonaws.com:7001/discovery/v2/ -eureka.serviceUrl.eu-west-1b=http://ec2-46-137-103-199.eu-west-1.compute.amazonaws.com:7001/discovery/v2/ -eureka.serviceUrl.eu-west-1c=http://ec2-46-137-103-212.eu-west-1.compute.amazonaws.com:7001/discovery/v2/ \ No newline at end of file diff --git a/eureka-server/main/conf/eureka-client-test.properties b/eureka-server/main/conf/eureka-client-test.properties deleted file mode 100644 index 42711f726..000000000 --- a/eureka-server/main/conf/eureka-client-test.properties +++ /dev/null @@ -1,20 +0,0 @@ - -#Availability zones with the format eureka..availabilityZones, -eureka.us-east-1.availabilityZones=us-east-1c,us-east-1d,us-east-1e - -#Service urls for eureka server in each zone -eureka.serviceUrl.us-east-1c=http://ec2-552-627-568-165.compute-1.amazonaws.com:7001/discovery/v2/,http://ec2-168-101-182-134.compute-1.amazonaws.com:7001/discovery/v2/ -eureka.serviceUrl.us-east-1d=http://ec2-552-627-568-170.compute-1.amazonaws.com:7001/discovery/v2/ -eureka.serviceUrl.us-east-1e=http://ec2-50-179-285-592.compute-1.amazonaws.com:7001/discovery/v2/ - -#Availability zones and serviceUrls for us-west-1 region -eureka.us-west-1.availabilityZones=us-west-1a,us-west-1b,us-west-1c -eureka.serviceUrl.us-west-1a=http://ec2-67-45-89-248.us-west-1.compute.amazonaws.com:7001/discovery/v2/ -eureka.serviceUrl.us-west-1b=http://ec2-67-45-89-249.us-west-1.compute.amazonaws.com:7001/discovery/v2/ -eureka.serviceUrl.us-west-1c=http://ec2-67-45-89-250.us-west-1.compute.amazonaws.com:7001/discovery/v2/ - -#Availability zones and serviceUrls for eu-west-1 region -eureka.eu-west-1.availabilityZones=eu-west-1a,eu-west-1b,eu-west-1c -eureka.serviceUrl.eu-west-1a=http://ec2-59-78-75-193.eu-west-1.compute.amazonaws.com:7001/discovery/v2/ -eureka.serviceUrl.eu-west-1b=http://ec2-59-78-75-199.eu-west-1.compute.amazonaws.com:7001/discovery/v2/ -eureka.serviceUrl.eu-west-1c=http://ec2-59-78-75-212.eu-west-1.compute.amazonaws.com:7001/discovery/v2/ diff --git a/eureka-server/main/conf/eureka-client.properties b/eureka-server/main/conf/eureka-client.properties deleted file mode 100644 index 1b6de92b4..000000000 --- a/eureka-server/main/conf/eureka-client.properties +++ /dev/null @@ -1,26 +0,0 @@ -## -#Properties based configuration for eureka client. The properties specified here is mostly what the users -#need to change. All of these can be specified as a java system property with -D option (eg)-Deureka.region=us-east-1 -#For additional tuning options refer - - -#Region where eureka is deployed -For AWS specify one of the AWS regions, for other datacenters specify a arbitrary string -#indicating the region.This is normally specified as a -D option (eg) -Deureka.region=us-east-1 -eureka.region=us-east-1 - -#Name of the application to be identified by other services - -eureka.name=eureka - -#Virtual host name by which the clients identifies this service -eureka.vipAddress=eureka.mydomain.net - -#Http port where eureka server will be running -eureka.port=80 - -#For eureka clients running in eureka server, it needs to connect to servers in other zones -eureka.preferSameZone=false - -#Change this if you want to use a DNS based lookup for determining other eureka servers. For example -#of specifying the DNS entries, check the eureka-client-test.properties, eureka-client-prod.properties -eureka.shouldUseDns=false diff --git a/eureka-server/main/conf/eureka-server-prod.properties b/eureka-server/main/conf/eureka-server-prod.properties deleted file mode 100644 index b8c72e5f0..000000000 --- a/eureka-server/main/conf/eureka-server-prod.properties +++ /dev/null @@ -1,5 +0,0 @@ -#Specific AWS access key and Id with the right access permissions to query the Amazon autoscaling info. -#This is only needed if you need to query ASG information to disable/enable your instance on launch -eureka.awsAccessId=ADIIEIFIFPFIKC -eureka.awsSecretKey=dieuilfkfoioljhjhjuTRoIiijc - diff --git a/eureka-server/main/conf/eureka-server-test.properties b/eureka-server/main/conf/eureka-server-test.properties deleted file mode 100644 index a506b62e0..000000000 --- a/eureka-server/main/conf/eureka-server-test.properties +++ /dev/null @@ -1,4 +0,0 @@ -#Specific AWS access key and Id with the right access permissions to query the Amazon autoscaling info. -#This is only needed if you need to query ASG information to disable/enable your instance on launch -eureka.awsAccessId=ADIIEIFIFPFIKC -eureka.awsSecretKey=dieuilfkfoioljhjhjuTRoIiijc diff --git a/eureka-server/main/conf/eureka-server.properties b/eureka-server/main/conf/eureka-server.properties deleted file mode 100644 index a506b62e0..000000000 --- a/eureka-server/main/conf/eureka-server.properties +++ /dev/null @@ -1,4 +0,0 @@ -#Specific AWS access key and Id with the right access permissions to query the Amazon autoscaling info. -#This is only needed if you need to query ASG information to disable/enable your instance on launch -eureka.awsAccessId=ADIIEIFIFPFIKC -eureka.awsSecretKey=dieuilfkfoioljhjhjuTRoIiijc diff --git a/eureka-server/main/conf/log4j.properties b/eureka-server/main/conf/log4j.properties deleted file mode 100644 index be1079244..000000000 --- a/eureka-server/main/conf/log4j.properties +++ /dev/null @@ -1,4 +0,0 @@ -log4j.rootCategory=INFO,stdout -log4j.appender.stdout=org.apache.log4j.ConsoleAppender -log4j.appender.stdout.layout=org.apache.log4j.PatternLayout -log4j.appender.stdout.layout.ConversionPattern=%d %-5p %C:%L [%t] [%M] %m%n