一、Eureka服务端
1.1 集群同步
首先服务端的启动时,会从别的peer中获取注册信息,后续通过互相通知的方式更新注册表。例如:现有三台Eureka Server分别名为A、B、C,当有一个Client注册至Server A,Server A则会将client的注册信息通过Http的方式将增量信息同步至Serber B、C,第一次同步,后续各个peer通过续约的方式保证各个peer之间的弱一致性。
上面的流程中,是看到Eureka没有满足强一致性的,当拉取注册信息后,服务节点之间由于网络延迟或网络波动无法达到强一致性。
1.2 下线
Server端默认在90秒内没有收到Client的心跳会将此实例剔除。在源码内部使用了Timer实现,这块有一个小问题,Timer中存在一个异常,其他任务会全部停止。
1.3 三级缓存
对于注册表信息,为了减少写锁逻辑,使用了三级缓存分别为register、readWriteCacheMap、readOnlyCacheMap。
register使用ConcurrentHashMap,本地最新的注册表信息;
readWriteCacheMap使用Guava Cache(LoadingCache),服务注册时会失效缓存,默认过期时间为180秒;
readOnlyCacheMap使用ConcurrentHashMap,客户端获取注册表信息的缓存,每30秒从readWriteCacheMap同步一次;
这三级缓存也是一个Eureka未实现强一致性的一个点。
在这里使用锁的逻辑还是比较叼的一波反向操作,正常我们的理解在写的时候加写锁,读取的时候加写锁。在这里当客户端获取服务端注册表信息的同时,别的客户端也是可以执行注册、下线、剔除的操作这些操作都会改变数据的appHashCode(ount + state),如并发操作则会导致appHashCode不一致,从而导致客户同步失败,所以在客户端拉取注册表信息的时候需要增加写锁已保证同步完成;而在更新注册表信息以及队列信息时候采用读锁,因为这些容器本身已经是安全容器了不需要在通过加互斥锁的方式来达到线程安全。
1.4 自我保护
自我保护本质是防止网络延时、波动而导致将服务剔除。默认在15分钟内客户端心跳占比低于85%会触发自我保护。触发后是不会剔除服务的,
二、Eureka客户端
客户端在启动时,会将自己注册至ServerUrl中的第一个地址,如第一个失败则注册至第二个,第二个失败则注册至第三个,到此处就结束了,只会尝试三个客户端。当注册成功后全量拉取服务端注册表信息,后续默认每隔30秒增量拉取注册表信息。
三、优化
Eureka的优化主要是围绕减少服务的上下线延时。
- 自我保护在服务多的时候开启,服务少的时候关闭;
- 关闭三级缓存;
- 跳转续租间隔时间;
- 跳转本地拉取注册表间隔时间;
- 打乱ServerUrl顺序;
Eureka 的定时器是真的多。。。。
先简单写一些关键点吧,后续再详细跟进源码。
先粗后细,先广再深。