最近整理了Redis相关缓存问题,以此记录
为什么要用Redis做缓存?
高性能,高并发(QPS:MySQL:1w,Redis:30w+)
Redis 基于内存,内存的访问速度是磁盘的上千倍;
Redis 基于 Reactor 模式设计开发了一套高效的事件处理模型,主要是单线程事件循环和 IO 多路复用;
Redis 内置了多种优化过后的数据结构实现,性能非常高。
Redis缓存更新策略
Cache Aside Pattern(旁路缓存模式):
适合读多场景
写:先更新db,再删除cache,不能先删缓存再写,一写一读导致读旧数据
缓存的写入速度比数据库的写入速度快很多
缺陷:首次请求数据一定不在 cache 的问题;写操作比较频繁的话导致 cache 中的数据会被频繁被删除,这样会影响缓存命中率
解决方法:加分布式锁(强一致);设置较短过期时间(短暂允许不一致场景)
Read/Write Through Pattern(读写穿透):
写:先查 cache,cache 中不存在,直接更新 db。cache 中存在,则先更新 cache,然后 cache 服务自己更新 db(同步更新 cache 和 db)
Write Behind Pattern(异步缓存写入):
Read/Write Through 是同步更新 cache 和 db,
Write Behind 则是只更新缓存,不直接更新 db,而是改为异步批量的方式来更新 db
缓存同步
推荐「先更新数据库,再删除缓存」方案,并配合「消息队列」或「订阅变更日志」(例如:阿里的canal)的方式来做删除
在高并发场景下建议采用延迟双删缓存策略
生产问题
缓存穿透
大量请求的 key 是不合理的,根本不存在于缓存中,也不存在于数据库中 。这就导致这些请求直接到了数据库上,根本没有经过缓存这一层,对数据库造成了巨大的压力,可能直接就被这么多请求弄宕机了
解决方式:布隆过滤器
缓存击穿(热key问题)
请求的 key 对应的是 热点数据 ,该数据 存在于数据库中,但不存在于缓存中(通常是因为缓存中的那份数据已经过期) 。这就可能会导致瞬时大量的请求直接打到了数据库上,对数据库造成了巨大的压力,可能直接就被这么多请求弄宕机了。
解决方式:过期时间加长+辅助线程及时更新数据,互斥锁,热点数据提前预热
缓存雪崩
缓存在同一时间大面积的失效,导致大量的请求都直接落到了数据库上,对数据库造成了巨大的压力。
解决方式:
Redis热点缓存失效问题:给不同的Key的TTL添加随机值,给业务添加多级缓存
Redis服务不可用问题:利用Redis集群提高服务的可用性,给缓存业务添加降级限流策略