Eureka详解系列(四)--Eureka Client部分的源码和配置
简介
按照原定的计划,我将分三个部分来分析 Eureka 的源码:
- Eureka 的配置体系(已经写完,见Eureka详解系列(三)--探索Eureka强大的配置体系);
- Eureka Client 的交互行为;
- 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 需要具备以下功能:
- 注册当前实例到 Eureka Server;
- 获取 Eureka Server 的服务注册表;
- 定期向 Eureka Server 发送心跳;
- 定期向 Eureka Server 同步当前实例信息;
- 定期刷新本地服务注册表
如何实现这些功能
知道了 Eureka Client 需要具备哪些功能,接下来我们就从源码的角度来看看怎样实现这些功能。
和之前一样,我更多的会从设计的层面来分析,而不会顺序地去看每个过程的代码,即重设计、轻实现。如果对源码细节有疑问的,可以交流学习下。
那么,还是从一个 UML 图开始吧。有了它,相信大家看源码时会更轻松一些。
通过这个图,我们再来看 Eureka Client 的几个功能:
- 注册当前实例到 Eureka Server;--初始化
DiscoveryClient
时就会注册上去。 - 获取 Eureka Server 的服务注册表;--通过
DiscoveryClient
获取。 - 定期向 Eureka Server 发送心跳;--通过
HeartbeatThread
任务实现。 - 定期向 Eureka Server 同步当前实例信息;--通过
InstanceInfoReplicator
任务实现。 - 定期刷新本地服务注册表;--通过
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 里,配置分成了三种:
- EurekaInstanceConfig:当前实例身份的配置信息,即我是谁?
- EurekaServerConfig:一些影响当前Eureka Server和客户端或对等节点交互行为的配置信息,即怎么交互?
- EurekaClientConfig:一些影响当前实例和Eureka Server交互行为的配置信息,即和谁交互?怎么交互?
这里我们来讲讲EurekaInstanceConfig
和EurekaClientConfig
的配置参数。
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 集群的配置,有三种方法:
- 在 serviceUrl 中写死 Eureka Server 的 IP,缺点就是每次增加、删除、更改机器都要更改配置;
- 在 serviceUrl 中配置 Eureka Server 对应的 EIP,更改机器时不需要更改,但是增加、删除机器都要更改配置;
- 采用 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://www.cnblogs.com/ZhangZiSheng001/p/14381169.html
Eureka详解系列(四)--Eureka Client部分的源码和配置的更多相关文章
- Eureka详解系列(五)--Eureka Server部分的源码和配置
简介 按照原定的计划,我将分三个部分来分析 Eureka 的源码: Eureka 的配置体系(已经写完,见Eureka详解系列(三)--探索Eureka强大的配置体系): Eureka Client ...
- Eureka详解系列(二)--如何使用Eureka(原生API,无Spring)
简介 通过上一篇博客 Eureka详解系列(一)--先谈谈负载均衡器 ,我们知道了 Eureka 是什么以及为什么要使用它,今天,我们开始研究如何使用 Eureka. 在此之前,先说明一点.网上几乎所 ...
- 详解Mybatis拦截器(从使用到源码)
详解Mybatis拦截器(从使用到源码) MyBatis提供了一种插件(plugin)的功能,虽然叫做插件,但其实这是拦截器功能. 本文从配置到源码进行分析. 一.拦截器介绍 MyBatis 允许你在 ...
- Scala 深入浅出实战经典 第61讲:Scala中隐式参数与隐式转换的联合使用实战详解及其在Spark中的应用源码解析
王家林亲授<DT大数据梦工厂>大数据实战视频 Scala 深入浅出实战经典(1-87讲)完整视频.PPT.代码下载: 百度云盘:http://pan.baidu.com/s/1c0noOt ...
- Scala 深入浅出实战经典 第60讲:Scala中隐式参数实战详解以及在Spark中的应用源码解析
王家林亲授<DT大数据梦工厂>大数据实战视频 Scala 深入浅出实战经典(1-87讲)完整视频.PPT.代码下载:百度云盘:http://pan.baidu.com/s/1c0noOt6 ...
- Mybatis源码详解系列(四)--你不知道的Mybatis用法和细节
简介 这是 Mybatis 系列博客的第四篇,我本来打算详细讲解 mybatis 的配置.映射器.动态 sql 等,但Mybatis官方中文文档对这部分内容的介绍已经足够详细了,有需要的可以直接参考. ...
- Eureka详解系列(一)--先谈谈负载均衡器
这个系列开始研究 Eureka,在此之前,先来谈谈负载均衡器. 本质上,Eureka 就是一个负载均衡器,可能有的人会说,它是一个服务注册中心,用来注册服务的,这种说法不能说错,只是有点片面. 在这篇 ...
- Eureka详解系列(三)--探索Eureka强大的配置体系
简介 通过前面的两篇博客,我们知道了:什么是 Eureka?为什么使用 Eureka?如何适用 Eureka?今天,我们开始来研究 Eureka 的源码,先从配置部分的源码开始看,其他部分后面再补充. ...
- 深入浅出Mybatis系列(三)---配置详解之properties与environments(mybatis源码篇)
上篇文章<深入浅出Mybatis系列(二)---配置简介(mybatis源码篇)>我们通过对mybatis源码的简单分析,可看出,在mybatis配置文件中,在configuration根 ...
随机推荐
- MySQL在按照某个字段分组、排序加序号
事情是这样的,最近领导给了一个新的需求,要求在一张订单表中统计每个人第一次和第二次购买的时间间隔,最后还需要按照间隔统计计数,求出中位数等数据. 由于MySQL不想Oracle那般支持行号.中位数等, ...
- Syn_Flood攻击&防御手段
Syn_Flood攻击原理 攻击者首先伪造地址对服务器发起SYN请求(我可以建立连接吗?),服务器就会回应一个ACK+SYN(可以+请确认).而真实的IP会认为,我没有发送请求,不作回应.服务器没有收 ...
- java进阶(29)--HashMap集合
一.HashMap简介 1.HashMap底层是哈希表结构,类似字典,初始化如下: 2.哈希表结构: 是一个数组+单向链表的结构体 数组:查询效率较高,随机增删效率很低 单向链表:在随机增删方面效率较 ...
- 【MySQL 基础】MySQ LeetCode
MySQL LeetCode 175. 组合两个表 题目描述 表1: Person +-------------+---------+ | 列名 | 类型 | +-------------+----- ...
- jenkins + Ansible Plugin + ansi-color 让结果显示颜色
1 安装jenkins: 此处省略百余字...... 2 安装jenkins的插件: Ansible Plugin AnsiColor Plugin 3 设置job 内容 让ansible ...
- EGADS框架处理流程分析
最近在搞异常检测相关的工作,因此调研了业界常用的异常检测系统.通过查阅相关资料,发现业界对雅虎开源的EGADS系统评价比较高,其git项目已有980个star.这周阅读了项目的源码,梳理了系统框架的基 ...
- 通过JS逆向ProtoBuf 反反爬思路分享
前言 本文意在记录,在爬虫过程中,我首次遇到Protobuf时的一系列问题和解决问题的思路. 文章编写遵循当时工作的思路,优点:非常详细,缺点:文字冗长,描述不准确 protobuf用在前后端传输,在 ...
- mysql的导入
方法1 load data [local] infile 'filename' into table tablename[option] ields terminated by 'string'(字段 ...
- 攻防世界—pwn—cgpwn2
题目分析 题目提示 checksec检查文件保护机制 使用ida查看伪代码 hello函数存在溢出,与level2类似 信息收集 system地址 name的地址 编写脚本 from pwn impo ...
- ctfhub技能树—文件上传—双写后缀
双写后缀绕过 用于只将文件后缀名,例如"php"字符串过滤的场合: 例如:上传时将Burpsuite截获的数据包中文件名[evil.php]改为[evil.pphphp],那么过滤 ...