Redis-缓存问题与解决


前言

Redis 缓存在高并发的情况下,能够大大地减轻数据库压力。但在一些情况下,大量的请求在 Redis 都未能够命中,转而访问数据库,则可能引发数据库、应用服务器宕机等问题。

缓存预热

​ 缓存预热是指,在应用服务上线之前,将相关的热数据加载到缓存系统中。以避免服务上线,大量请求涌入,导致数据库、应用服务器以及缓存服务器宕机。

发生现象

Redis 服务刚启动,主从间数据吞吐量较大,数据同步操作频度较高,数据库或应用服务迅速崩掉。

解决方案

  1. 使用 Nginx + Lua 将访问情况上报到 Kafka
  2. 使用 Storm 等实时流计算引擎从 Kafka 中消费数据,实时统计出热点数据,利用 LRU 保存策略构建数据留存队列
  3. 根据数据级别,Redis 优先加载热度较高的数据。

缓存雪崩

​ 大量的缓存,集中在一段时间内失效,导致大量请求直接访问数据库。随着数据库请求激增,会造成数据库奔溃,应用系统无法提供服务等一系列问题。

发生现象

  • 应用系统平稳运行过程中,忽然数据库连接激增,数据库崩溃
  • 应用服务器无法及时请求,出现 500 响应,应用服务器崩溃
  • Redis CPU 占用标高,服务器/集群崩溃

解决方案

  • 采用 Redis 集群,保证高可用,降低服务器宕机的概率
  • 构建多级缓存架构:Nginx 缓存 + Redis 缓存 + EhCache 缓存
  • Hystrix 限流、降级
  • 在给缓存设置过期时间时,加上一个随机值,尽可能使每个 key 分散开
  • Redis 数据备份和恢复,快速缓存预热

缓存击穿

​ 对于一个热 key,如果此时刚好失效,大量的请求都去访问数据库。这种现象就成为缓存击穿

发生现象

  • 某一时刻,数据库压力激增

解决方案

  • 使用互斥锁,仅让第一个查询请求去访问数据库,将结果存入缓存,后续的请求直接访问缓存。

缓存穿透

​ 有些恶意请求,查询一些不存在于数据库的数据(比如通过一个不存在的 ID 查找用户),这样的数据自然也在缓存中。则导致所有请求直接访问数据库,如果这样请求数量很大,可能会压垮数据库。

发生现象

  • 数据库压力过大,服务器崩溃

解决方案

  • 设置缓存空值并设置过期时间,缺点是需要额外空间存储不存在的值
  • 布隆过滤器(BloomFilter),把所有可能查询的数据的 key 都放到 BloomFilter 中。每次查询时,都先使用 BloomFilter 判断,如果不存在则直接返回 null