摘要:在上一篇中,介绍了Eureka的相关的知识,解释了Eureka为什么适合做服务发现和注册。接下来,在本篇文章将通过源码分析的方式,看一下Eureka是怎么work的。本章主要介绍Eureka的服务注册。那eureka client如何将本地服务的注册信息发送到远端的注册服务器eureka server上。通过下面的源码分析,看出Eureka Client的定时任务调用Eureka Server的REST接口,而Eureka接收到调用请求后会处理服务的注册以及Eureka Server中的数据同步的问题。
服务注册
服务注册,想必大家并不陌生,就是服务提供者启动的时候,把自己提供的服务信息,例如 服务名,IP,端口号,版本号等信息注册到注册中心,比如注册到ZK中。那eureka client如何将本地服务的注册信息发送到远端的注册服务器eureka server上。通过下面的源码分析,看出服务注册可以认为是Eureka client自己完成,不需要服务本身来关心。
Eureka Client的定时任务调用Eureka Server的提供接口
实现思路其实也挺简单,在com.netflix.discovery.DiscoveryClient启动的时候,会初始化一个定时任务,定时的把本地的服务配置信息,即需要注册到远端的服务信息自动刷新到注册服务器上。
首先看一下Eureka的代码,在spring-cloud-netflix-eureka-server工程中可以找到这个依赖eureka-client-1.4.11.jar查看代码可以看到,
com.netflix.discovery.DiscoveryClient.java中的1240行可以看到Initializes all scheduled tasks,在1277行,可以看到InstanceInfoReplicator定时任务。
- 在DiscoveryClient中初始化一个InstanceInfoReplicator,其实里面封装了以定时任务。123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475/*** Initializes all scheduled tasks.*/private void initScheduledTasks() {if (clientConfig.shouldFetchRegistry()) {// registry cache refresh timerint registryFetchIntervalSeconds = clientConfig.getRegistryFetchIntervalSeconds();int expBackOffBound = clientConfig.getCacheRefreshExecutorExponentialBackOffBound();scheduler.schedule(new TimedSupervisorTask("cacheRefresh",scheduler,cacheRefreshExecutor,registryFetchIntervalSeconds,TimeUnit.SECONDS,expBackOffBound,new CacheRefreshThread()),registryFetchIntervalSeconds, TimeUnit.SECONDS);}if (clientConfig.shouldRegisterWithEureka()) {int renewalIntervalInSecs = instanceInfo.getLeaseInfo().getRenewalIntervalInSecs();int expBackOffBound = clientConfig.getHeartbeatExecutorExponentialBackOffBound();logger.info("Starting heartbeat executor: " + "renew interval is: " + renewalIntervalInSecs);// Heartbeat timerscheduler.schedule(new TimedSupervisorTask("heartbeat",scheduler,heartbeatExecutor,renewalIntervalInSecs,TimeUnit.SECONDS,expBackOffBound,new HeartbeatThread()),renewalIntervalInSecs, TimeUnit.SECONDS);// InstanceInfo replicator/**************************封装了定时任务**********************************/instanceInfoReplicator = new InstanceInfoReplicator(this,instanceInfo,clientConfig.getInstanceInfoReplicationIntervalSeconds(),2); // burstSizestatusChangeListener = new ApplicationInfoManager.StatusChangeListener() {public String getId() {return "statusChangeListener";}public void notify(StatusChangeEvent statusChangeEvent) {if (InstanceStatus.DOWN == statusChangeEvent.getStatus() ||InstanceStatus.DOWN == statusChangeEvent.getPreviousStatus()) {// log at warn level if DOWN was involvedlogger.warn("Saw local status change event {}", statusChangeEvent);} else {logger.info("Saw local status change event {}", statusChangeEvent);}instanceInfoReplicator.onDemandUpdate();}};if (clientConfig.shouldOnDemandUpdateStatusChange()) {applicationInfoManager.registerStatusChangeListener(statusChangeListener);}//点击可以查看start方法instanceInfoReplicator.start(clientConfig.getInitialInstanceInfoReplicationIntervalSeconds());} else {logger.info("Not registering with Eureka server per configuration");}}
2.以initialDelayMs为间隔调用。
3.ScheduledExecutorService的task的具体业务定义在com.netflix.discovery.InstanceInfoReplicator.run()中,也就是InstanceInfoReplicator中的98-113行,可以看到调用了了client的register方法。
4.com.netflix.discovery.DiscoveryClient中的 register()方法,大概在811行。
Eureka server端接到请求后的处理
打开spring-cloud-netflix-eureka-server工程或spring-cloud-netflix-eureka-client过程,找到相应的maven依赖jar,如下图所示
1.Eureka server服务端请求入口
ApplicationResource.java文件中第183行,如下所示,可以看出Eureka是通过http post的方式去服务注册
2.如下图所示可以看到,从ApplicationResource.java怎么进入到PeerAwareInstanceRegistryImpl中的register方法
InstanceRegistry.java文件中的88行,可以看到调用PeerAwareInstanceRegistryImpl中的405行register方法
3.PeerAwareInstanceRegistryImpl中的405行register方法,代码如下所示。阅读方法上面的注释,就知道该方法是注册服务信息并把Eureka Server中的配置信息同步。执行注册的动作在com.netflix.eureka.registry.PeerAwareInstanceRegistryImpl.register(InstanceInfo info, boolean isReplication)中,具体代码如下所示:
|
|
4.AbstractInstanceRegistry.java中192行,可以看到Eureka真正的服务注册实现的代码
说明:注册信息其实就是存储在一个 ConcurrentHashMap
更多的细节源码内容,大家可以自己阅读。
总结
ApplicationResource类接收Http服务请求,调用PeerAwareInstanceRegistryImpl的register方法,PeerAwareInstanceRegistryImpl完成服务注册后,调用replicateToPeers向其它Eureka Server节点(Peer)做状态同步。如下图所示。