news 2026/4/22 9:51:32

艾体宝干货 |【Redis实用技巧#6】用了这么多年都错了?如何正确地使用缓存

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
艾体宝干货 |【Redis实用技巧#6】用了这么多年都错了?如何正确地使用缓存

这次也来分享我们一位客户的经历,相信也能给你带来一点启发。

许多人一直以来都在用黑盒的思路看待 Redis。只是设置一个 key,然后从上面读 key,就开始抱怨为什么 p99 延迟此般夸张。曾经好几个夜晚,抱怨着包括数据库、网络在内的各种组件,不断排查瓶颈,最后才意识到根因出在 Redis:缓存策略设置得太不成熟了。

在高并发时让系统资源枯竭、抖动不止,反过来一旦缓存冷掉,数据库就被打得压力飙升。如果这些情况,看起来眼熟,不妨接着看看我们的分享。了解下我们是如何让系统从只是纸面性能好变成真正的线上稳定。

让我吃足苦头的错误

许多人所犯下的最大的错误,无外乎别的,就是**但凡是能缓存的都缓存,毫无策略地用 cache-aside。**没有限界、没不设TTL、没有 miss 保护机制,一切交给 Redis,系统在看起来干练简洁,一旦上线,在真实流量下又惨不忍睹。

  • 现象:流量高峰时 miss 暴涨

  • 根因:裸用 cache-aside,没有任何保护

  • 结果:数据库被打穿、请求超时、用户体验崩溃

# 典型的 cache-aside value = r.get("user:42")if value is None: value = db_get_user(42) r.set("user:42", value)return value
  • 问题:没命中的每个请求都会直奔数据库。

  • 解决:统一加 TTL,并对过期策略做柔性处理。

  • 效果:避免冲击、降低峰值抖动、内存更稳定。

决定什么值得被缓存

缓存不等同于数据库的副本,它是一个需要规则的加速层。

哪些数据适合放入缓存?

  • 热数据且稳定:商品元数据、feature flags、枚举表

  • 热数据,但多变:会话、购物车、推荐 feed

  • 冷数据,但成本高:汇总、报表、搜索提示

提升性能最快的方式不是缓存得越多越好,而是只缓存回报最高的那部分,同时为不同波动频率选择不同策略。


最常用的三种缓存模式

Cache-aside + 合理的 TTL(读多更新少)

适用于:读多写少、偶尔更新的数据。

# 带合理 TTL 的 cache-aside value = r.get("item:123")if value is None: value = db_get_item(123) r.set("item:123", value, ex=300) # 5 分钟return value
  • 问题:无限期缓存导致旧数据堆积、内存占用膨胀

  • 解决:TTL 与数据更新频率一致

  • 效果:命中率稳定,可接受的过期窗口

Read-through + 背景刷新(一致的读取性能)

适用于:需要稳定响应延迟、能接受极短时窗口 stale。

# read-through + 后台异步刷新def get_item(item_id): value = r.get(f"item:{item_id}")if value is None: value = db_get_item(item_id) r.set(f"item:{item_id}", value, ex=600)return value # 接近过期时触发异步刷新 ttl = r.ttl(f"item:{item_id}")if ttl is not None and ttl < 60: enqueue_refresh(item_id)return value
  • 问题:过期点上的同步 miss 形成山峰效应

  • 解决:提前刷、后台刷

  • 效果:miss 风暴消失,p99 延迟收敛


Write-through(对一致性要求极高)

用于:必须确保缓存不出现 stale 的写操作。

# write-through 写操作def update_user(user_id, payload): db_update_user(user_id, payload) r.set(f"user:{user_id}", payload, ex=900)
  • 问题:缓存与数据库出现竞态

  • 解决:写数据库后立即同步写缓存

  • 效果:数据读回始终一致


从源头阻止缓存击穿

热点 key 一旦过期,在高并发流量下所有请求都会打到数据库。使用以下三个组件避免缓存击穿:

  1. single flight(互斥填充):只有 1 个请求负责更新,其他请求暂时返回(可能)过期的缓存值。

  2. 随机 TTL(jitter):避免大量key同时过期。

  3. soft TTL(柔性过期):允许短暂带过期返回,后台更新。

# soft TTL + single flight 示例def get_hot(key): value = r.get(key)if value is not None: exp_ts = r.hget(f"meta:{key}", "exp")if exp_ts and int(exp_ts) > now():return value # 允许短时间的 stale,单飞刷新if r.setnx(f"lock:{key}", "1"): r.expire(f"lock:{key}", 30) enqueue_refresh(key)return value # 空缓存情况下的单飞填充if r.setnx(f"lock:{key}", "1"): r.expire(f"lock:{key}", 30) value = db_get(key) r.set(key, value, ex=300) r.hset(f"meta:{key}", mapping={"exp": now() + 240}) r.delete(f"lock:{key}")return value return fallback_value()

能抗流量波峰的缓存架构

+-----------+ +---------+ | Users | ----> | API | +-----------+ +---------+ | v +-------------+ | Redis | | Cache | +-------------+ | miss / refresh | v +-------------+ | DB | +-------------+
  • 核心路径:API 优先读 Redis,只有有限情况才落到 DB

  • 防护:single flight

  • 保持热度:后台任务定期刷新热键

别啥都往里扔,内存不是垃圾桶

Redis 的淘汰策略本质上决定了谁必须让位。

  • allkeys-lru:最近最少使用

  • volatile-ttl:只淘汰有 TTL 的 key(计划性缓存常用)

  • allkeys-lfu:基于访问频率,适合突发访问

# redis.conf maxmemory 4gb maxmemory-policy allkeys-lfu
  • 问题:高频 churn 的 key 把真正有价值的热点数据挤掉

  • 解决:LFU 更适合突发流量

  • 效果:命中率提升、内存抖动减少

避免代价高昂的错误

  • 不要在错误的层做缓存

  • 缓存的数据必须能被正确失效(write-through / event-driven)

  • 必须监控命中率、miss 风暴、p99、memory、evictions

# 简单的命中率监控 redis-cli INFO stats | grep keyspace_hits redis-cli INFO stats | grep keyspace_misses

CheckList

  • TTL 必须与更新频率一致

  • TTL 加 jitter

  • 填充路径使用 single flight

  • 热点 key 在发布前预热

  • 淘汰策略需与访问模式匹配

  • 每天监控 hit rate / p99 / evictions

架构示意

Users | v +------+ hit | API | ------------+ +------+ | | v v +--------+ +------+ | Redis | | Auth | | Cache | +------+ +--------+ | | | miss/refresh v | +-------------------------+ | Database | +-------------------------+ Deploy warmup | v +--------+ +--------+ +-----------+ | Jobs |->| Redis |-> | API Read | +--------+ +--------+ +-----------+ ^ | | | v v | +-------+ +-------+ | | DB | | Users | | +-------+ +-------+ | Metrics

结语

Redis 是性能优化的利器,但只有策略正确,它才能真正发挥威力。

  • 合理的 TTL 胜过永不过期

  • single flight 胜过硬扛流量

  • 策略优化胜过盲目堆缓存

如果这篇分享能帮助你更清晰地理解系统行为,欢迎继续关注后续文章。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/20 17:18:29

PingFangSC字体包:让每个网页都享受苹果级字体体验的终极解决方案

PingFangSC字体包&#xff1a;让每个网页都享受苹果级字体体验的终极解决方案 【免费下载链接】PingFangSC PingFangSC字体包文件、苹果平方字体文件&#xff0c;包含ttf和woff2格式 项目地址: https://gitcode.com/gh_mirrors/pi/PingFangSC 还在为网页在不同设备上字体…

作者头像 李华
网站建设 2026/4/15 11:52:59

艾体宝干货 |【Redis实用技巧#5】掌握 Redis 与 Kafka,搞定系统设计

多数人其实不需要记住世界上所有的数据库、消息队列或缓存策略。只需要深入理解两个工具&#xff1a;Redis 和 Kafka。掌握了它们&#xff0c;就能解决 80% 的系统设计难题。为什么是这两个&#xff1f;Redis 解决速度&#xff0c;Kafka 解决扩展。二者共同构成了现代分布式系统…

作者头像 李华
网站建设 2026/4/20 5:59:45

13、Lotus Domino 6 for Linux:MySQL 与应用配置全攻略

Lotus Domino 6 for Linux:MySQL 与应用配置全攻略 在 Linux 环境下使用 Lotus Domino 6 时,配置 MySQL 数据库以及相关应用是关键步骤。下面将详细介绍如何完成这些配置,让你能够顺利使用 Domino 应用访问 MySQL 数据库中的员工数据。 1. 配置 MySQL 配置 MySQL 主要涉及…

作者头像 李华
网站建设 2026/4/21 10:45:58

克隆jQuery项目的表格组件,迁移为Vue 3组件并优化性能

文章目录 一、核心迁移思路二、分步实现&#xff08;基础迁移&#xff09;1. 组件骨架搭建&#xff08;单文件组件格式&#xff09;2. 核心功能迁移映射&#xff08;jQuery → Vue 3&#xff09; 三、性能优化关键措施1. 渲染优化&#xff08;减少 DOM 操作&#xff09;2. 数据…

作者头像 李华
网站建设 2026/4/19 9:19:52

零基础渗透测试全攻略:从入门到精通,一篇就够!

渗透测试入门教程&#xff08;非常详细&#xff09;从零基础入门到精通&#xff0c;看完这一篇就够了 PART.1 什么是渗透测试 渗透测试&#xff08;Penetration Testing&#xff0c;简称 PenTest&#xff09;&#xff0c;也被称为道德黑客攻击或白帽黑客攻击&#xff0c;是一种…

作者头像 李华
网站建设 2026/4/18 7:07:58

44、Linux 系统用户与组管理及打印、日志操作全解析

Linux 系统用户与组管理及打印、日志操作全解析 1. 用户账户管理 在 Linux 系统中,用户账户管理是一项基础且重要的任务。以下将介绍如何进行用户账户的删除、创建以及权限相关的操作。 1.1 删除用户账户 删除用户账户可以使用 userdel 命令。例如,要删除用户 bobg 的…

作者头像 李华