关于服务注册

以下图片来自Netflix官方,图中显示Eureka Client会向注册中心发起Get Registry请求来获取服务列表:

以Spring Cloud的Edgware.RELEASE版本为例,Eureka client的注册动作是在com.netflix.discovery.DiscoveryClient类的initScheduledTasks方法中执行的,相关代码片段如下所示,请注意中文注释:

//略去不相关代码
...
//实例化InstanceInfoReplicator对象
instanceInfoReplicator = new InstanceInfoReplicator(this,instanceInfo,clientConfig.getInstanceInfoReplicationIntervalSeconds(),2); // burstSize//监听器,用来监听作为Eureka client的自身的状态变化statusChangeListener = new ApplicationInfoManager.StatusChangeListener() {@Overridepublic String getId() {return "statusChangeListener";}@Overridepublic 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);}//状态变化时notify方法会被执行,此时上报最新状态到Eureka serverinstanceInfoReplicator.onDemandUpdate();}};if (clientConfig.shouldOnDemandUpdateStatusChange()) {//注册监听器applicationInfoManager.registerStatusChangeListener(statusChangeListener);}//服务注册instanceInfoReplicator.start(clientConfig.getInitialInstanceInfoReplicationIntervalSeconds());

上述代码表明,将自身信息上报到Eureka server的工作是通过调用instanceInfoReplicator的api完成的;

InstanceInfoReplicator的作用

先看InstanceInfoReplicator源码的注释:

/*** A task for updating and replicating the local instanceinfo to the remote server. Properties of this task are:* - configured with a single update thread to guarantee sequential update to the remote server* - update tasks can be scheduled on-demand via onDemandUpdate()* - task processing is rate limited by burstSize* - a new update task is always scheduled automatically after an earlier update task. However if an on-demand task*   is started, the scheduled automatic update task is discarded (and a new one will be scheduled after the new*   on-demand update).**   @author dliu*/

我的理解:

  1. InstanceInfoReplicator是个任务类,负责将自身的信息周期性的上报到Eureka server;
  2. 有两个场景触发上报:周期性任务、服务状态变化(onDemandUpdate被调用),因此,在同一时刻有可能有两个上报的任务同时出现;
  3. 单线程执行上报的操作,如果有多个上报任务,也能确保是串行的;
  4. 有频率限制,通过burstSize参数来控制;
  5. 先创建的任务总是先执行,但是onDemandUpdate方法中创建的任务会将周期性任务给丢弃掉;

源码分析

以前面对注释的理解作为主线,去看源码:

  1. 先看构造方法,如下,中文注释位置需要注意:
InstanceInfoReplicator(DiscoveryClient discoveryClient, InstanceInfo instanceInfo, int replicationIntervalSeconds, int burstSize) {this.discoveryClient = discoveryClient;this.instanceInfo = instanceInfo;//线程池,core size为1,使用DelayedWorkQueue队列this.scheduler = Executors.newScheduledThreadPool(1,new ThreadFactoryBuilder().setNameFormat("DiscoveryClient-InstanceInfoReplicator-%d").setDaemon(true).build());this.scheduledPeriodicRef = new AtomicReference<Future>();this.started = new AtomicBoolean(false);//RateLimiter是个限制频率的工具类,用来限制单位时间内的任务次数this.rateLimiter = new RateLimiter(TimeUnit.MINUTES);this.replicationIntervalSeconds = replicationIntervalSeconds;this.burstSize = burstSize;//通过周期间隔,和burstSize参数,计算每分钟允许的任务数this.allowedRatePerMinute = 60 * this.burstSize / this.replicationIntervalSeconds;logger.info("InstanceInfoReplicator onDemand update allowed rate per min is {}", allowedRatePerMinute);}

从以上代码可见,构造方法中准备好了线程池和频率限制工具,再算好了每分钟允许的任务数;
2. 在com.netflix.discovery.DiscoveryClient类的initScheduledTasks方法中,通过调用instanceInfoReplicator.start方法启动了周期性任务,现在来看此方法:

public void start(int initialDelayMs) {//CAS操作,不但保证了只执行一次,多线程场景也能保证if (started.compareAndSet(false, true)) {instanceInfo.setIsDirty();  // for initial register//提交一个任务,延时执行,注意第一个参数是this,因此延时结束时,InstanceInfoReplicator的run方法会被执行Future next = scheduler.schedule(this, initialDelayMs, TimeUnit.SECONDS);//这个任务的Feature对象放在成员变量scheduledPeriodicRef中scheduledPeriodicRef.set(next);}
}
  1. 延时时间到达时,会执行run方法:
public void run() {try {//更新信息,用于稍后的上报discoveryClient.refreshInstanceInfo();Long dirtyTimestamp = instanceInfo.isDirtyWithTime();if (dirtyTimestamp != null) {//上报discoveryClient.register();instanceInfo.unsetIsDirty(dirtyTimestamp);}} catch (Throwable t) {logger.warn("There was a problem with the instance info replicator", t);} finally {//每次执行完毕都会创建一个延时执行的任务,就这样实现了周期性执行的逻辑Future next = scheduler.schedule(this, replicationIntervalSeconds, TimeUnit.SECONDS);//每次创建的周期性任务,都要放入scheduledPeriodicRef,//如果外部调用了onDemandUpdate,就能通过onDemandUpdate取得当前要执行的任务scheduledPeriodicRef.set(next);}}
  1. 以上代码汇总起来,就完成了周期性任务的逻辑,接下来看看被外部调用的onDemandUpdate方法:
public boolean onDemandUpdate() {//没有达到频率限制才会执行if (rateLimiter.acquire(burstSize, allowedRatePerMinute)) {//提交一个任务scheduler.submit(new Runnable() {@Overridepublic void run() {logger.debug("Executing on-demand update of local InstanceInfo");//取出之前已经提交的任务Future latestPeriodic = scheduledPeriodicRef.get();//如果此任务未完成,就立即取消if (latestPeriodic != null && !latestPeriodic.isDone()) {logger.debug("Canceling the latest scheduled update, it will be rescheduled at the end of on demand update");latestPeriodic.cancel(false);}//通过调用run方法,令任务在延时后执行,相当于周期性任务中的一次InstanceInfoReplicator.this.run();}});return true;} else {//如果超过了设置的频率限制,本次onDemandUpdate方法就提交任务了logger.warn("Ignoring onDemand update due to rate limiter");return false;}}

如上述代码所示,可见之前注释中提到的功能都已实现;

至此,InstanceInfoReplicator已分析完毕,可见这是个功能强大的辅助类,在应用信息上报到Eureka server时发挥了重要的作用,业务逻辑可以放心的提交上报请求,并发、频率超限等情况都被InstanceInfoReplicator处理好了;

Eureka的InstanceInfoReplicator类(服务注册辅助工具)相关推荐

  1. Vue UI组件 开发框架 服务端 辅助工具 应用实例 Demo示例

    2019独角兽企业重金招聘Python工程师标准>>> element ★11612 - 饿了么出品的Vue2的web UI工具套件 Vux ★7503 - 基于Vue和WeUI的组 ...

  2. 前端开发全家桶:UI组件 开发框架 服务端 辅助工具 应用实例 Demo示例

    element ★11612 - 饿了么出品的Vue2的web UI工具套件 Vux ★7503 - 基于Vue和WeUI的组件库 iview ★5801 - 基于 Vuejs 的开源 UI 组件库 ...

  3. Python (百万答题类节目)辅助工具代码(实测有效)

    前段时间很火的百万答题,现在编写了一个脚本辅助工具,思路如下: ①adb连接手机获取截屏,保存到本地 ②pytesseract获取图片指定位置的文字 ③网页查找答案 附代码如下:(亲测通过,执行时间6 ...

  4. Windows 服务(附服务开发辅助工具)

    引子 近来在 Windows 下摆弄了一阵子的服务程序,有在 C++ 下弄服务的,也在 C# 下弄服务的, 感觉在 C# 下弄服务蛮简单的の,C/C++ 的麻烦蛮多の(当然我的服务所要求的功能也是很简 ...

  5. Tom邮箱注册机|注册辅助工具!!!

    .net开发的Tom邮箱注册机,请下载微软的.net framework 3.5运行库.软件启动的时候就点慢,这个是因为第一次要从tom网站读取数据. 下载:http://files.cnblogs. ...

  6. 如何恢复类视图中突然消失的类已经编程辅助工具VISUAL ASIST

    关闭工程 删除工程下.clw   .ncb文件和debug目录 开启工程 rebuild   all 需要再把.clw添加进来,这是个类向导(不知道可不可以之前不删这个,我没试,后来添加类向导时候发现 ...

  7. SpringCloud系列之Eureka服务注册及发现

    Eureka 1. Eureka简介 1.1 什么是Eureka 2. Eureka实例 2.1 编写Eureka Server 2.2 编写Eureka Client 3. Eureka源码解析 3 ...

  8. Spring Cloud构建微服务架构:服务注册与发现(Eureka、Consul)【Dalston版】

    Spring Cloud简介 Spring Cloud是一个基于Spring Boot实现的云应用开发工具,它为基于JVM的云应用开发中涉及的配置管理.服务发现.断路器.智能路由.微代理.控制总线.全 ...

  9. Spring Boot(2.1.2.RELEASE) + Spring Cloud (Finchley.RELEASE)搭建服务注册和发现组件Eureka

    前言:由于版本原因,部分关于Spring Cloud的书中使用的是Spring Boot 1.x 版本,很多配置或名称在新版本中已经发生了改变.此篇文章记录的是使用较新的Spring Boot 2.x ...

最新文章

  1. python 解决最佳方案_python使用列表的最佳方案
  2. 02_计算机科学和软件工程的区别
  3. Measuring Similarity between Clusters (Clusters 之间相似度的测量)【未完待续】
  4. 项目交付为什么失败?-记我在某个项目中的迷思
  5. poj 3304 Segments (几何 : 线段 直线相交)
  6. Spring Boot——[Spring Boot Configuration Annotation Processor not found in classpath]解决方案
  7. Django从理论到实战(part10)--URL命名与反转
  8. 程序员技术练级攻略(转载)
  9. 您应该对什么进行单元测试? –测试技术3
  10. infopath转换html,Microsoft Tools to Save InfoPath Forms as HTML
  11. 朱晔和你聊Spring系列S1E9:聊聊Spring的那些注解
  12. 将含有自定义代码的Infopath模板发布到Sharepoint表单库中
  13. CSAPP-C1-计算机系统漫游
  14. GB35114—⑤、附 录C
  15. java 设置压缩文件大小不变_为什么把文件压缩后,文件大小却不变呢?
  16. linux的XDG(X Desktop Group)基本目录规范
  17. 二年级计算机学什么礼物,二年级的小朋友喜欢什么礼物(最美好的礼物二年级)...
  18. 【python逻辑算法题】一只青蛙一次可以跳上1级台阶,也可以跳上2级.求该青蛙跳上一个n级的台阶总共有多少种跳法
  19. 使用java的方式配置Spring---JavaConfig
  20. 方队 - 启发式合并 - 主席树

热门文章

  1. 整个世界都是你的绿幕:这个视频抠图换背景的方法太惊艳了!
  2. 无线智能蓝牙追踪防丢器
  3. android敏感api函数,基于敏感API调用的Android应用程序动态监控
  4. 3分钟了解阿里云自营建站服务。
  5. 决策树系列之一决策树的入门教程
  6. 第25章 JDBC核心技术第3节
  7. SASS实现颜色卡动画
  8. 在win桌面上添加系统图标
  9. 科目二:倒车入库考试技巧详细图解
  10. python之表白神器--组图拼爱心墙