Redis 缓存

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