前言
Redis 缓存在高并发的情况下,能够大大地减轻数据库压力。但在一些情况下,大量的请求在 Redis 都未能够命中,转而访问数据库,则可能引发数据库、应用服务器宕机等问题。
缓存预热
缓存预热是指,在应用服务上线之前,将相关的热数据加载到缓存系统中。以避免服务上线,大量请求涌入,导致数据库、应用服务器以及缓存服务器宕机。
发生现象
Redis 服务刚启动,主从间数据吞吐量较大,数据同步操作频度较高,数据库或应用服务迅速崩掉。
解决方案
- 使用 Nginx + Lua 将访问情况上报到 Kafka。
- 使用 Storm 等实时流计算引擎从 Kafka 中消费数据,实时统计出热点数据,利用 LRU 保存策略构建数据留存队列
- 根据数据级别,Redis 优先加载热度较高的数据。
缓存雪崩
大量的缓存,集中在一段时间内失效,导致大量请求直接访问数据库。随着数据库请求激增,会造成数据库奔溃,应用系统无法提供服务等一系列问题。
发生现象
- 应用系统平稳运行过程中,忽然数据库连接激增,数据库崩溃
- 应用服务器无法及时请求,出现 500 响应,应用服务器崩溃
- Redis CPU 占用标高,服务器/集群崩溃
解决方案
- 采用 Redis 集群,保证高可用,降低服务器宕机的概率
- 构建多级缓存架构:Nginx 缓存 + Redis 缓存 + EhCache 缓存
- Hystrix 限流、降级
- 在给缓存设置过期时间时,加上一个随机值,尽可能使每个 key 分散开
- 对 Redis 数据备份和恢复,快速缓存预热
缓存击穿
对于一个热 key,如果此时刚好失效,大量的请求都去访问数据库。这种现象就成为缓存击穿。
发生现象
- 某一时刻,数据库压力激增
解决方案
- 使用互斥锁,仅让第一个查询请求去访问数据库,将结果存入缓存,后续的请求直接访问缓存。
缓存穿透
有些恶意请求,查询一些不存在于数据库的数据(比如通过一个不存在的 ID 查找用户),这样的数据自然也在缓存中。则导致所有请求直接访问数据库,如果这样请求数量很大,可能会压垮数据库。
发生现象
- 数据库压力过大,服务器崩溃
解决方案
- 设置缓存空值并设置过期时间,缺点是需要额外空间存储不存在的值
- 布隆过滤器(BloomFilter),把所有可能查询的数据的 key 都放到 BloomFilter 中。每次查询时,都先使用 BloomFilter 判断,如果不存在则直接返回 null。