Redis SET GETEX 一次读写 TTL 时如何避免竞态
缓存代码里常见一个小陷阱:先 SET,再单独执行 EXPIRE,或者先 GET 再 EXPIRE。中间只要遇到超时、覆盖或并发请求,值和 TTL 就可能不同步。更稳妥的做法是写入时使用 SET key value EX seconds,读取并续期时使用 GETEX key EX seconds;两个命令各自把相关动作放在一次 Redis 命令里完成。
SET ... EX/PX负责“写值时一起设置 TTL”,不要把EXPIRE作为事后补丁。GETEX ... EX/PX负责“返回字符串值时刷新 TTL”,不存在的键返回空值。- 单命令原子性不等于多键业务事务;还要做条件判断、跨键更新时,使用事务或 Lua 脚本。
一、先把写入过期和读取续期分开
“设置缓存并让它五分钟后过期”和“读到缓存后再延长五分钟”是两个动作。前者用 SET,后者用 GETEX。不要把它们理解成一个叫“SET GETEX”的组合语法:Redis 命令仍然是分别发送的,只是每条命令内部的值操作与 TTL 操作不会被另一个客户端插入。
| 场景 | 推荐命令 | 返回/检查重点 |
|---|---|---|
| 首次写入或覆盖缓存 | SET key value EX 300 | 返回 OK,再用 TTL 抽查 |
| 读取并滑动续期 | GETEX key EX 300 | 返回值或空值,TTL 同时更新 |
| 只读不续期 | GET key | 不会改变 TTL |

二、写入时用 SET EX,别让值先裸奔
缓存回源成功后,直接把过期参数放进 SET。EX 使用秒,PX 使用毫秒;两者选一个即可。这样不会出现 SET 已经成功、进程却在 EXPIRE 前崩溃的窗口。
# 写入字符串,并在同一条命令里设置 300 秒 TTL SET user:42:profile profile-v1 EX 300 # 只允许不存在的键被创建;条件不满足时不会覆盖旧值 SET lock:order:42 token-abc NX PX 5000
如果业务要求“只有键不存在才写入”,把 NX 和 TTL 一起放进同一条 SET。不要先 EXISTS 再 SET,那会重新暴露检查与写入之间的竞态。
三、读取时用 GETEX,滑动过期只做一次往返
GETEX 类似 GET,但它是写命令,会在返回字符串值的同时修改 TTL。下面的写法适合会话、短期授权缓存或“访问后再保留五分钟”的滑动窗口。
# 返回缓存内容,并把有效期重新设为 300 秒 GETEX user:42:profile EX 300 # 只查看内容,不延长生命周期 GET user:42:profile # 需要诊断时再检查 TTL;-1 表示无过期,-2 表示键不存在 TTL user:42:profile
GETEX 的过期选项互斥,可用 EX、PX、EXAT、PXAT 或 PERSIST。键不存在时返回空值,不会凭空创建键。若只是想取消过期,可使用 GETEX key PERSIST,但这会改变缓存生命周期,不能当作普通读取。

四、用返回值和 TTL 检查真正的问题
排查时不要只看业务日志里的“缓存命中”。把结果拆成两个维度:返回值判断键是否存在,TTL 判断是否仍有过期策略。
- 返回空值且
TTL为-2:键已不存在,通常应回源。 - 返回非空但
TTL为-1:值存在却没有过期时间,检查是否有旧代码使用了普通SET覆盖了 TTL。 TTL比预期小很多:确认客户端传的是秒还是毫秒,并检查是否有其他读取路径在刷新。
这类抽查命令只是诊断动作,不要在高并发请求路径里为每次命中额外发送 TTL,否则又增加了一次网络往返。
五、单命令安全,不代表复合业务自动安全
SET ... NX EX 和 GETEX ... EX 能保证各自命令内部的动作连续执行,但不能替代“读值、比较版本、更新另一个键”的事务。如果你要根据旧值决定是否改写多个键,使用 MULTI/EXEC 配合乐观锁,或把完整判断放进 Lua 脚本。
另外,GETEX 从 Redis 6.2 才提供;连接到更旧的服务端时应先确认版本,再考虑用客户端兼容方案。若只能拆成 GET 与 EXPIRE,至少要记录失败、重试和键被覆盖的情况,不要把两个成功率相乘后当成原子操作。
相关问题
GETEX 会把 TTL 延长到原来的剩余时间再加五分钟吗?
不会。使用 EX 300 时是把过期时间重新设为当前命令指定的 300 秒窗口,不是自动累加剩余 TTL。
SET EX 和 SETEX 有什么区别?
SET key value EX seconds 更容易与 NX、XX 等条件组合;新代码优先使用它。两者都能在写入字符串时设置秒级过期。
GETEX 能读取 Hash 字段吗?
不能。GETEX 面向字符串键;Hash 字段需要使用对应的 Hash 命令或重新设计缓存粒度。
Go tls.ClientSessionCache 命中率低时先看哪些条件
- 上一篇
- Go tls.ClientSessionCache 命中率低时先看哪些条件
- 下一篇
- 鼠尾草纸鹤手机壁纸如何用柔雾留白衬托小主体
-
- 数据库 · Redis | 22小时前 | Redis · 缓存一致性 · 失效通知 · redis CLIENT TRACKING 客户端缓存
- Client Tracking 失效通知怎么配置或排查
- 439浏览 收藏
-
- 数据库 · Redis | 23小时前 | Redis · cluster · redis Redis Cluster Hash Tag hash slot
- Cluster hash tag 同槽怎么配置或排查
- 358浏览 收藏
-
- 数据库 · Redis | 1天前 |
- WATCH 事务重试怎么配置或排查
- 230浏览 收藏
-
- 数据库 · Redis | 1天前 | Redis · Sorted Set · ZRANGE · ZRANGEBYLEX ·
- Sorted Set 字典序范围怎么配置或排查
- 461浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- PubMedQA
- 深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
- 17次使用
-
- H2O EvalGPT
- H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
- 125次使用
-
- LMArena
- LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
- 49次使用
-
- HELM
- 深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
- 17次使用
-
- OpenCompass
- OpenCompass是上海AI实验室推出的开源大模型评测平台,提供CompassKit、CompassHub和CompassRank三大核心组件,支持LLM及多模态模型的一站式标准化评估与排行榜查询。
- 70次使用
-
- 详解如何在Go语言中循环数据结构
- 2022-12-22 406浏览
-
- 详解Golang中字符串的使用
- 2023-01-01 370浏览
-
- 深度解密Go语言中字符串的使用
- 2022-12-24 160浏览
-
- Go实现快速生成固定长度的随机字符串
- 2023-02-24 432浏览
-
- Go与Redis实现分布式互斥锁和红锁
- 2022-12-22 117浏览

