分布式缓存技术方案
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
一、背景
在高并发的分布式的系统中,缓存是必不可少的一部分。
没有缓存对系统的加速和阻挡大量的请求直接落到系统的底层,系统是很难撑住高并发的冲击,分布式系统中缓存的设计是很重要的一环
使用缓存的收益:
●加速读写,缓存一般是内存操作,要比传统数据库操作要快的多
●降低后端的负载。
缓存一些复杂计算或者耗时得出的结果可以降低后端系统对CPU、
IO、线程这些资源的需求
●本地缓存远端调用结果,减少服务间的调用,提升服务并发能力
目前问题:
●目前业务中对缓存的使用并不多,在这次直播活动中,组件性能瓶劲很多,有很大一
部分是可以通过缓存加速的
●疫情直播活动期间,几个核心服务由于人手、改造难度问题等,最后由罗陈珑做一了
个缓存代理服务,把UC、EOMS的部分接口做了缓存代理,这些缓存本来应該由服务提供者来实现的
●数据一致性问题,加了缓存之后,随之而来的就是数据一致性的问题,发现有数据不
能及时更新
●目前大家对缓存使用方式不太统一,有的组件使用本地JVM缓存时封装太复杂,出现
问题不好定位,清除缓存也不好做
二、目标
●降低分布式缓存技术使用门槛,将分布式缓存框架作为微服务开发必备的脚手架,让
开发者更易使用,避免因技术门槛而放弃使用缓存
梳理核心业务,使用分布式缓存加速服务响应速度,降低服务负载
三、分布式缓存方案
3.1 @WafCacheable 缓存
3.1.1 分布式缓存和本地jvm缓存
为了提高接口能力,需要将一些频繁访问但数据更新频率比较低的放入缓存中,不要每次从数据库或其他耗时耗资源的数据源中取。
使用@WafCacheable 注解,缓存过期时间可以根据数据更新频率自由设定,不设置默认为2小时。
@WafCacheable 标记的方法被拦截后,数据获取的优先级:本地jvm缓存>redis缓存> 数据源(DB、RMI、其他耗时耗资源的操作)
@WafCacheable
使用场景:高频访问低频更新的数据
注意:@WafCacheable 对同一个类里的内调方法(A调B, B上加注解不生效),如果直接用this.B(),加在B上的缓存不生效,需要使用${service}.B()调用(${service}指service实例)。
3.1.2 RMI缓存
RMI(Remote Method Invocation)是指微服务提供的SDK中FeignClient方式申请的接
口,具体参考
/noteshare?id=dda3f2af3976689339c9ffa5ba0b0675 RMI上也可以加@WafCacheable注解。
使用场景:对于数据变化频率在2小时以上的,为了减少服务端的请求,提高接口性能
缓存方式:本地jvm缓存
作用域:客户端/消费者,拦截的包要注意,只拦截以下规则的包命名
建议RMI上缓存时间不要超过同一接口service上的过期时间的1/2, 最好设置为1/4.
3.1.3 关闭缓存方法
1)配置文件中修改
●在application.yml中加入
waf:
cache:
enabled: false
注意:生产环境禁止关闭缓存
●调用rest接口关闭当前结点缓存
2)管理接口动态设置
3.1.4 缓存配置
默认情况下缓存是开启状态,缓存队列大小3W,单个对象20K以下会放入jvm,否则只放入redis,当然也可以通过缓存模式可以强制指定放入jvm.
application.yml 配置:
waf:
cache:enabled: true #控制缓存开关max-object-siz e: 30 #缓存单条对象最大上限大小,单位k b max-queue-si ze: 20000 #缓存队列上限
3.1.5 缓存注解的使用
3.1.5 手动使用缓存
CacheService是封装了jvm缓存和redis缓存,在使用sdk操作缓存时,会同时往jvm和redis都放一份,部分api支持对象大于设置的单个对象大小上限可不放jvm. RedisService封装redis的基本操作,包含分布式锁的操作。
3.2 缓存清除/数据一致性问题
缓存能极大的提高系统负载能力,但同时也引入新的问题,数据一致的问题,当一个业务规则或缓存的源数据发生变化时,一般要求被缓存的数据也需要立即更新为最新的数据(少数场景是对数据实时性不敏感或有一定的容忍度)
3.2.1 缓存清理的难点
●缓存key不确定。
通过@Wafcacheable注解设置的缓存,缓存key的生成策略为如果设置了自定义key 的前缀,则使用自定义key前缀+各个参数拼接而成,如果没有设置自定义key则使用包名+类名+方法名+各个参数拼接而成。
●缓存存在多个节点中。
缓存不仅有微服务提供者内部缓存,还有客户端(消费端)的缓存,一般是在rmi通过@Wafcacheable设置的。
缓存既有jvm缓存也有redis缓存。
jvm缓存存在于每个application中。
这样意味着需要清除所有微服务节点内部的jvm缓存及redis缓存,包括客户端(消费者端)缓存。
3.2.2 LRU+TTL算法缓存更新
在被动更新缓存上是采用LRU+TTL组合算法实现缓存更新,也就是说只要缓存达到任一清除条件(缓存过期或LRU)都会被清除
LRU算法,当缓存容量不足时(控制了缓存上限,避免OOM),淘汰最久没有被访问过的,始终保持热数据的缓存命中率
TTL算法,也就是超时剔除,给缓存数据手动设置一个过期时间,当超过时间后,再次访问时从数据源重新加载并设回缓存期,
3.2.3 主动通知缓存更新(立即生效)
由上层应用在配置更新后,通过MQ消息通知给微服务,微服务各应用节点以广播消
息的方式消费,清除本节点内的缓存。
适用场景:适用数据一致性要求高,对数据不一致容忍度低的场景
优点:数据一致性高,实现方式简单,上层应用改动比较小,只需在缓存的数据发生变化后发送一条mq消息
缺点:上层应用需要按照清除缓存规则在相应的增、删、改的功能处增加mq消息。
缓存key规则说明:
"," 英文逗号表示且的关系,检索同一个key中包含的逗号分隔的多个关键字
";" 英文分号表示或的关系,检索封号分隔的多个key.
例如:city,010;getAllCity
解释:
⏹检索缓存key中同时包含city和010字符串的key
⏹检索缓存key中包含getAllCity的key.
3.3 内置缓存管理
3.3.1 开关缓存
请求
地址
/cache/edit
请求
类型
GET
接口描述手动控制缓存开关
注意:不要轻意关闭整个缓存,目前生产上流量比较大,关闭整个缓存会对数据库有较大压力
如需紧级让某个开关生效,可以调用清除缓存的方法单个清缓
请求示例http://xxxxx/app/cache/edit?enable=close 关闭缓存http://xxxxx/app/cache/edit?enable=t 开启缓存
响应示例true 开启缓存false 关闭缓存
3.3.2 打印jvm缓存
请求
地址
app/cache/stack 请求
类型
GET
接口描述以json 格式输出全部jvm缓存,包括key及value 此方法可用于调试缓存内变量
请求
示例
http://xxxxx/app/cache/stack
响应示例响应示例
{
"code": 200,
"message": "OK",
"result": {
}
}
3.3.3 打印jvm缓存队列大小
请求
地址
/cache/stack/size
请求
类型
GET
接口
描述
仅输出jvm内缓存key的个数
请求
示例
http://xxxxx/app/cache/stack/size
响应示例{ "size": 3963 }
3.3.4 打印所有jvm缓存key
请求地
址
/cache/stack/keys
请求类
型
GET
接口描
述
输出当前进程中所有jvm缓存的key
请求示
例
http://xxxxx/app/cache/stack/keys
响应示
例
3.3.5 模糊搜索缓存中的key
请求地
址
/cache/keys/_search
请求类
型
GET
接口描
述
模糊搜索某个key, 大小写无关
请求示
例
http://xxxxx/app/cache/keys/_search?q=com 响应示
例
3.3.6 清除全部jvm缓存
请求地
址
/cache/clearjvm
请求类
型
GET
接口描述清除全部jvm内存
注意:尽量不要使用清除全部jvm内存,可以使用清除特定缓存操作
请求示
例
http://xxxxx/app/cache/clearjvm
响应示例响应示例
{
"code": 200,
"message": "OK",
"result": {}
}
3.3.7 清除指定key缓存
请求地
址
/cache/clear
请求类
型
POST
接口描
述
清除缓存,可以清除多个缓存
请求示例http://xxxxx/app/cache/clear body:
[
"key"
]
响应示例响应示例
{
"code": 200,
"message": "OK",
"result": {}
}
3.3.8 缓存状态
请求地
址
/cache/states
请求类
型
GET
接口描
述
输出当前进程的缓存状态
请求示
例
http://xxxxx/app/cache/states
响应参数说明enabled 是否开启缓存
maxQueueSize 缓存对列大小
maxObjectSize 单个key允许对象最大大小,单位kb
响应示例{
"enabled": true, "maxQueueSize": 30000, "maxObjectSize": 20
}
3.3.9 获取缓存中某个key的值
/cache/get
请求地
址
GET
请求类
型
输出key对应的值
接口描
述
请求示
/cache/get?key={key}
例
响应示
例。