缓存在现代计算机系统中无处不在,各式各样硬件和软件的组合构成和管理着缓存,一个编写良好的计算机程序倾向于展示出良好的局部性。
创新互联建站是一家网站设计公司,集创意、互联网应用、软件技术为一体的创意网站建设服务商,主营产品:响应式网站建设、品牌网站设计、全网整合营销推广。我们专注企业品牌在网站中的整体树立,网络互动的体验,以及在手机等移动端的优质呈现。做网站、成都网站制作、移动互联产品、网络运营、VI设计、云产品.运维为核心业务。为用户提供一站式解决方案,我们深知市场的竞争激烈,认真对待每位客户,为客户提供赏析悦目的作品,网站的价值服务。
在高性能服务架构设计中,缓存是一个不可或缺的环节。以Java体系为例,我们从传统的硬编码方式使用缓存到基于注解的spring-cache框架,确实大大提升了我们的效率,代码也更加的简洁易维护。
但随着越来越多的项目使用spring-cache,场景越来越复杂,我们逐渐发现缓存配置代码重复、缓存策略不能在注解上直接配置、不支持多级缓存、不支持自动刷新缓存等问题逐渐突显。
基于这些在业务中遇到的问题点,我们构建了一套注解式两级缓存服务框架。在实际设计和构建过程中积累了一些经验,借此机会分享给大家,希望对业务中使用缓存尤其使用spring-cache场景的可以提供一些帮助。
Spring 3.1之后,引入了注解缓存技术,其本质上不是一个具体的缓存实现方案,而是一个对缓存使用的抽象,不仅能够使用SpEL(Spring Expression Language)来定义缓存的key和各种condition,还提供开箱即用的缓存临时存储方案,也支持和主流的专业缓存集成。
事物都有两面性,优点如此优秀,那么缺点或不足是否也是如此的突出呢?
基于以上我们认为的问题点,我们造了一个轮子,来试图解决这些问题,这个轮子就是“注解式两级缓存框架”。
只使用一级缓存
只使用二级缓存
同时用两级缓存
前菜我们品完了,接下来我们开始正餐,一步步介绍下设计思路,聊下如何站在spring-cache巨人肩膀上,试图解决上述问题点的。
1、注解@EnableCache导入CacheConfigurationSelector。
CacheConfigurationSelector向容器内注入了AutoProxyRegistrar和ProxyCacheAutoConfiguration这两个Bean
2、AutoProxyRegistrar会确保容器中存在一个自动代理创建器(APC),缓存的代理对象最终是委托给自动代理创建器来完成。
AutoProxyRegistrar在容器启动阶段对每个bean创建进行处理,如果bean中有方法标记了cache注解,为其创建代理对象, 包裹定义的CacheOperationSourceAdvisor bean
3、ProxyCacheAutoConfiguration向容器定义如下基础设施bean。
CacheOperationSourceAdvisor 用于管理CacheOperationSource和CacheInterceptor, CacheOperationSource 用于获取方法调用时最终应用的Cache注解的元数据, CacheInterceptor 包裹在目标bean外面用于操作Cache的AOP Advice
由于AutoProxyRegistrar在容器启动阶段会对标有cache注解的bean创建代理对象,这时我们可以获取到具体方法和注解元数据, 我们针对两部分数据进行绑定提前缓存起来,这样目标方法调用时直接从缓存中获取元数据即可,避免了反射效率低下影响性能。
1、根据目标方法和目标类获取注解元数据,元数据包括缓存名称、缓存key、过期时间、自动刷新时间、本地缓存容量、缓存类型、缓存条件等。
2、根据缓存条件是否走注解缓存,缓存条件支持SpEL表达式,如果为false则直接执行目标方法,为ture走缓存逻辑。
3、生成key:支持SpEL表达式,可以自定义生成规则,默认规则:命名空间、所属类名称、方法名称、方法参数以冒号相连。
4、获取cache:根据cacheName和cacheType获取cache,对应cache有本地cache、远程cache、两级cache,根据key获取缓存结果, 缓存结果为空则执行目标方法并对结果缓存,反之直接返回缓存结果。
cache实现类有三种LocalCache、RemoteCache和TwoLevelCache,每个缓存实现类集成了具体的缓存中间件,LocalCache可以集成Caffeine、Guava、ehCache等, RemoteCache可以集成Redis、Memcache等,TwoLevelCache是LocalCache和RemoteCache组合实现。
1、CacheManagerContainer管理着所有的CacheManager,每个cacheType对应一个CacheManager的实现。
2、CacheManager提供了cache实现bean的创建,管理着多个cache,每个cache有对应的cacheName,每个应用里可以通过cacheName来对cache进行隔离,如果cacheName对应的cache不存在则会注册一个新的cache。
3、Cache接口提供了缓存的具体操作,例如放入,读取,清理等。
两级缓存的产生是因为远程缓存有网络开销,大量的缓存读取会导致远程缓存网络成为整个系统的瓶颈,本地缓存是和应用程序在一个进程内,请求缓存速度快,没有过多的网络开销, 加入本地缓存目标是降低对远程缓存的读取次数,减轻网络开销,从而再次提升程序的响应速度与服务性能。
1、从本地缓存读出数据,如果存在则直接返回,进行后续具体业务逻辑。
2、本地缓存如果不存在则读取远程缓存,远程缓存如果存在则更新本地缓存,不存在则从数据源读取,然后依次更新远程缓存、本地缓存,然后进行后续具体业务逻辑。
防止某个缓存失效时,访问量突然大增,所有请求访问数据库,可能导致数据库挂掉;适用场景:key数量比较少,访问量大,加载开销较大的情况。
1、缓存读取时如果元数据自动刷新时间有值,会根据缓存key、目标方法、刷新时间创建一个给定初始延迟的间隔性的任务,任务自动执行间隔为自动刷新时间, 任务执行时会根据缓存key、目标方法重新加载缓存,保持缓存一直生效。
2、根据自动刷新时间会生成一个停止刷新时间,如果缓存key访问间隔时间超过了停止刷新时间或者缓存key过期,会删除该定时任务,释放资源,避免无效的刷新缓存。
3、两级缓存刷新缓存顺序为:先刷新远程缓存,然后根据Redis的pub/sub模式去监测和操作本地cache的删除动作,随后第一次请求会检查本地缓存--->再检查Redis缓存--->回源。
4、远程缓存自动刷新使用分布式锁,对同一key,全局只有一台机器自动刷新。
1、 @Cacheable可以作用在方法上,也可以标记在一个类上,当标记在一个方法上时表示该方法是支持缓存的,当标记在一个类上时则表示该类所有的方法都是支持缓存的
名称 |
默认值 |
说明 |
value |
空字符串 |
缓存名称,cacheName的别名 |
cacheName |
空字符串 |
缓存名称 |
key |
空字符串 |
缓存key,支持SpEL表达式,提供默认生成策略 |
ttl |
10分钟 |
过期时间,d/h/m/s四种时间单位选择,分别代表天/时/分/秒, ttl="10m"表示10分钟过期时间 |
refreshTime |
空字符串 |
自动刷新时间,d/h/m/s四种时间单位选择,分别代表天/时/分/秒 |
maximumSize |
5000 |
本地缓存容量 |
cacheType |
REMOTE |
缓存类型,LOCAL/REMOTE/BOTH三种选择,分别代表本地缓存/集中式缓存/两级缓存 |
condition |
空字符串 |
指定符合条件的情况下才缓存,为空则认为全部无条件缓存,支持SpEL表达式 |
2、key默认生成规则:命名空间、所属类名称、方法名称、方法参数以冒号相连。
3、如果设置ttl为空:表示缓存永不过期。
这里举个例子,具体的参数值,根据自己业务情况自行调整。
auto:
cache:
local:
type: caffeine
remote:
type: redis
host: localhost #服务器地址
port: 6379 #服务器连接端口
timeout: 2000 #连接超时时间(毫秒)
pool:
min-idle: 2 #最小空闲连接数
max-idle: 10 #最大空闲连接数
max-active: 20 #连接池的最大数据库连接数
max-wait: 200 #最大建立连接等待时间
key-serializer: org.springframework.data.redis.serializer.StringRedisSerializer #key序列化策略
value-serializer: org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer #value序列化策略
namespace: testCache # 缓存的命名空间前缀,最终缓存格式为:testCache:xxx:xx
allow-null-values: true #防止缓存穿透
本文主要是记录了商业资源组在使用spring-cache过程中遇到的问题点及注解式两级缓存服务框架设计思路,通过一步步拆解,将问题点逐个击破。该框架在实际项目中也经过了千万级别的验证,为我们的线上服务提供了良好的性能。
构建一套完整的服务框架需要不断的迭代功能开发,后续要逐步支持的功能如下:
增加熔断与降级
增加缓存数据压缩
增加缓存一致性
增加缓存监控统计看板
增加自定义缓存中间件
增加缓存接口用于手工缓存操作
https://github.com/ben-manes/caffeine/wiki/Benchmarks
https://docs.spring.io/spring-framework/docs/4.3.x/spring-framework-reference/html/expressions.html
作者介绍:王云朋
名称栏目:注解式两级缓存服务框架设计与构建
URL标题:http://www.shufengxianlan.com/qtweb/news17/212467.html
网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等
声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联