SpringCache+Redis+Canal+Redisson,分布式锁/分布式缓存,读写模式,缓存击穿/穿透/雪崩,SpringCloud-SpringCache技术解决方案讨论与总结。
Redis缓存问题:穿透,击穿,雪崩
读模式,lazy版,遇到缓存没有的数据,去数据库读,然后载入数据库写模式,positive版 双写,失效模式
缓存雪崩
同一时间大规模key失效,大量请求涌入数据库
解决:失效时间添加随机值避免雪崩
缓存击穿
热点key突然失效,大并发涌入数据库。
解决:针对业务情况,过于热点key不过期(但一定要注意key的生成量相关问题,避免爆内存)加锁,拿到锁才允许查数据库
缓存穿透
访问到了非法key值,该key值不存在,即为大量缓存不命中,全部打到数据库,而数据库也没有响应数据,导致缓存永远没法正常起效。
解决:给数据库也没有的值也添加至缓存,例如null值进缓存。
-(但是该方法也存在问题,大量非法请求的话,每次随机,则缓存每次也不命中,缓存无意义,)给查询做过滤,查询前判断是否存在该key,不存在直接返回。
redis分布式锁
使用redisson,redisson实现了juc里面的各种锁 看门狗机制
自动续期机制,默认30秒一个锁,到时间业务没结束自动续期,结束了则自动删锁。但是在调用lock()方法时手动指定锁的时间的话,没有自动续期机制(可以足够长,确保业务完成) 常用锁介绍
缓存一致性问题
双写模式
写数据库同时写缓存失效模式
数据更新后写数据库,删除原缓存。
-解决:读写锁,面向多读情况,少写,性能影响较小(并且分布式读写锁)缓存主动更新
以上两种均存在问题,即缓存一致性问题
对于即时性要求不高的业务,容忍度提高,缓存一致性可以忽略。 使用Canal,mysql的binlog机制mysql更新同时,Canal作为mysql子节点,订阅binlog同步至其他中间件,例如redis利:无需关心缓存同步,专心处理数据库即可。弊:增加中间件,添加各种复杂度等。Cannal在大数据方面应用,订阅到多张表数据,进行数据分析,然后数据异构出适合用户的推荐表等
SpringCache 缓存抽象层
通过注解解决分布式缓存的以上各种问题,使用简单注解解决技术痛点。CompositeCacheManager 缓存管理器管理多个CacheManagerCacheManager 管理缓存(类似单个容器)多种实现 ConcurrentMapCache,redis,等。例如ConcurrentMapCache内用ConcurrentMap来管理缓存,保存在store属性里。实际操作是Cache组件。Crud。 整合SpringCache 引入依赖
配置
自动配置:
CacheConfigurations,里使用什么作为缓存中间件,则会放入到配置的MAPPINGS内,使用静态代码块初始化put到Mappings里,那我们使用Redis,实际上会再导入RedisCacheConfiguration类做自动配置,里面有个RedisCacheManager(会初始化所有缓存),实际配置这个提供这个Bean即可。RedisCacheManager会读取配置文件,默认配置基础上,自己配置例如名字之类的,初始化我们的缓存。
自动配置内容:字符序列化器,key前缀,等
我们需要做的配置
使用缓存注解操作缓存@Cacheable 触发将数据保存到缓存的操作(将方法返回值放入缓存)@CacheEvict 出发缓存删除操作@CachePut 不影响方法执行更新缓存@Caching 复合多种以上操作@CacheConfig 类级别共享缓存配置 读模式缓存使用
开启缓存功能
启动类添加@EnableCaching注解即可
给方法添加注解即可完成
@Cacheable,加在有查数据库的方法上,表示自动缓存,以后缓存中有则当前方法不会调用,直接返回缓存内数据缓存中没有,则调用该方法,返回值放入缓存,以供以后使用
每一个需要缓存的数据@Cacheable()注解需要指定参数,缓存名字,
@Cacheable({“category”,“xxxx”}) 此注解标注的名字类似给缓存分区,指定相同name的在一个区,类似namespace名称空间的东西。
@Cacheable注解常用参数:value=xxx 即等同于上述未指定参数起名分区key 缓存key名,可以为参数指定key=“#root.method.name”SpEL表达式语法,参考官方文档。举例:#root.method.name…
-sync =true //查询加锁,解决击穿
默认行为缓存中没有那就执行,缓存中有,方法不执行直接给缓存值。key默认自动生成,缓存名字::simplekey []自定义生成的值序列化使用java序列化器默认ttl -1 即为无过期时间。
自定义指定json序列化器
配置文件指定存活时间
缓存null值,缓存穿透问题
写模式缓存失效缓存使用
方法替换为@CacheEvict即可
多缓存操作,例如一个更新删多个缓存
缓存修改
总结讨论,与 SpringCache不足 读模式穿透击穿雪崩
相应使用上述解决方案 写模式-数据一致性问题读写加锁引入Canal,感知Mysql变动更新数据库 读写都多,考虑不适用缓存,直接查数据库
总结:常规数据,读多写少,一致性宽容度高,可以使用SpringCache。那特殊读写都多,且宽容度低之类的,特殊设计。