erueka的几个特性
1.register 方法的源码,打开eureka-client-1.9.3.jar包下面的DiscoveryClient类
先进入initScheduledTasks,有个instanceInfoReplicator 加载
scheduler = Executors.newScheduledThreadPool(2,
new ThreadFactoryBuilder()
.setNameFormat("DiscoveryClient-%d")
.setDaemon(true)
.build()); //2分钟的定时调度任务,设置为守护线程
heartbeatExecutor = new ThreadPoolExecutor(
1, clientConfig.getHeartbeatExecutorThreadPoolSize(), 0, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(),
new ThreadFactoryBuilder()
.setNameFormat("DiscoveryClient-HeartbeatExecutor-%d")
.setDaemon(true)
.build()
); // 建立个心跳机制
private void initScheduledTasks()
{
if (this.clientConfig.shouldFetchRegistry())
{
int registryFetchIntervalSeconds = this.clientConfig.getRegistryFetchIntervalSeconds();
int expBackOffBound = this.clientConfig.getCacheRefreshExecutorExponentialBackOffBound();
this.scheduler.schedule(new TimedSupervisorTask("cacheRefresh", this.scheduler, this.cacheRefreshExecutor, registryFetchIntervalSeconds, TimeUnit.SECONDS, expBackOffBound, new CacheRefreshThread()), registryFetchIntervalSeconds, TimeUnit.SECONDS);
}
if (this.clientConfig.shouldRegisterWithEureka())
{
int renewalIntervalInSecs = this.instanceInfo.getLeaseInfo().getRenewalIntervalInSecs();
int expBackOffBound = this.clientConfig.getHeartbeatExecutorExponentialBackOffBound();
logger.info("Starting heartbeat executor: renew interval is: {}", Integer.valueOf(renewalIntervalInSecs));
this.scheduler.schedule(new TimedSupervisorTask("heartbeat", this.scheduler, this.heartbeatExecutor, renewalIntervalInSecs, TimeUnit.SECONDS, expBackOffBound, new HeartbeatThread(null)), renewalIntervalInSecs, TimeUnit.SECONDS);//心跳机制
this.instanceInfoReplicator = new InstanceInfoReplicator(this, this.instanceInfo, this.clientConfig.getInstanceInfoReplicationIntervalSeconds(), 2);
this.statusChangeListener = new ApplicationInfoManager.StatusChangeListener()
{
public String getId()
{
return "statusChangeListener";
}
public void notify(StatusChangeEvent statusChangeEvent)
{
if ((InstanceInfo.InstanceStatus.DOWN == statusChangeEvent.getStatus()) ||
(InstanceInfo.InstanceStatus.DOWN == statusChangeEvent.getPreviousStatus())) {
DiscoveryClient.logger.warn("Saw local status change event {}", statusChangeEvent);
} else {
DiscoveryClient.logger.info("Saw local status change event {}", statusChangeEvent);
}
DiscoveryClient.this.instanceInfoReplicator.onDemandUpdate();
}
};
if (this.clientConfig.shouldOnDemandUpdateStatusChange()) {
this.applicationInfoManager.registerStatusChangeListener(this.statusChangeListener);
}
this.instanceInfoReplicator.start(this.clientConfig.getInitialInstanceInfoReplicationIntervalSeconds());
}
else
{
logger.info("Not registering with Eureka server per configuration");
}
}
public void run()
{
try
{
this.discoveryClient.refreshInstanceInfo();
Long dirtyTimestamp = this.instanceInfo.isDirtyWithTime();
if (dirtyTimestamp != null)
{
this.discoveryClient.register();//调用注册
this.instanceInfo.unsetIsDirty(dirtyTimestamp.longValue());
}
}
catch (Throwable t)
{
Future next;
logger.warn("There was a problem with the instance info replicator", t);
}
finally
{
Future next;
Future next = this.scheduler.schedule(this, this.replicationIntervalSeconds, TimeUnit.SECONDS);
this.scheduledPeriodicRef.set(next);
}
}
}
boolean register()
throws Throwable
{
logger.info("DiscoveryClient_{}: registering service...", this.appPathIdentifier);
try
{
httpResponse = this.eurekaTransport.registrationClient.register(this.instanceInfo);
}
catch (Exception e)
{
EurekaHttpResponse<Void> httpResponse;
logger.warn("DiscoveryClient_{} - registration failed {}", new Object[] { this.appPathIdentifier, e.getMessage(), e });
throw e;
}
EurekaHttpResponse<Void> httpResponse;
if (logger.isInfoEnabled()) {
logger.info("DiscoveryClient_{} - registration status: {}", this.appPathIdentifier, Integer.valueOf(httpResponse.getStatusCode()));
}
return httpResponse.getStatusCode() == 204;
}
因为client端向server发送HTTP请求,所以我们继续看eureka-core-1.9.3.jar的注册,如何注册
protected void initEurekaServerContext()
throws Exception
{
EurekaServerConfig eurekaServerConfig = new DefaultEurekaServerConfig();
JsonXStream.getInstance().registerConverter(new V1AwareInstanceInfoConverter(), 10000);
XmlXStream.getInstance().registerConverter(new V1AwareInstanceInfoConverter(), 10000);
logger.info("Initializing the eureka client...");
logger.info(eurekaServerConfig.getJsonCodecName());
ServerCodecs serverCodecs = new DefaultServerCodecs(eurekaServerConfig);
ApplicationInfoManager applicationInfoManager = null;
if (this.eurekaClient == null)
{
EurekaInstanceConfig instanceConfig = isCloud(ConfigurationManager.getDeploymentContext()) ? new CloudInstanceConfig() : new MyDataCenterInstanceConfig();
applicationInfoManager = new ApplicationInfoManager(instanceConfig, new EurekaConfigBasedInstanceInfoProvider(instanceConfig).get());
EurekaClientConfig eurekaClientConfig = new DefaultEurekaClientConfig();
this.eurekaClient = new DiscoveryClient(applicationInfoManager, eurekaClientConfig);
}
else
{
applicationInfoManager = this.eurekaClient.getApplicationInfoManager();
}
PeerAwareInstanceRegistry registry;
if (isAws(applicationInfoManager.getInfo()))
{
PeerAwareInstanceRegistry registry = new AwsInstanceRegistry(eurekaServerConfig, this.eurekaClient.getEurekaClientConfig(), serverCodecs, this.eurekaClient);
this.awsBinder = new AwsBinderDelegate(eurekaServerConfig, this.eurekaClient.getEurekaClientConfig(), registry, applicationInfoManager);
this.awsBinder.start();
}
else
{
registry = new PeerAwareInstanceRegistryImpl(eurekaServerConfig, this.eurekaClient.getEurekaClientConfig(), serverCodecs, this.eurekaClient);
}
PeerEurekaNodes peerEurekaNodes = getPeerEurekaNodes(registry, eurekaServerConfig, this.eurekaClient
.getEurekaClientConfig(), serverCodecs, applicationInfoManager);
this.serverContext = new DefaultEurekaServerContext(eurekaServerConfig, serverCodecs, registry, peerEurekaNodes, applicationInfoManager);
EurekaServerContextHolder.initialize(this.serverContext);
this.serverContext.initialize();
logger.info("Initialized server context");
int registryCount = registry.syncUp();
registry.openForTraffic(applicationInfoManager, registryCount);
EurekaMonitors.registerAllStats();
}
PeerAwareInstanceRegistryImpl类里
public void register(InstanceInfo info, boolean isReplication)
{
int leaseDuration = 90;
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);
}
PeerAwareInstanceRegistryImpl 继承了AbstractInstanceRegistry
public void register(InstanceInfo registrant, int leaseDuration, boolean isReplication)
{
try
{
this.read.lock();
Map<String, Lease<InstanceInfo>> gMap = (Map)this.registry.get(registrant.getAppName());
EurekaMonitors.REGISTER.increment(isReplication);
if (gMap == null)
{
ConcurrentHashMap<String, Lease<InstanceInfo>> gNewMap = new ConcurrentHashMap();
gMap = (Map)this.registry.putIfAbsent(registrant.getAppName(), gNewMap);
if (gMap == null) {
gMap = gNewMap;
}
}
Lease<InstanceInfo> existingLease = (Lease)gMap.get(registrant.getId());
if ((existingLease != null) && (existingLease.getHolder() != null))
{
Long existingLastDirtyTimestamp = ((InstanceInfo)existingLease.getHolder()).getLastDirtyTimestamp();
Long registrationLastDirtyTimestamp = registrant.getLastDirtyTimestamp();
logger.debug("Existing lease found (existing={}, provided={}", existingLastDirtyTimestamp, registrationLastDirtyTimestamp);
if (existingLastDirtyTimestamp.longValue() > registrationLastDirtyTimestamp.longValue())
{
logger.warn("There is an existing lease and the existing lease's dirty timestamp {} is greater than the one that is being registered {}", existingLastDirtyTimestamp, registrationLastDirtyTimestamp);
logger.warn("Using the existing instanceInfo instead of the new instanceInfo as the registrant");
registrant = (InstanceInfo)existingLease.getHolder();
}
}
else
{
synchronized (this.lock)
{
if (this.expectedNumberOfRenewsPerMin > 0)
{
this.expectedNumberOfRenewsPerMin += 2;
this.numberOfRenewsPerMinThreshold = ((int)(this.expectedNumberOfRenewsPerMin * this.serverConfig.getRenewalPercentThreshold()));
}
}
logger.debug("No previous lease information found; it is new registration");
}
Lease<InstanceInfo> lease = new Lease(registrant, leaseDuration);
if (existingLease != null) {
lease.setServiceUpTimestamp(existingLease.getServiceUpTimestamp());
}
gMap.put(registrant.getId(), lease);
synchronized (this.recentRegisteredQueue)
{
this.recentRegisteredQueue.add(new Pair(
Long.valueOf(System.currentTimeMillis()), registrant
.getAppName() + "(" + registrant.getId() + ")"));
}
if (!InstanceInfo.InstanceStatus.UNKNOWN.equals(registrant.getOverriddenStatus()))
{
logger.debug("Found overridden status {} for instance {}. Checking to see if needs to be add to the overrides", registrant
.getOverriddenStatus(), registrant.getId());
if (!this.overriddenInstanceStatusMap.containsKey(registrant.getId()))
{
logger.info("Not found overridden id {} and hence adding it", registrant.getId());
this.overriddenInstanceStatusMap.put(registrant.getId(), registrant.getOverriddenStatus());
}
}
InstanceInfo.InstanceStatus overriddenStatusFromMap = (InstanceInfo.InstanceStatus)this.overriddenInstanceStatusMap.get(registrant.getId());
if (overriddenStatusFromMap != null)
{
logger.info("Storing overridden status {} from map", overriddenStatusFromMap);
registrant.setOverriddenStatus(overriddenStatusFromMap);
}
InstanceInfo.InstanceStatus overriddenInstanceStatus = getOverriddenInstanceStatus(registrant, existingLease, isReplication);
registrant.setStatusWithoutDirty(overriddenInstanceStatus);
if (InstanceInfo.InstanceStatus.UP.equals(registrant.getStatus())) {
lease.serviceUp();
}
registrant.setActionType(InstanceInfo.ActionType.ADDED);
this.recentlyChangedQueue.add(new RecentlyChangedItem(lease));
registrant.setLastUpdatedTimestamp();
invalidateCache(registrant.getAppName(), registrant.getVIPAddress(), registrant.getSecureVipAddress());
logger.info("Registered instance {}/{} with status {} (replication={})", new Object[] {registrant
.getAppName(), registrant.getId(), registrant.getStatus(), Boolean.valueOf(isReplication) });
}
finally
{
this.read.unlock();
}
}
最后调用Applicationresource 发post请求
@POST
@Consumes({"application/json", "application/xml"})
public Response addInstance(InstanceInfo info, @HeaderParam("x-netflix-discovery-replication") String isReplication)
{
logger.debug("Registering instance {} (replication={})", info.getId(), isReplication);
if (isBlank(info.getId())) {
return Response.status(400).entity("Missing instanceId").build();
}
if (isBlank(info.getHostName())) {
return Response.status(400).entity("Missing hostname").build();
}
if (isBlank(info.getIPAddr())) {
return Response.status(400).entity("Missing ip address").build();
}
if (isBlank(info.getAppName())) {
return Response.status(400).entity("Missing appName").build();
}
if (!this.appName.equals(info.getAppName())) {
return Response.status(400).entity("Mismatched appName, expecting " + this.appName + " but was " + info.getAppName()).build();
}
if (info.getDataCenterInfo() == null) {
return Response.status(400).entity("Missing dataCenterInfo").build();
}
if (info.getDataCenterInfo().getName() == null) {
return Response.status(400).entity("Missing dataCenterInfo Name").build();
}
DataCenterInfo dataCenterInfo = info.getDataCenterInfo();
if ((dataCenterInfo instanceof UniqueIdentifier))
{
String dataCenterInfoId = ((UniqueIdentifier)dataCenterInfo).getId();
if (isBlank(dataCenterInfoId))
{
boolean experimental = "true".equalsIgnoreCase(this.serverConfig.getExperimental("registration.validation.dataCenterInfoId"));
if (experimental)
{
String entity = "DataCenterInfo of type " + dataCenterInfo.getClass() + " must contain a valid id";
return Response.status(400).entity(entity).build();
}
if ((dataCenterInfo instanceof AmazonInfo))
{
AmazonInfo amazonInfo = (AmazonInfo)dataCenterInfo;
String effectiveId = amazonInfo.get(AmazonInfo.MetaDataKey.instanceId);
if (effectiveId == null) {
amazonInfo.getMetadata().put(AmazonInfo.MetaDataKey.instanceId.getName(), info.getId());
}
}
else
{
logger.warn("Registering DataCenterInfo of type {} without an appropriate id", dataCenterInfo.getClass());
}
}
}
this.registry.register(info, "true".equals(isReplication));
return Response.status(204).build();
}
这样客户端就想服务端注册了端口,并且同步到各个节点
2.renew
DiscoveryClient中方法
boolean renew()
{
try
{
EurekaHttpResponse<InstanceInfo> httpResponse = this.eurekaTransport.registrationClient.sendHeartBeat(this.instanceInfo.getAppName(), this.instanceInfo.getId(), this.instanceInfo, null);
logger.debug("DiscoveryClient_{} - Heartbeat status: {}", this.appPathIdentifier, Integer.valueOf(httpResponse.getStatusCode()));
if (httpResponse.getStatusCode() == 404)
{
this.REREGISTER_COUNTER.increment();
logger.info("DiscoveryClient_{} - Re-registering apps/{}", this.appPathIdentifier, this.instanceInfo.getAppName());
long timestamp = this.instanceInfo.setIsDirtyWithTime();
boolean success = register();y
if (success) {
this.instanceInfo.unsetIsDirty(timestamp);
}
return success;
}
return httpResponse.getStatusCode() == 200;
}
catch (Throwable e)
{
logger.error("DiscoveryClient_{} - was unable to send heartbeat!", this.appPathIdentifier, e);
}
return false;
}
在server端中的PeerAwareInstanceRegisteryImpl
public boolean renew(String appName, String id, boolean isReplication)
{
if (super.renew(appName, id, isReplication))
{
replicateToPeers(Action.Heartbeat, appName, id, null, null, isReplication);
return true;
}
return false;
}
3.canel
DiscoveryClient
void unregister()
{
if ((this.eurekaTransport != null) && (this.eurekaTransport.registrationClient != null)) {
try
{
logger.info("Unregistering ...");
EurekaHttpResponse<Void> httpResponse = this.eurekaTransport.registrationClient.cancel(this.instanceInfo.getAppName(), this.instanceInfo.getId());
logger.info("DiscoveryClient_{} - deregister status: {}", this.appPathIdentifier, Integer.valueOf(httpResponse.getStatusCode()));
}
catch (Exception e)
{
logger.error("DiscoveryClient_{} - de-registration failed{}", new Object[] { this.appPathIdentifier, e.getMessage(), e });
}
}
}
server端
protected boolean internalCancel(String appName, String id, boolean isReplication)
{
try
{
this.read.lock();
EurekaMonitors.CANCEL.increment(isReplication);
Map<String, Lease<InstanceInfo>> gMap = (Map)this.registry.get(appName);
Lease<InstanceInfo> leaseToCancel = null;
if (gMap != null) {
leaseToCancel = (Lease)gMap.remove(id);
}
synchronized (this.recentCanceledQueue)
{
this.recentCanceledQueue.add(new Pair(Long.valueOf(System.currentTimeMillis()), appName + "(" + id + ")"));
}
InstanceInfo.InstanceStatus instanceStatus = (InstanceInfo.InstanceStatus)this.overriddenInstanceStatusMap.remove(id);
if (instanceStatus != null) {
logger.debug("Removed instance id {} from the overridden map which has value {}", id, instanceStatus.name());
}
if (leaseToCancel == null)
{
EurekaMonitors.CANCEL_NOT_FOUND.increment(isReplication);
logger.warn("DS: Registry: cancel failed because Lease is not registered for: {}/{}", appName, id);
return false;
}
leaseToCancel.cancel();
InstanceInfo instanceInfo = (InstanceInfo)leaseToCancel.getHolder();
String vip = null;
String svip = null;
if (instanceInfo != null)
{
instanceInfo.setActionType(InstanceInfo.ActionType.DELETED);
this.recentlyChangedQueue.add(new RecentlyChangedItem(leaseToCancel));
instanceInfo.setLastUpdatedTimestamp();
vip = instanceInfo.getVIPAddress();
svip = instanceInfo.getSecureVipAddress();
}
invalidateCache(appName, vip, svip);
logger.info("Cancelled instance {}/{} (replication={})", new Object[] { appName, id, Boolean.valueOf(isReplication) });
return true;
}
finally
{
this.read.unlock();
}
}