序章
缓存的数据一致性
延时双删
- 淘汰缓存
- 写数据库
- 休眠1s,再次淘汰缓存
缺点:如果mysql是主从复制,去从库中拿去数据,此时同步数据还未完成,拿到的数据是旧数据。
先更新 DB,后删除缓存
- 采用异步延时删除策略. ①利用消息队列进行删除的补偿。②Mysql 数据库更新操作后
再 binlog 日志中我们都能够找到相应的操作,那么我们可以订阅 Mysql 数据库
的 binlog 日志对缓存进行操作。
商城项目的缓存实践
基础实现
tulingmall-portal,商城的首页入口服务。 为了保护数据库应对高并发,我们考虑首先将促销信息放入缓存,在tulingmall-promotion 的 HomePromotionServiceImpl.getHotProducts 。
tulingmall-portal 的 HomeServiceImpl.getFromRemote方法 获取缓存
查询请求我们先从本地 缓存中获取,未获取到再从远程获取。
能不能将缓存的数据再提前呢?于是我们在首页服务内引入了应用级
缓存 Caffeine。代码中 CaffeineCacheConfig为配置类。
于是在 tulingmall-portal 的 HomeServiceImpl.recommendContent 中,对于查询请求我们先从本地 缓存中获取,未获取到再从远程获取
缓存预热
在 tulingmall-portal 启动 时从远程获得相关的数据写入本地的 Caffeine 缓存
public class preheatCache implements CommandLineRunner
在 tulingmall-promotion 中也存在同样的缓存预热机制,负责将数据从 MySQL 数据写入到 Redis 集群中(preheatCache)。
数据一致性
对于 tulingmall-portal 的本地 Caffeine 缓存,我们设置了过期时间 30 分钟并在 RefreshPromotionCache 中以后台任务的形式异步的刷新缓存,每分钟 检查一次本地 Caffeine 缓存是否已无效,无效则刷新缓存。
而对于 Redis 集群中的数据,则是利用 Canal 监测数据库的更新,然后删除 缓存中的对应部分,具体实现在 tulingmall-canal 数据同步程序的 PromotionData 中。Redis 数据的再载入自然由 tulingmall-promotion 负责。
双缓存
同时 tulingmall-portal 中也提供了专门的缓存管理接口CacheManagerController,方便进行强制本地缓存失效和手动刷新本地缓存。
其他
秒杀的活动信息在首页的是单独处理的,但是处理的思路是一致的,只有
细微的地方有所不同,这里不再赘述。
其实首页的这些信息还可以使用固定的图片或者 Http 连接作为本地缓存、 Redis 集群和 tulingmall-promotion 微服务均失效的最终的降级和兜底方案,这个 可以自行实现。
同时我们系统在缓存的使用上,还有可以改进的空间,比如注册用户的布 隆过滤器化以应对缓存穿透,商品信息的缓存化等等。