当前位置: 首页 > news >正文

Redis缓存设计与性能优化指南

Redis缓存设计与性能优化指南


一、缓存穿透

问题描述
查询不存在的数据,缓存和DB均未命中,导致每次请求直达数据库。

原因

  1. 自身业务代码或数据问题
  2. 恶意攻击/爬虫大量请求不存在的数据

解决方案

✅ 缓存空对象
String get(String key) {String cacheValue = cache.get(key);if (StringUtils.isBlank(cacheValue)) {String storageValue = storage.get(key);cache.set(key, storageValue);// 存储值为空时设置短过期时间(300秒)if (storageValue == null) {cache.expire(key, 300);}return storageValue;}return cacheValue;
}
✅ 布隆过滤器(Bloom Filter)
  • 原理:使用位数组+多个无偏哈希函数,判断元素一定不存在或可能存在
  • 特点
    • 适用于数据固定、实时性低的场景
    • 不支持删除操作(需重新初始化)
  • Redisson实现
    RBloomFilter<String> bloomFilter = redisson.getBloomFilter("sample");
    bloomFilter.tryInit(100000L, 0.03);  // 初始化元素量+误判率
    bloomFilter.add("key1");              // 添加数据
    bloomFilter.contains("key1");         // 校验存在性
    

二、缓存击穿(失效)

问题描述
大批量缓存在同一时间失效,导致请求穿透至数据库。

解决方案

// 批量设置缓存时分散过期时间
for (int i = 0; i < items.size(); i++) {int expireTime = 1800 + new Random().nextInt(300); // 1800±300秒cache.set(key, value, expireTime);
}

三、缓存雪崩

问题描述
缓存层崩溃后,流量直接冲击存储层导致级联故障。

解决方案

  1. 高可用架构:使用Redis Cluster/Sentinel
  2. 限流降级
    • 非核心数据:返回预定义空值/错误信息
    • 核心数据(如库存):允许查缓存或DB
  3. 容灾演练:提前模拟缓存宕机场景

四、热点Key重建优化

问题:热点Key失效瞬间,大量线程并发重建缓存。
方案:互斥锁控制重建

String rebuildCache(String key) {String value = cache.get(key);if (value == null) {String lockKey = "lock:" + key;if (lock.tryLock()) {      // 获取分布式锁value = db.get(key);   // 查询数据库cache.set(key, value); // 重建缓存lock.unlock();} else {Thread.sleep(100);     // 等待其他线程完成return cache.get(key); // 重试获取}}return value;
}

五、缓存与DB双写不一致

场景分析

  • 双写不一致:并发写导致数据覆盖
  • 读写不一致:读操作与写操作并发

解决方案

场景策略
低并发数据设置缓存过期时间 + 定期主动更新
允许短暂不一致缓存过期时间兜底
强一致性要求分布式读写锁(如Redisson)
异步监听通过Canal订阅Binlog更新缓存

📌 写多读多且强一致性场景,建议直接读写DB或采用缓存为主存储+DB异步备份。


六、键值设计规范

🔑 Key设计

  • 规范业务名:表名:id(例:trade:order:1
  • 简洁性:控制长度(例:u:{uid}:fr:m:{mid}
  • 禁用字符:空格、换行符、引号等

📦 Value设计

⚠️ 避免BigKey
  • 定义
    • String类型 > 10KB
    • 集合元素 > 5000个
  • 危害
    • 阻塞Redis
    • 网络拥塞
    • 删除操作引发延迟
  • 优化方案
    1. 拆分:大Hash拆分为小Key(例:user:1user:1:info, user:1:orders
    2. 选择合适结构:实体类型用Hash替代多个String
⭐ 最佳实践
  • 设置过期时间:expire key seconds
  • 过期时间打散:避免集中失效

七、命令使用规范

  1. 避免O(N)命令
    • 使用HSCAN/SSCAN替代HGETALL/SMEMBERS
  2. 禁用危险命令
    rename-command KEYS ""
    rename-command FLUSHALL ""
    
  3. 高效批量操作
    • 原生批量命令:MGET/MSET
    • Pipeline非原子操作(一次批量 ≤ 500元素)

八、客户端优化

🔗 连接池配置

参数含义建议值
maxTotal最大连接数按QPS计算(例:QPS=50000 → 50+连接)
maxIdle最大空闲连接maxTotal一致
minIdle最小空闲连接预热连接至该值
testOnBorrow借出时校验高并发设为false

预热连接池示例

List<Jedis> minIdleList = new ArrayList<>(jedisPoolConfig.getMinIdle());
for (int i = 0; i < jedisPoolConfig.getMinIdle(); i++) {Jedis jedis = pool.getResource();minIdleList.add(jedis);jedis.ping(); // 预热连接
}
for (Jedis jedis : minIdleList) {jedis.close(); // 归还连接池
}

九、内存策略优化

♻️ 内存淘汰策略(maxmemory-policy)

策略适用场景
volatile-lru过期Key中淘汰最近最少使用(推荐)
allkeys-lru所有Key中淘汰最近最少使用
volatile-lfu过期Key中淘汰访问频率最低
noeviction不淘汰,拒绝写入(默认)

4.0+版本支持LFU策略,适合热点数据场景。

⚙️ 内核参数调优

# 调整SWAP倾向(避免OOM Kill)
echo vm.swappiness=1 >> /etc/sysctl.conf# 允许内存超分配(保障fork成功)
echo vm.overcommit_memory=1 >> /etc/sysctl.conf# 增加文件句柄数
ulimit -n 65535

十、慢查询监控

# 设置慢查询阈值(单位:微秒)
config set slowlog-log-slower-than 1000  # 保存慢查询日志条数
config set slowlog-max-len 1024  # 查看慢查询日志
slowlog get 5  

📌 生产环境建议阈值设为1ms(1000微秒)


总结:缓存设计的核心在于平衡性能与一致性,避免过度设计。优先解决穿透、雪崩、击穿问题,规范Key设计,警惕BigKey,合理配置连接池和淘汰策略,结合监控实现高性能缓存方案。

http://www.lryc.cn/news/586841.html

相关文章:

  • 解码冯・诺依曼:操作系统是如何为进程 “铺路” 的?
  • [Nagios Core] CGI接口 | 状态数据管理.dat | 性能优化
  • 基于Redis Streams的实时消息处理实战经验分享
  • Appium源码深度解析:从驱动到架构
  • 使用macvlan实现容器的跨主机通信
  • 在Intel Mac的PyCharm中设置‘add bin folder to the path‘的解决方案
  • React强大且灵活hooks库——ahooks入门实践之常用场景hook
  • p4 大小写检查
  • Rust赋能文心大模型4.5智能开发
  • QCustomPlot绘图保存成PDF文件
  • 软考中级学习系列-- 阶码与尾数
  • 香港服务器Python自动化巡检脚本开发与邮件告警集成
  • 详解Linux下多进程与多线程通信(一)
  • Leetcode 3615. Longest Palindromic Path in Graph
  • OpenLoong技术观察 | 卓益得十年磨一剑:“行者”系列人形机器人技术演进观察
  • 构造函数延伸应用
  • DH(Denavit–Hartenberg)矩阵
  • redis汇总笔记
  • JAVA生成PDF(itextpdf)
  • 译码器设计
  • 论意识与人工智能:跨越鸿沟的艰难求索
  • gitlab批量删除远程分支(推荐方案二)
  • Java 大视界 -- Java 大数据在智能安防视频监控系统中的视频摘要快速生成与检索优化(345)
  • 【读书笔记】《C++ Software Design》第十章与第十一章 The Singleton Pattern The Last Guideline
  • vue3 ref vs reactive值的修改
  • 【Python练习】042. 编写一个函数,实现二叉树的前序、中序、后序遍历
  • k8s:0/1 nodes are available: pod has unbound immediate PersistentVolumeClaims.
  • 线性代数学习笔记
  • 【unitrix】 5.1 第二套类型级二进制数基本结构体(types2.rs)
  • k8s存储入门