当前位置:网站首页>图文详述Eureka的缓存机制/三级缓存
图文详述Eureka的缓存机制/三级缓存
2022-08-01 19:26:00 【秃秃爱健身】
前言
1、为什么说Eureka是CAP理论中的AP?
从CAP理论看,Eureka是一个AP系统,其优先保证可用性(A)和分区容错性§,不保证强一致性,但能做到最终一致性。
- 因为只要集群中
任意一个实例不出现问题,Eureka服务就是可用的;即Eureka Client 在向某个 Eureka Server 注册时,如果发现连接失败,则会自动切换至其它节点; - 另外Eureka集群中没有主从的概念,各个节点都是平等的,节点间采用Replicate异步的方式来同步数据;
也正因为Eureka 本身不保证数据的强一致性,所以在架构又设计了很多缓存。
2、为什么要设计那么多缓存(三级缓存)?
这个和MySQL用主从做读写分离很相似,数据库层面的读写分离是为了分摊主数据库的读压力;而Eureka的三级缓存也是为了做读写分离,使写操作不阻塞读操作。
- 因为在
写的时候,线程会持有ConcurrentHashmap相应Hash桶节点对象的锁,阻塞同一个Hash桶的其他读线程。 - 这样可以有效的降低读写并发,避免读写读写争抢资源所带来的压力。
那么加了那么多缓存,如何保证缓存数据的最终一致性?
我们下面就详细聊一下Eureka是如何做的。
缓存机制
Eureka Server中有三个变量用来保存服务注册信息,分别是:registry、readWriteCacheMap、readOnlyCacheMap;默认情况下定时任务每30s将二级缓存readWriteCacheMap同步至三级缓存readOnlyCacheMap;
1、Eureka Server每60s清理超过90s * 2(官方彩蛋)未续约的节点;
2、Eureka Client每30s从readOnlyCacheMap更新服务注册信息;
3、UI界面则从registry获取最新的服务注册信息。
1、三级缓存分别是什么?
| 缓存 | 缓存类型 | 所处类 | 概述 |
|---|---|---|---|
| registry 一级缓存 | ConcurrentHashMap | AbstractInstanceRegistry | 实时更新,又名注册表,UI界面从这里获取服务注册信息; |
| readWriteCacheMap 二级缓存 | Guava Cache(LoadingCache) | ResponseCacheImpl | 实时更新,缓存时间180秒; |
| readOnlyCacheMap 三级缓存 | ConcurrentHashMap | ResponseCacheImpl | 周期更新,默认每30s从二级缓存readWriteCacheMap中同步数据更新; Eureka Client默认从这里获取服务注册信息,可配为直接从readWriteCacheMap获取 |
二级缓存又称读写缓存、三级缓存又称只读缓存;
1)Eureka Server缓存相关配置
| 配置名 | 默认值 | 概述 |
|---|---|---|
| eureka.server.useReadOnlyResponseCache | true | Client从readOnlyCacheMap更新数据,false则跳过readOnlyCacheMap直接从readWriteCacheMap更新 |
| eureka.server.responsecCacheUpdateIntervalMs | 30000 | readWriteCacheMap更新至readOnlyCacheMap的周期,默认30s |
2、缓存之间的数据同步
AbstractInstanceRegistry类中的registry字段为注册表、并与保存一级缓存(实时最新数据);ResponseCacheImpl类中的readWriteCacheMap字段和readOnlyCacheMap字段分别表示二级缓存和三级缓存;下面我们就围绕这两个类、三个字段的数据同步展开讨论。
1)注册一个服务实例
Eureka Server中做的操作:
向注册表registry中写入服务实例信息,并使得二级缓存失效;

Eureka client第一次向Eureka Server注册服务或者发送心跳续约时,会进去到Eureka Serve中ApplicationResource#addInstance()方法中:
最终进入到AbstractInstanceRegistry#register()方法中,往其registry字段中添加服务注册信息:
这里以服务注册为例,我们知道了registry的数据来源;
注意,在做服务注册的最后会将二级缓存清空/失效;
下面我们接着来看一下Eureka的二级缓存和三级缓存是如何运作的?
2)二级/三级缓存什么时候初始化?
Eureka Server启动的时候会根据SpringBoot自动装配的特性,初始化EurekaServerContext接口的实现类DefaultEurekaServerContext;在DefaultEurekaServerContext初始化时会执行构造器后置逻辑initialize(),其中会初始化注册中心;
接着进入到PeerAwareInstanceRegistry接口的实现类PeerAwareInstanceRegistryImpl#init()方法中,其中会通过调用initializedResponseCache()方法初始化二级/三级缓存;
3)二级/三级缓存初始化都做了什么?
这里可以看到initializedResponseCache()方法中直接new了一个ResponseCacheImpl类;
我们接着进入到ResponseCacheImpl类中,看一下它的构造函数:
总的来说,在初始化ResponseCacheImpl类时:
- 会设置初始化二级缓存
readWriteCacheMap(过期时间180s),设置二级缓存往三级缓存readOnlyCacheMap同步的时间间隔(默认30s)。 - 设置是否使用三级缓存(默认使用),如果使用则启动一个定时任务,默认每隔30s从二级缓存中同步数据到三级缓存(只更新三级缓存中已存在的key);
4、发现/寻找一个服务
针对Eureka Client和UI界面,他们读取的服务注册信息的方式略有不同:
- 针对Eureka Client:
1、如果使用只读缓存(三级缓存)<默认使用>,则先从只读缓存中获取;如果获取不到,则从读写缓存(二级缓存)中获取,并将数据缓存到只读缓存;
2、不使用只读缓存,则直接从读写缓存中获取;如果获取不到则触发guava的回调函数从注册表registry中同步数据(即从一级缓存 – 注册表registry中取)- 而对于UI界面,则是实时从一级缓存(注册表registry)中取。
对于Eureka Client无论是获取一个Application的信息(入口为ApplicationResource#getApplication())还是获取所有Application的信息(入口为ApplicationsResource#getContainers())都会进入到ResponseCacheImple#get(Key key)方法,然后进过此路径《get(key, shouldUseReadOnlyResponseCache) --> getValue(final Key key, boolean useReadOnlyCache)》最终走到真正从缓存中读取数据的逻辑:

总结
1、Eureka Server 在接收Eureka Client注册的时候,会将读写缓存(二级缓存)清空;
2、Eureka Server启动时会做两件事:
- 会初始化读写缓存(
二级缓存),从注册表registry(一级缓存)中实时加载数据,默认180s过期;- 判定是否使用只读缓存(三级缓存),默认开启;如果使用则开启一个定时任务,默认每30s做一次读写缓存到只读缓存的数据同步;
3、Eureka Client获取服务信息时,默认先从只读缓存获取;获取不到再从读写缓存中获取,并将数据缓存到只读缓存;获取不到,再触发guava的回调函数从注册表中同步(即从一级缓存 – 注册表registry中取)。
1、多级缓存带来的好处?
- 尽可能的避免服务注册出现频繁的读写冲突,写阻塞读;
- 提高Eureka Server服务的读写性能。
面对频繁读写资源争抢、写阻塞读等情况,我可以考虑借鉴Eureka的多级缓存方案做读写分离。
边栏推荐
猜你喜欢

#yyds干货盘点# 面试必刷TOP101: 链表中倒数最后k个结点

Fuzzy query in Map pass-by-value and object pass-by-value

硬件大熊原创合集(2022/07更新)

Redis的内存淘汰策略和过期删除策略的区别是什么

使用常见问题解答软件的好处有哪些?

kubernetes - deploy nfs storage class
![[pyqt5] Custom controls to achieve scaling sub-controls that maintain the aspect ratio](/img/99/34f223614449fcee8e9322dff2e839.png)
[pyqt5] Custom controls to achieve scaling sub-controls that maintain the aspect ratio

30分钟成为Contributor|如何多方位参与OpenHarmony开源贡献?

10 个 PHP 代码安全漏洞扫描程序

MLX90640 Infrared Thermal Imager Temperature Measurement Module Development Notes (Complete)
随机推荐
openresty 动态黑白名单
odoo coding conventions (programming conventions, coding guidelines)
log factory (detail)
modbus总线模块DAM-8082
What are the application advantages of SaaS management system?How to efficiently improve the digital and intelligent development level of food manufacturing industry?
C#/VB.NET 从PDF中提取表格
安徽建筑大学&杭州电子科技大学|基于机器学习方法的建筑可再生能源优化控制
kubernetes - deploy nfs storage class
【综述专栏】IJCAI 2022 | 图结构学习最新综述:研究进展与未来展望
通配符 SSL/TLS 证书
1个小时!从零制作一个! AI图片识别WEB应用!
#yyds dry goods inventory# Interview must brush TOP101: the last k nodes in the linked list
How to query database configuration parameters in GBase 8c, such as datestyle.What function or syntax to use?
Choosing the right DevOps tool starts with understanding DevOps
No need to crack, install Visual Studio 2013 Community Edition on the official website
123123123123
1个小时!从零制作一个! AI图片识别WEB应用!
ThreadLocal讲义
Keras深度学习实战——交通标志识别
Creo5.0草绘如何绘制正六边形