简介

按照原定的计划,我将分三个部分来分析 Eureka 的源码:

  1. Eureka 的配置体系(已经写完,见Eureka详解系列(三)--探索Eureka强大的配置体系);
  2. Eureka Client 的交互行为;
  3. Eureka Server 的交互行为。

今天,我们来研究第二部分的源码。

我的思路是这样子的:先明确 Eureka Client 拥有哪些功能,然后从源码角度分析如何实现,最后,我会补充 Eureka Client 的配置解读。

Eureka Client的功能

首先来回顾下 Eureka 的整个交互过程。

从用户的角度来讲,Eureka Client 要能够向 Eureka Server 注册当前实例以及获取注册表。

至于其他的功能,我们需要再思考下。

当我们把当前实例注册到了 Eureka Server 后,并非一劳永逸,如果当前实例故障了,Eureka Server 需要及时将它从注册表中剔除,那么,Eureka Server 怎么知道哪些实例故障了呢?做法比较简单,Application Service 需要定期向 Eureka Server 报告自己的健康状态,如果一直不报告,就认为是故障了。

考虑到性能和可靠性,Application Client 本地会缓存一份服务注册表,并不需要每次用到就从 Eureka Server 重新获取。但是,Application Service “来来去去”,Eureka Server 的注册表并非一成不变,所以,Application Client 还需要定期同步注册表。

最后还有一点,我们注册到 Eureka Server 的实例信息,除了实例 IP、端口、服务名等,还有实例 id、附带的元数据等,这些是可更改的,Application Service 需要及时地将这些更改同步到 Eureka Server。

通过上面的分析,我们知道一个 Eureka Client 需要具备以下功能

  1. 注册当前实例到 Eureka Server
  2. 获取 Eureka Server 的服务注册表
  3. 定期向 Eureka Server 发送心跳
  4. 定期向 Eureka Server 同步当前实例信息
  5. 定期刷新本地服务注册表

如何实现这些功能

知道了 Eureka Client 需要具备哪些功能,接下来我们就从源码的角度来看看怎样实现这些功能。

和之前一样,我更多的会从设计的层面来分析,而不会顺序地去看每个过程的代码,即重设计、轻实现。如果对源码细节有疑问的,可以交流学习下。

那么,还是从一个 UML 图开始吧。有了它,相信大家看源码时会更轻松一些。

通过这个图,我们再来看 Eureka Client 的几个功能:

  1. 注册当前实例到 Eureka Server;--初始化DiscoveryClient时就会注册上去。
  2. 获取 Eureka Server 的服务注册表;--通过DiscoveryClient获取。
  3. 定期向 Eureka Server 发送心跳;--通过HeartbeatThread任务实现。
  4. 定期向 Eureka Server 同步当前实例信息;--通过InstanceInfoReplicator任务实现。
  5. 定期刷新本地服务注册表;--通过CacheRefreshThread任务实现。

我们拿Eureka详解系列(二)--如何使用Eureka(原生API,无Spring) 中的例子来分析下整个过程。

// 创建ApplicationInfoManager对象
ApplicationInfoManager applicationInfoManager = new ApplicationInfoManager(
new MyDataCenterInstanceConfig(), new EurekaConfigBasedInstanceInfoProvider(instanceConfig).get());
// 创建EurekaClient对象,这个时候完成了几件事:
// 1. 注册当前实例到Eureka Server(实例的初始状态一般是STARTING);
// 2. 开启心跳、刷缓存、同步实例信息的定时任务;
// 3. 注册状态监听器到ApplicationInfoManager(不然后面的setInstanceStatus不会生效的)
EurekaClient eurekaClient = new DiscoveryClient(applicationInfoManager, new DefaultEurekaClientConfig());
// 设置当前实例状态为STARTING(原状态也是STARTING,所以这一句没什么用)
applicationInfoManager.setInstanceStatus(InstanceInfo.InstanceStatus.STARTING);
// 设置当前实例状态为UP触发(监听器触发,执行InstanceInfoReplicator的任务)
applicationInfoManager.setInstanceStatus(InstanceInfo.InstanceStatus.UP);
// 和application client交互
// ······
// 关闭客户端,同时也会注销当前实例
eurekaClient.shutdown();

我们会发现,DiscoveryClient初始化化时做了非常多的事情,核心的源码都在它的构造方法里,大家感兴趣的可以自行阅读。

这里提醒下,Eureka 的定时任务有点奇怪,它不是完全交给ScheduledExecutorService来调度,举个例子,ScheduledExecutorService只会按设定的延迟执行一次心跳任务,然后就不执行了,之所以能够实现定时调度,是因为心跳任务里又提交了一次任务,代码如下:

    public void run() {
try {
// ······
} finally {
// ······
if (!scheduler.isShutdown()) {
scheduler.schedule(this, delay.get(), TimeUnit.MILLISECONDS);
}
}
}

Eureka Client的配置详解

回顾下Eureka详解系列(三)--探索Eureka强大的配置体系的内容,在 Eureka 里,配置分成了三种:

  1. EurekaInstanceConfig:当前实例身份的配置信息,即我是谁?
  2. EurekaServerConfig:一些影响当前Eureka Server和客户端或对等节点交互行为的配置信息,即怎么交互?
  3. EurekaClientConfig:一些影响当前实例和Eureka Server交互行为的配置信息,即和谁交互?怎么交互?

这里我们来讲讲EurekaInstanceConfigEurekaClientConfig的配置参数。

EurekaInstanceConfig--我是谁?

这些参数大部分用来向 Eureka Server 表明当前实例的身份,但我们会发现,这里混进了两个“异类”--lease.renewalInterval 和 lease.duration,这个不应该放在EurekaClientConfig里吗?

我一开始也不明白,后来发现很重要的一点,EurekaClientConfig的参数只能影响当前实例,而不能影响 Eureka Server,它的信息不能向 Eureka Server 传递,而EurekaInstanceConfig的就可以,所以,除了表明实例的身份,EurekaInstanceConfig还有另外一个功能,就是向 Eureka Server 传递某些重要的交互参数。

# 同一个服务下存在多个实例,这个可以作为唯一标识区分它们。默认为当前实例的主机名
eureka.instanceId=zzs # 服务名。默认unknown
eureka.name=SampleService # 当前实例开放服务的端口,默认80
eureka.port=8001 # 当前实例多久向Eureka Server发送一次心跳,单位秒。默认30s
eureka.lease.renewalInterval=30
# 如果没收到心跳,Eureka Server隔多久将当前实例剔除,单位秒。默认90s
eureka.lease.duration=90 # 当前实例的虚拟主机名,通过这个可以直接访问到当前实例。默认:当前主机名+port
eureka.vipAddress=sampleservice.zzs.cn # 绑定在当前实例的一些自定义信息,它们会被放在一个map里,其他Eureka Client可以拿来用。默认是一个空map
eureka.metadata.name=zzs
eureka.metadata.age=18 # 这几个一般不用,我就不展开了
eureka.appGroup=unknown
#eureka.asgName=
eureka.traffic.enabled=false
eureka.port.enabled=true
eureka.securePort=443
eureka.securePort.enabled=false
eureka.secureVipAddress=zzs:443
eureka.statusPageUrlPath=/Status
eureka.statusPageUrl=http://zzs:8001/Status
eureka.homePageUrlPath=/
eureka.homePageUr=http://zzs:8001/
eureka.healthCheckUrlPath=/healthcheck
eureka.healthCheckUrl=http://zzs:8001/healthcheck
eureka.secureHealthCheckUrl=https://zzs:443/healthcheck

EurekaClientConfig--和谁交互?怎么交互?

关于 Eureka Server 集群的配置,有三种方法:

  1. 在 serviceUrl 中写死 Eureka Server 的 IP,缺点就是每次增加、删除、更改机器都要更改配置;
  2. 在 serviceUrl 中配置 Eureka Server 对应的 EIP,更改机器时不需要更改,但是增加、删除机器都要更改配置;
  3. 采用 DNS 配置 Eureka Server 的 IP,增加、删除、更改机器都不需要更改配置。

这里还涉及到 region、zone 的概念,可以理解为:region 表示机器部署在不同的城市,zone 表示机器部署在同一个城市的不同机房里。默认情况下,Eureka Client 会优先选择自己所属 region 的 Eureka Server 来访问。

# 当前实例多久同步一次本地注册表,单位秒。默认30s
eureka.client.refresh.interval=30
# 当前实例多久同步一次实例信息,单位秒。默认30s
eureka.appinfo.replicate.interval=30 # 当前实例是否注册到Eureka Server。默认true
eureka.registration.enabled=true
# 当前实例是否需要从Eureka Server获取服务注册表
eureka.shouldFetchRegistry=true # 当前实例可以和哪些region的Eureka Server交互
eureka.fetchRemoteRegionsRegistry=beijing,shanghai
# 当前实例所在的region
eureka.region=beijing
# region下有哪些zone
eureka.beijing.availabilityZones=zone-1,zone-2
eureka.shanghai.availabilityZones=zone-3
# zone下有哪些Eureka Server(这种配置可以通过EIP来避免写死IP,但扩展时还是要改,推荐使用DNS的方式)
eureka.serviceUrl.zone-1=http://ec2-552-627-568-165.compute-1.amazonaws.com:7001/eureka/v2/,http://ec2-368-101-182-134.compute-1.amazonaws.com:7001/eureka/v2/
eureka.serviceUrl.zone-2=http://ec2-552-627-568-170.compute-1.amazonaws.com:7001/eureka/v2/
eureka.serviceUrl.zone-3=http://ec2-500-179-285-592.compute-1.amazonaws.com:7001/eureka/v2/ # 当我们使用DNS配置serviceUrl时需要用到的配置(非常推荐使用,可以避免写死IP,且方便扩展)
eureka.shouldUseDns=true
eureka.eurekaServer.domainName=sampleservice.zzs.cn
eureka.eurekaServer.port=8001
eureka.eurekaServer.context=eureka/v2 # 这几个一般不用,我就不展开了
eureka.preferSameZone=true
eureka.appinfo.initial.replicate.time=40
eureka.serviceUrlPollIntervalMs=300
eureka.client.heartbeat.threadPoolSize=5
eureka.client.heartbeat.exponentialBackOffBound=10
eureka.client.cacheRefresh.threadPoolSize=5
eureka.client.cacheRefresh.exponentialBackOffBound=10
#eureka.eurekaServer.proxyHost=
#eureka.eurekaServer.proxyPort=
#eureka.eurekaServer.proxyUserName=
#eureka.eurekaServer.proxyPassword=
eureka.eurekaServer.gzipContent=true
eureka.eurekaServer.readTimeout=8
eureka.eurekaServer.connectTimeout=5
eureka.eurekaServer.maxTotalConnections=200
eureka.eurekaServer.maxConnectionsPerHost=50
eureka.eurekaserver.connectionIdleTimeoutInSeconds=45
#eureka.backupregistry=
eureka.shouldEnforceRegistrationAtInit=false
eureka.shouldEnforceFetchRegistryAtInit=false
eureka.shouldUnregisterOnShutdown=true
eureka.shouldFilterOnlyUpInstances=true
eureka.shouldOnDemandUpdateStatusChange=true
eureka.allowRedirects=true
eureka.printDeltaFullDiff=true
eureka.disableDelta=false
eureka.registryRefreshSingleVipAddress=false
eureka.dollarReplacement=_-
eureka.escapeCharReplacement=__
#eureka.encoderName=
#eureka.decoderName=
eureka.clientDataAccept=full
eureka.experimental.clientTransportFailFastOnInit=true

以上比较宏观地讲完了 Eureka Client 的源码和配置,感谢您的阅读。

参考资料

https://github.com/Netflix/eureka/wiki/Eureka-at-a-glance

相关源码请移步:https://github.com/ZhangZiSheng001/eureka-demo

本文为原创文章,转载请附上原文出处链接:https://www.cnblogs.com/ZhangZiSheng001/p/14381169.html

Eureka详解系列(四)--Eureka Client部分的源码和配置的更多相关文章

  1. Eureka详解系列(五)--Eureka Server部分的源码和配置

    简介 按照原定的计划,我将分三个部分来分析 Eureka 的源码: Eureka 的配置体系(已经写完,见Eureka详解系列(三)--探索Eureka强大的配置体系): Eureka Client ...

  2. Eureka详解系列(二)--如何使用Eureka(原生API,无Spring)

    简介 通过上一篇博客 Eureka详解系列(一)--先谈谈负载均衡器 ,我们知道了 Eureka 是什么以及为什么要使用它,今天,我们开始研究如何使用 Eureka. 在此之前,先说明一点.网上几乎所 ...

  3. 详解Mybatis拦截器(从使用到源码)

    详解Mybatis拦截器(从使用到源码) MyBatis提供了一种插件(plugin)的功能,虽然叫做插件,但其实这是拦截器功能. 本文从配置到源码进行分析. 一.拦截器介绍 MyBatis 允许你在 ...

  4. Scala 深入浅出实战经典 第61讲:Scala中隐式参数与隐式转换的联合使用实战详解及其在Spark中的应用源码解析

    王家林亲授<DT大数据梦工厂>大数据实战视频 Scala 深入浅出实战经典(1-87讲)完整视频.PPT.代码下载: 百度云盘:http://pan.baidu.com/s/1c0noOt ...

  5. Scala 深入浅出实战经典 第60讲:Scala中隐式参数实战详解以及在Spark中的应用源码解析

    王家林亲授<DT大数据梦工厂>大数据实战视频 Scala 深入浅出实战经典(1-87讲)完整视频.PPT.代码下载:百度云盘:http://pan.baidu.com/s/1c0noOt6 ...

  6. Mybatis源码详解系列(四)--你不知道的Mybatis用法和细节

    简介 这是 Mybatis 系列博客的第四篇,我本来打算详细讲解 mybatis 的配置.映射器.动态 sql 等,但Mybatis官方中文文档对这部分内容的介绍已经足够详细了,有需要的可以直接参考. ...

  7. Eureka详解系列(一)--先谈谈负载均衡器

    这个系列开始研究 Eureka,在此之前,先来谈谈负载均衡器. 本质上,Eureka 就是一个负载均衡器,可能有的人会说,它是一个服务注册中心,用来注册服务的,这种说法不能说错,只是有点片面. 在这篇 ...

  8. Eureka详解系列(三)--探索Eureka强大的配置体系

    简介 通过前面的两篇博客,我们知道了:什么是 Eureka?为什么使用 Eureka?如何适用 Eureka?今天,我们开始来研究 Eureka 的源码,先从配置部分的源码开始看,其他部分后面再补充. ...

  9. 深入浅出Mybatis系列(三)---配置详解之properties与environments(mybatis源码篇)

    上篇文章<深入浅出Mybatis系列(二)---配置简介(mybatis源码篇)>我们通过对mybatis源码的简单分析,可看出,在mybatis配置文件中,在configuration根 ...

随机推荐

  1. element-ui使用后手记

    一.路由模式el-menu中使用路由模式 在el-meun中设置:router="true" 在el-menu-item中设置index="路由地址"

  2. Windows搭建SkyWalking8.3环境进行JAVA应用性能监控及入门示例(使用Mysql持久化)

    下载SkyWalking 一.下载地址(点击) 选择tar 解压后进入config文件夹先配置一下Mysql数据源,打开application.yml文件 默认selector是h2我们改成mysql ...

  3. 树莓派-4WD智能小车操作小结

    树莓派-4WD智能小车操作小结 树莓派4B-4WD智能小车,双层结构,第一层结构为:小车扩展板(底层)+树莓派主板,通过铜柱隔离固定,小车扩展板相当于计算机的外设扩展板:上面一层为第二层,是三个舵机承 ...

  4. 【Nginx】配置nginx图片服务器

    想通过nginx来访问服务器上的图片 可以搭建一个nginx图片服务器. 做法如下: 先安装nginx,这里直接用yum来进行安装的 安装方法如下: https://blog.csdn.net/iml ...

  5. web测试误区:浏览器后退键退出系统会话失效

    通过最近测试的项目,认识到实际:浏览器后退键退出系统,会话仍旧有效.打破了之前认为浏览器后退键就会退出系统登录的认知. 一,了解Cookie和Session的作用,具体来说cookie机制采用的是在客 ...

  6. C# ADO.NET连接字符串详解

    C#中连接字符串包含以下内容 参数 说明 Provider 设置或者返回提供的连接程式的名称,仅用于OLeDbConnection对象 Connection Timeout 在终止尝试并产生异常前,等 ...

  7. 在Ubuntu18.04下编译出ffmpeg(支持推流H265成rtmp)

    Ubuntu18.04下编译libx264.libx265.libfdk_aac和ffmpeg 一.编译x264库 二.编译fdk-aac库 三.编译x265库 四.编译FFmpeg源码 五.设置环境 ...

  8. Graph Explore的使用介绍

    我在Graph API开发中用的最多的测试工具就是Graph Explore,这个是微软开发的网页版的Graph API的测试工具,能满足我大部分需求. 访问网址是:Graph Explorer - ...

  9. 消息队列之activeMQ

    1.activeMQ的主要功能 实现高可用.高伸缩.高性能.易用和安全的企业级面向消息服务的系统 异步消息的消费和处理 控制消息的消费顺序 可以和Spring/springBoot整合简化编码 配置集 ...

  10. 阿里云镜像仓库镜像迁移至私有Harbor

    下载镜像同步工具 wget https://goodrain-delivery.oss-cn-hangzhou.aliyuncs.com/boe/image-syncer && chm ...