本文档风哥主要介绍Redis缓存雪崩、击穿和穿透的防范实战,包括基础概念、防范策略、高可用性设计、监控与告警、实施方案、代码实现、测试与验证以及实战案例等内容,风哥教程参考Redis官方文档等内容编写,适合DBA人员和开发人员在生产环境中使用。
Part01-基础概念与理论知识
1.1 缓存雪崩
缓存雪崩是指在短时间内,大量缓存同时过期,导致所有请求都直接访问数据库,造成数据库压力骤增,甚至宕机的情况。
- 原因:大量缓存同时过期,或Redis实例宕机
- 影响:数据库压力骤增,可能导致数据库宕机
- 防范:设置随机过期时间,使用多级缓存,确保Redis高可用
1.2 缓存击穿
缓存击穿是指一个热点Key过期,导致大量请求同时访问这个Key,直接访问数据库,造成数据库压力骤增的情况。
- 原因:热点Key过期,或热点Key不存在
- 影响:数据库压力骤增,可能导致数据库宕机
- 防范:设置热点Key永不过期,使用互斥锁,预热热点数据
1.3 缓存穿透
缓存穿透是指请求一个不存在的数据,缓存和数据库都没有,导致每次请求都直接访问数据库,造成数据库压力骤增的情况。
- 原因:请求不存在的数据,或恶意攻击
- 影响:数据库压力骤增,可能导致数据库宕机
- 防范:使用布隆过滤器,缓存空值,限流
更多视频教程www.fgedu.net.cn
Part02-生产环境规划与建议
2.1 防范策略
- 缓存雪崩防范:
- 设置随机过期时间,避免大量缓存同时过期
- 使用多级缓存,如本地缓存 + Redis
- 确保Redis高可用,如使用哨兵或集群模式
- 缓存预热,提前加载热点数据
- 缓存击穿防范:
- 设置热点Key永不过期
- 使用互斥锁,防止并发请求同时访问数据库
- 预热热点数据
- 使用读写分离,分散数据库压力
- 缓存穿透防范:
- 使用布隆过滤器,过滤不存在的数据
- 缓存空值,避免重复访问数据库
- 限流,防止恶意攻击
- 参数校验,过滤非法请求
2.2 高可用性设计
## 1. Redis高可用方案
– 主从复制:提供数据备份和读写分离
– 哨兵模式:自动故障转移
– 集群模式:数据分片和高可用
## 2. 多级缓存设计
– 本地缓存:如Guava Cache、Caffeine
– 分布式缓存:如Redis
– CDN缓存:静态资源缓存
## 3. 数据库高可用
– 主从复制:提供数据备份和读写分离
– 集群模式:如MySQL Cluster、PostgreSQL Cluster
– 读写分离:分散数据库压力
## 4. 服务高可用
– 负载均衡:如Nginx、HAProxy
– 服务集群:多实例部署
– 熔断降级:如Hystrix、Sentinel
2.3 监控与告警
## 1. Redis监控
– 内存使用:info memory
– 命令执行:info commandstats
– 慢查询:slowlog get
– 集群状态:cluster info
## 2. 数据库监控
– 连接数:show global status like ‘Threads_connected’
– 查询性能:show global status like ‘Queries’
– 锁等待:show global status like ‘Innodb_row_lock_waits’
## 3. 应用监控
– QPS:每秒查询数
– 响应时间:平均响应时间
– 错误率:请求错误率
– 缓存命中率:缓存命中次数 / 总请求次数
## 4. 告警机制
– 内存使用过高:超过80%
– 命令执行延迟:超过100ms
– 数据库连接数:超过最大值的80%
– 缓存命中率:低于90%
学习交流加群风哥QQ113257174
Part03-生产环境项目实施方案
3.1 实施方案
## 1. 缓存雪崩防范
– 设置随机过期时间:在基础过期时间上增加随机值
– 实现多级缓存:本地缓存 + Redis
– 部署Redis高可用:哨兵或集群模式
– 缓存预热:系统启动时加载热点数据
## 2. 缓存击穿防范
– 热点Key永不过期:设置较长的过期时间或定期更新
– 实现互斥锁:使用Redis的setnx命令
– 预热热点数据:系统启动时加载热点数据
– 读写分离:主节点写,从节点读
## 3. 缓存穿透防范
– 实现布隆过滤器:过滤不存在的数据
– 缓存空值:对不存在的数据缓存空值,设置较短的过期时间
– 限流:对请求进行限流,防止恶意攻击
– 参数校验:过滤非法请求
## 4. 监控与告警
– 配置Prometheus监控Redis和数据库
– 配置Grafana面板,可视化监控数据
– 设置告警规则,及时发现问题
– 定期分析监控数据,优化缓存策略
3.2 代码实现
## 1. 缓存雪崩防范
// 设置随机过期时间
public void setWithRandomExpire(String key, String value, int baseExpire) {
int randomExpire = baseExpire + new Random().nextInt(300); // 增加0-300秒的随机时间
redisTemplate.opsForValue().set(key, value, randomExpire, TimeUnit.SECONDS);
}
## 2. 缓存击穿防范
// 使用互斥锁
public String getWithLock(String key) {
String value = redisTemplate.opsForValue().get(key);
if (value == null) {
String lockKey = “lock:” + key;
Boolean locked = redisTemplate.opsForValue().setIfAbsent(lockKey, “1”, 5, TimeUnit.SECONDS);
if (locked != null && locked) {
try {
// 从数据库获取数据
value = getDataFromDB(key);
if (value != null) {
redisTemplate.opsForValue().set(key, value, 3600, TimeUnit.SECONDS);
}
} finally {
redisTemplate.delete(lockKey);
}
} else {
// 等待一段时间后重试
Thread.sleep(100);
return getWithLock(key);
}
}
return value;
}
## 3. 缓存穿透防范
// 使用布隆过滤器
private BloomFilter
public String getWithBloomFilter(String key) {
if (!bloomFilter.mightContain(key)) {
return null; // 不存在的数据,直接返回
}
String value = redisTemplate.opsForValue().get(key);
if (value == null) {
value = getDataFromDB(key);
if (value != null) {
redisTemplate.opsForValue().set(key, value, 3600, TimeUnit.SECONDS);
} else {
// 缓存空值,设置较短的过期时间
redisTemplate.opsForValue().set(key, “”, 60, TimeUnit.SECONDS);
}
}
return value;
}
3.3 测试与验证
## 1. 缓存雪崩测试
– 模拟大量缓存同时过期的情况
– 观察系统响应时间和数据库压力
– 验证多级缓存和随机过期时间的效果
## 2. 缓存击穿测试
– 模拟热点Key过期的情况
– 观察系统响应时间和数据库压力
– 验证互斥锁和热点Key永不过期的效果
## 3. 缓存穿透测试
– 模拟请求不存在的数据的情况
– 观察系统响应时间和数据库压力
– 验证布隆过滤器和缓存空值的效果
## 4. 性能测试
– 使用JMeter进行性能测试
– 测试不同场景下的系统性能
– 优化缓存策略,提高系统性能
风哥提示:Redis接口限流是保护系统的重要机制,合理的限流策略可以防止系统过载,确保系统的稳定性和可用性。在实际应用中,需要根据具体业务场景和数据特点,选择合适的限流算法和策略。
Part04-生产案例与实战讲解
4.1 缓存雪崩防范
## 1. 场景描述
– 电商系统,大量商品缓存同时过期
– 系统启动时,缓存未加载
## 2. 解决方案
– 设置随机过期时间
– 实现多级缓存
– 部署Redis高可用
– 缓存预热
## 3. 实战操作
# 设置随机过期时间
$ /redis/app/bin/redis-cli -h 192.168.1.100 -p 6379 -a fgedu@2026 set product:2001:info “{\”id\”:\”2001\”,\”name\”:\”iPhone 14\”,\”price\”:\”6999\”}” EX 3600
# 实际应用中,在代码中设置随机过期时间
# 实现多级缓存(使用Caffeine)
// Java代码
Cache
.expireAfterWrite(10, TimeUnit.MINUTES)
.maximumSize(1000)
.build();
// 获取数据
public String getProductInfo(String productId) {
String key = “product:” + productId + “:info”;
// 先从本地缓存获取
String value = localCache.getIfPresent(key);
if (value == null) {
// 从Redis获取
value = redisTemplate.opsForValue().get(key);
if (value != null) {
localCache.put(key, value);
} else {
// 从数据库获取
value = getDataFromDB(productId);
if (value != null) {
// 设置随机过期时间
int expire = 3600 + new Random().nextInt(300);
redisTemplate.opsForValue().set(key, value, expire, TimeUnit.SECONDS);
localCache.put(key, value);
}
}
}
return value;
}
## 4. 测试
$ ab -n 10000 -c 100 http://localhost:8080/product/info/2001
# 输出示例
Concurrency Level: 100
Time taken for tests: 1.234 seconds
Complete requests: 10000
Failed requests: 0
Total transferred: 1234567 bytes
HTML transferred: 123456 bytes
Requests per second: 8103.57 [#/sec] (mean)
Time per request: 12.345 [ms] (mean)
Time per request: 0.123 [ms] (mean, across all concurrent requests)
Transfer rate: 987.65 [Kbytes/sec] received
Connection Times (ms):
min mean[+/-sd] median max
Connect: 0 0 0.1 0 1
Processing: 5 12 2.3 12 20
Waiting: 5 12 2.3 12 20
Total: 5 12 2.3 12 21
4.2 缓存击穿防范
## 1. 场景描述
– 热点商品,访问频率高
– 商品缓存过期
## 2. 解决方案
– 设置热点Key永不过期
– 使用互斥锁
– 预热热点数据
## 3. 实战操作
# 设置热点Key永不过期
$ /redis/app/bin/redis-cli -h 192.168.1.100 -p 6379 -a fgedu@2026 set product:hot:2001 “{\”id\”:\”2001\”,\”name\”:\”iPhone 14\”,\”price\”:\”6999\”}”
# 使用互斥锁获取热点数据
// Java代码
public String getHotProductInfo(String productId) {
String key = “product:hot:” + productId;
String value = redisTemplate.opsForValue().get(key);
if (value == null) {
String lockKey = “lock:product:hot:” + productId;
Boolean locked = redisTemplate.opsForValue().setIfAbsent(lockKey, “1”, 5, TimeUnit.SECONDS);
if (locked != null && locked) {
try {
// 从数据库获取数据
value = getDataFromDB(productId);
if (value != null) {
// 设置永不过期(或较长的过期时间)
redisTemplate.opsForValue().set(key, value);
}
} finally {
redisTemplate.delete(lockKey);
}
} else {
// 等待一段时间后重试
try {
Thread.sleep(100);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
return getHotProductInfo(productId);
}
}
return value;
}
# 预热热点数据
// 系统启动时预热热点数据
@PostConstruct
public void warmupHotProducts() {
List
for (String productId : hotProductIds) {
String value = getDataFromDB(productId);
if (value != null) {
String key = “product:hot:” + productId;
redisTemplate.opsForValue().set(key, value);
}
}
}
## 4. 测试
$ ab -n 10000 -c 100 http://localhost:8080/product/hot/2001
# 输出示例
Concurrency Level: 100
Time taken for tests: 0.876 seconds
Complete requests: 10000
Failed requests: 0
Total transferred: 1234567 bytes
HTML transferred: 123456 bytes
Requests per second: 11415.53 [#/sec] (mean)
Time per request: 8.760 [ms] (mean)
Time per request: 0.088 [ms] (mean, across all concurrent requests)
Transfer rate: 1376.45 [Kbytes/sec] received
Connection Times (ms):
min mean[+/-sd] median max
Connect: 0 0 0.1 0 1
Processing: 3 8 1.5 8 15
Waiting: 3 8 1.5 8 15
Total: 3 8 1.5 8 16
4.3 缓存穿透防范
## 1. 场景描述
– 恶意请求不存在的商品ID
– 系统遭受大量无效请求
## 2. 解决方案
– 使用布隆过滤器
– 缓存空值
– 限流
## 3. 实战操作
# 使用布隆过滤器
// 初始化布隆过滤器
private BloomFilter
// 加载商品ID到布隆过滤器
@PostConstruct
public void initBloomFilter() {
List
for (String productId : productIds) {
bloomFilter.put(productId);
}
}
// 使用布隆过滤器获取数据
public String getProductInfoWithBloomFilter(String productId) {
if (!bloomFilter.mightContain(productId)) {
return null; // 不存在的数据,直接返回
}
String key = “product:” + productId + “:info”;
String value = redisTemplate.opsForValue().get(key);
if (value == null) {
// 从数据库获取数据
value = getDataFromDB(productId);
if (value != null) {
redisTemplate.opsForValue().set(key, value, 3600, TimeUnit.SECONDS);
} else {
// 缓存空值,设置较短的过期时间
redisTemplate.opsForValue().set(key, “”, 60, TimeUnit.SECONDS);
}
}
return value;
}
# 限流
// 使用Redis实现限流
public boolean isAllowed(String key, int limit, int window) {
String limitKey = “limit:” + key;
Long current = redisTemplate.opsForValue().increment(limitKey);
if (current == 1) {
redisTemplate.expire(limitKey, window, TimeUnit.SECONDS);
}
return current <= limit;
}
// 在请求处理前进行限流
public String handleRequest(String productId) {
if (!isAllowed("product:" + productId, 100, 60)) {
return "Too many requests";
}
return getProductInfoWithBloomFilter(productId);
}
## 4. 测试
$ ab -n 10000 -c 100 http://localhost:8080/product/info/999999
# 输出示例
Concurrency Level: 100
Time taken for tests: 0.567 seconds
Complete requests: 10000
Failed requests: 0
Total transferred: 1234567 bytes
HTML transferred: 123456 bytes
Requests per second: 17636.68 [#/sec] (mean)
Time per request: 5.670 [ms] (mean)
Time per request: 0.057 [ms] (mean, across all concurrent requests)
Transfer rate: 2134.56 [Kbytes/sec] received
Connection Times (ms):
min mean[+/-sd] median max
Connect: 0 0 0.1 0 1
Processing: 2 5 1.0 5 10
Waiting: 2 5 1.0 5 10
Total: 2 5 1.0 5 11
更多学习教程公众号风哥教程itpux_com
Part05-风哥经验总结与分享
5.1 最佳实践
Redis缓存雪崩击穿穿透防范实战最佳实践:
- 综合防范:结合多种防范策略,提高系统的稳定性,学习交流加群风哥微信: itpux-com
- 热点数据处理:对热点数据进行特殊处理,如永不过期、预热等
- 多级缓存:使用本地缓存 + Redis,减轻Redis的压力
- 高可用设计:确保Redis和数据库的高可用性
- 监控与告警:建立完善的监控和告警机制,及时发现问题
- 性能测试:定期进行性能测试,优化缓存策略
- 安全防护:防止恶意攻击,如限流、参数校验等
- 持续优化:根据实际情况,持续优化缓存策略
5.2 常见问题
- 缓存雪崩:设置随机过期时间,使用多级缓存,确保Redis高可用
- 缓存击穿:设置热点Key永不过期,使用互斥锁,预热热点数据
- 缓存穿透:使用布隆过滤器,缓存空值,限流
- 性能下降:优化缓存策略,使用多级缓存,合理设置过期时间
- 内存使用过高:合理设置缓存大小,定期清理过期数据
- 监控不到位:配置完善的监控系统,及时发现问题
5.3 优化技巧
## 1. 缓存策略优化
– 根据数据特点选择合适的缓存策略
– 合理设置过期时间,避免大量缓存同时过期
– 对热点数据进行特殊处理,如永不过期、预热等
– 使用多级缓存,减轻Redis的压力
## 2. 高可用性优化
– 部署Redis高可用方案,如哨兵或集群模式
– 确保数据库的高可用性,如主从复制、集群等
– 实现服务的高可用,如负载均衡、服务集群等
## 3. 性能优化
– 优化Redis配置,提高性能
– 优化网络配置,减少网络延迟
– 优化应用代码,减少Redis的访问次数
– 合理使用Redis的高级数据结构
## 4. 安全防护
– 防止恶意攻击,如限流、参数校验等
– 使用布隆过滤器,过滤不存在的数据
– 缓存空值,避免重复访问数据库
## 5. 监控与告警
– 配置完善的监控系统,及时发现问题
– 设置合理的告警规则,及时处理问题
– 定期分析监控数据,优化缓存策略
通过本文档的学习,您应该掌握了Redis缓存雪崩、击穿和穿透的防范实战,能够在生产环境中实施有效的防范策略,提高系统的稳定性和性能。在实际应用中,需要根据具体业务场景和数据特点,选择合适的防范策略,确保系统的高效运行。
风哥提示:Redis缓存雪崩、击穿和穿透是缓存使用中的常见问题,合理的防范策略可以提高系统的稳定性和性能。在实际应用中,需要根据具体业务场景和数据特点,选择合适的防范策略。
from Redis视频:www.itpux.com
本文由风哥教程整理发布,仅用于学习测试使用,转载注明出处:http://www.fgedu.net.cn/10327.html
