Redis 缓存
缓存更新策略
- 低一致性业务建议配置最大内存和淘汰策略的方式使用。
- 高一致性业务可以结合使用超时剔除和主动更新,这样即使主动更新出了问题,也能保证数据过期时间后删除脏数据。
缓存击穿
为了避免缓存击穿给数据库带来的激增压力,我们的解决方法也比较直接,对于访问特别频繁的热点数据,我们就不设置过期时间了。这样一来,对热点数据的访问请求,都可以在缓存中进行处理,而Redis数万级别的高吞吐量可以很好地应对大量的并发请求访问。
穿透优化
缓存穿透是指查询一个根本不存在的数据,缓存层和存储层都不会命中,通常出于容错的考虑,如果从存储层查不到数据则不写入缓存层。缓存穿透将导致不存在的数据每次请求都要到存储层去查询,失去了缓存保护后端存储的意义。
通常可以在程序中分别统计总调用数、缓存层命中数、存储层命中数,如果发现大量存储层空命中,可能就是出现了缓存穿透问题。造成缓存穿透的基本原因有两个。第一,自身业务代码或者数据出现问题,第二,一些恶意攻击、爬虫等造成大量空命中。下面我们来看一下如何解决缓存穿透问题。
- 缓存空对象。设置较短过期时间,自动剔除,可以减少内存占用;存储层有了数据,可以利用消息系统或其它方式清楚掉缓存中的空对象。
- 布隆过滤器拦截
雪崩优化
大量 Key 同时过期
我们可以避免给大量的数据设置相同的过期时间。如果业务层的确要求有些数据同时失效,你可以在用EXPIRE命令给每个数据设置过期时间时,给这些数据的过期时间增加一个较小的随机数(例如,随机增加1~3分钟),这样一来,不同数据的过期时间有所差别,但差别又不会太大,既避免了大量数据同时过期,同时也保证了这些数据基本在相近的时间失效,仍然能满足业务需求。
除了微调过期时间,我们还可以通过服务降级,来应对缓存雪崩。
所谓的服务降级,是指发生缓存雪崩时,针对不同的数据采取不同的处理方式。
- 当业务应用访问的是非核心数据(例如电商商品属性)时,暂时停止从缓存中查询这些数据,而是直接返回预定义信息、空值或是错误信息。
- 当业务应用访问的是核心数据(例如电商商品库存)时,仍然允许查询缓存,如果缓存缺失,也可以继续通过数据库读取。
Redis 缓存实例故障宕机
- 保证缓存层服务高可用性。和飞机都有多个引擎一样。可以采用限流或降级方案。
- 依赖隔离组件为后端限流并降级
热点 Key 重建优化
在缓存失效的瞬间,有大量线程来重建缓存,造成后端负载加大,甚至可能会让应用崩溃。
- 互斥锁
Redis 热 Key 如何解决,降级成本地缓存。不过需要加监测,而且 Redis 本身也有 hotkeys 参数可以监测,还可以实时分析用户请求。
MySQL 同步到 Redis
数据更新服务只负责处理业务逻辑,更新 MySQL,完全不用管如何去更新缓存。负责更新缓存的服务,把自己伪装成一个 MySQL 的从节点,从 MySQL 接收 Binlog,解析 Binlog之后,可以得到实时的数据变更信息,然后根据这个变更信息去更新 Redis 缓存。
这种收 Binlog 更新缓存的方案,和收 MQ 消息更新缓存的方案,其实它们的实现思路是一样的,都是异步订阅实时数据变更信息,去更新 Redis。只不过,直接读取 Binlog 这种方式,它的通用性更强。不要求订单服务再发订单消息了,订单更新服务也不用费劲去解决“发消息失败怎么办?”这种数据一致性问题了。
这个方案唯一的缺点是,实现订单缓存更新服务有点儿复杂,毕竟不像收消息,拿到的直接就是订单数据,解析 Binlog 还是挺麻烦的。
有很多开源的项目就提供了订阅和解析 MySQL Binlog 的功能,常用的开源项目有 Canal。