Redis命令:PEXPIRE

Redis PEXPIRE 命令详细教程

PEXPIRE 用于为 Key 设置以毫秒为单位的过期时间(生存时间,TTL),到期后 Redis 会自动删除该 Key。它是 EXPIRE 的毫秒级版本,适合需要亚秒级精度的场景,如短时分布式锁、高频限流、精确倒计时等。

本文基于 Redis 通用 Key 操作介绍 PEXPIRE。Redis 命令本身不区分大小写,因此 PEXPIREpexpirePexpire 的效果相同;文档统一使用大写形式。PEXPIRE 自 Redis 2.6 起可用,NX/XX/GT/LT 条件选项自 Redis 7.0 起可用。

资料合集:https://pan.quark.cn/s/10e98d308913https://pan.quark.cn/s/f56bc69c5338

一、命令概览

1. 基本语法

PEXPIRE key milliseconds [NX | XX | GT | LT]

参数说明:

参数说明
key要设置过期时间的 Key
milliseconds过期时间,单位为毫秒
NX仅当 Key 没有过期时间时才设置(Not eXists),Redis 7.0+
XX仅当 Key 已有过期时间时才设置(eXists),Redis 7.0+
GT仅当新 TTL 大于当前 TTL 时才设置(Greater Than),Redis 7.0+
LT仅当新 TTL 小于当前 TTL 时才设置(Less Than),Redis 7.0+

返回值:

  • 设置成功返回 (integer) 1
  • 设置失败返回 (integer) 0(如 Key 不存在、条件不满足等)。

2. 最简单的示例

先写入一个字符串值,然后设置 5000 毫秒(5 秒)过期:

SET mykey "Hello"
PEXPIRE mykey 5000

返回:

(integer) 1

查看剩余生存时间(毫秒):

PTTL mykey

返回类似:

(integer) 4980

5 秒后 Key 被自动删除:

EXISTS mykey

返回:

(integer) 0

二、PEXPIRE 的基本用法

1. 设置毫秒级过期时间

SET lock:job:1 "owner"
PEXPIRE lock:job:1 300

返回 (integer) 1,表示该锁将在 300 毫秒后过期。

PTTL lock:job:1

返回类似:

(integer) 295

2. 对不存在的 Key 设置过期

PEXPIRE no-such-key 60000

返回:

(integer) 0

Key 不存在时,PEXPIRE 返回 0,不会创建 Key。

3. 毫秒数为 0 的情况

SET temp "value"
PEXPIRE temp 0
EXISTS temp

PEXPIRE temp 0 返回 (integer) 1,Key 立即过期,EXISTS temp 返回 (integer) 0

4. 负值毫秒数

传入负值时,Key 同样立即过期:

SET temp2 "value"
PEXPIRE temp2 -1
EXISTS temp2

返回 (integer) 0

5. 毫秒与秒的换算

PEXPIRE key 1500EXPIRE key 1.5 不等价——EXPIRE 只接受整数秒。亚秒级精度必须使用 PEXPIRE

PEXPIRE mykey 1500
PTTL mykey

返回类似 (integer) 1490,精度达到毫秒级。

如果只需要整秒精度,两种写法等价:

EXPIRE mykey 5
PEXPIRE mykey 5000

6. 覆盖已有过期时间

再次执行 PEXPIRE 会覆盖之前的过期时间(不带条件选项时):

SET mykey "value"
PEXPIRE mykey 60000
PEXPIRE mykey 30000
PTTL mykey

返回类似 (integer) 29995,新设置生效。

三、条件选项(Redis 7.0+)

1. NX — 仅当 Key 没有过期时间时设置

SET mykey "value"
PEXPIRE mykey 60000 NX
PTTL mykey

返回 (integer) 1,TTL 设置成功。

再次用 NX 设置:

PEXPIRE mykey 30000 NX

返回:

(integer) 0

Key 已有过期时间,NX 条件不满足,TTL 保持 60000 毫秒不变。

2. XX — 仅当 Key 已有过期时间时设置

SET fresh:key "value"
PEXPIRE fresh:key 30000 XX

返回:

(integer) 0

Key 没有过期时间,XX 条件不满足。

先设置过期时间再使用 XX

PEXPIRE fresh:key 60000
PEXPIRE fresh:key 30000 XX

返回 (integer) 1,TTL 被更新为 30000 毫秒。

3. GT — 仅当新 TTL 大于当前 TTL 时设置

SET mykey "value"
PEXPIRE mykey 60000
PEXPIRE mykey 30000 GT

返回 (integer) 0,30000 小于当前 60000,不更新。

PEXPIRE mykey 90000 GT

返回 (integer) 1,90000 大于 60000,TTL 更新为 90000 毫秒。

GT 常用于"只延长、不缩短"的续期场景。

4. LT — 仅当新 TTL 小于当前 TTL 时设置

PEXPIRE mykey 90000
PEXPIRE mykey 120000 LT

返回 (integer) 0,120000 大于当前 90000,不更新。

PEXPIRE mykey 30000 LT

返回 (integer) 1,TTL 缩短为 30000 毫秒。

LT 常用于"只收紧、不放宽"的安全收紧场景。

5. 特殊规则

  • 当前 TTL 为 -1(永不过期)时,GT 视为无穷大,任何新 TTL 都不满足;LT 视为满足,可以设置。
  • GT/LTNX/XX 组合使用会报语法错误,只能选择其一。

四、PEXPIRE 与 EXPIRE 的区别

两者唯一的区别是时间单位:

特性EXPIREPEXPIRE
时间单位毫秒
最小精度1 秒1 毫秒
参数类型整数秒整数毫秒
查询命令TTLPTTL
绝对时间版本EXPIREATPEXPIREAT
时间戳查询EXPIRETIMEPEXPIRETIME
可用版本1.02.6

Redis 内部以毫秒级绝对时间戳记录过期时刻,因此 PEXPIRE 是最直接匹配内部精度的设置方式,没有秒到毫秒的转换误差:

EXPIRE mykey 1
PTTL mykey

返回可能是 9991000,取决于执行时刻的毫秒对齐;而 PEXPIRE mykey 1000 精确对应 1000 毫秒。

选择建议:

  • 需要 1 秒以上粒度(会话、缓存):两者均可,EXPIRE 更直观。
  • 需要亚秒精度(锁、限流、测试):必须使用 PEXPIRE
  • 查看剩余时间时保持单位一致:用 PEXPIRE 设置就用 PTTL 查询。

五、与相关命令的区别

1. PEXPIRE 与 PEXPIREAT

PEXPIRE 设置相对时间(从现在起多少毫秒),PEXPIREAT 设置绝对时间戳(Unix 毫秒时间戳):

SET mykey "value"
PEXPIREAT mykey 1767225600000
PEXPIRETIME mykey

返回 (integer) 1767225600000PEXPIREAT 适合"在某个固定时刻过期"(如整点、活动截止时间),不受执行时间影响。

2. PEXPIRE 与 SET … PX

SET key value PX milliseconds 在写入值的同时原子地设置毫秒级过期时间,一条命令完成,不存在竞态:

SET session:1001 "data" PX 1800000

分两步则存在竞态:

SET session:1001 "data"       # 与下一条命令之间崩溃,Key 永不过期
PEXPIRE session:1001 1800000

写入新值并设置 TTL 的场景应优先使用 SET ... PXPEXPIRE 适合为已存在的 Key 补充或修改过期时间。

3. PEXPIRE 与 PERSIST

PERSIST 移除过期时间,PEXPIRE 设置过期时间,两者互逆:

SET mykey "value"
PEXPIRE mykey 60000
PERSIST mykey
PTTL mykey

PERSIST 返回 (integer) 1 后,PTTL 返回 (integer) -1(永不过期)。

4. PEXPIRE 与 PTTL / PEXPIRETIME

PTTL 查询剩余毫秒数,PEXPIRETIME 查询过期时刻的毫秒时间戳:

PEXPIRE mykey 90000
PTTL mykey
PEXPIRETIME mykey

PTTL 返回类似 (integer) 89950PEXPIRETIME 返回类似 (integer) 1767225615000。两者换算关系:PEXPIRETIME ≈ 当前时间 + PTTL

5. PEXPIRE 与 GETEX … PX

GETEX key PX milliseconds(Redis 7.0+)在读取 String 值的同时修改过期时间:

SET mykey "value"
GETEX mykey PX 60000

返回 "value",同时 TTL 被设置为 60000 毫秒。PEXPIRE 不读取值,且适用于所有数据类型。

六、过期时间刷新与更新规则

1. 各命令对 TTL 的影响

命令对 TTL 的影响
PEXPIRE key ms设置/覆盖为新的 TTL
EXPIRE key s设置/覆盖为新的 TTL(秒)
SET key value清除 TTL,Key 永不过期
SET key value KEEPTTL保留 TTL(Redis 6.0+)
SET key value PX ms设置新 TTL
PERSIST key移除 TTL
RENAME key newkeyTTL 跟随 Key 迁移
GETSET key value清除 TTL
HSETLPUSH 等集合类写命令保留 TTL

2. 覆盖式更新

不带条件选项的 PEXPIRE 总是覆盖当前 TTL,无论是延长还是缩短:

SET mykey "value"
PEXPIRE mykey 60000
PEXPIRE mykey 1000
PTTL mykey

返回小于等于 1000,TTL 被缩短为 1 秒。

3. 集合写命令不刷新 TTL

对 Hash、List 等类型的修改不会重置过期时间:

HSET user:1001 name "Alice"
PEXPIRE user:1001 60000
HSET user:1001 age 30
PTTL user:1001

TTL 继续倒计时,HSET 不影响过期时间。

七、过期机制原理

1. 惰性过期

访问 Key 时检查是否过期,过期则删除并当作不存在处理。这意味着过期 Key 在被访问或被后台清理之前,可能仍短暂占用内存。

2. 定期过期

Redis 后台周期性随机抽样检查带 TTL 的 Key,删除其中已过期的,避免大量过期 Key 堆积。抽样频率由 hz 配置控制。

3. 内存淘汰

过期删除与内存淘汰是两个机制。内存达到 maxmemory 时,按 maxmemory-policy 淘汰 Key;volatile-* 策略只淘汰带 TTL 的 Key。

4. 主从复制与持久化

  • PEXPIRE 在主节点执行后传播到从节点,从节点不能自主决定过期时刻,过期删除以主节点为准。
  • AOF 以毫秒时间戳记录过期事件;RDB 快照保存绝对过期时间,加载时已过期的 Key 会被丢弃。
  • 源端与目标端系统时间差异会影响 MIGRATE 迁移后过期 Key 的实际行为,生产环境应保证 NTP 时间同步。

八、不同数据类型

PEXPIRE 是 Key 级别的通用操作,适用于所有数据类型:

SET str:key "hello"
PEXPIRE str:key 5000

HSET hash:key name "Alice" age 30
PEXPIRE hash:key 5000

RPUSH list:key a b c
PEXPIRE list:key 5000

SADD set:key m1 m2
PEXPIRE set:key 5000

ZADD zset:key 100 "player1"
PEXPIRE zset:key 5000

XADD stream:key * type "login"
PEXPIRE stream:key 5000

每个 PEXPIRE 都返回 (integer) 1。过期时间属于整个 Key,Redis 不支持对 Hash 的字段、List 的元素等子结构单独设置过期时间。

九、事务与并发

1. 在事务中使用

MULTI
PEXPIRE session:1001 1800000
PEXPIRE cache:item 60000
EXEC

EXEC 返回两条命令各自的结果。注意 Redis 事务不回滚,若第一条成功第二条失败(如 Key 不存在返回 0),第一条的设置仍然生效。

2. 设置与读取的竞态

"先检查再设置"不是原子的:

PTTL mykey        # 返回 3000
PEXPIRE mykey 60000  # 两条命令之间 Key 可能已被其他客户端删除或设置

对结果敏感的场景应检查 PEXPIRE 返回值,或使用 Lua 脚本:

EVAL "if redis.call('EXISTS', KEYS[1]) == 1 then return redis.call('PEXPIRE', KEYS[1], ARGV[1]) else return 0 end" 1 mykey 60000

3. 分布式锁续期

持锁任务执行时间不确定时,常见模式是后台线程周期性续期:

PEXPIRE lock:job:1 30000 XX

使用 XX 确保仅在锁仍持有时刷新,且周期必须远小于 TTL(如 TTL 30 秒、每 10 秒续期一次),避免续期间隙锁过期。更完善的方案是只允许锁持有者续期,可在 Lua 脚本中校验锁的值。

4. 写入与设置 TTL 的原子性

新建 Key 时分开执行 SETPEXPIRE 存在窗口,应使用原子命令:

# 推荐:一条命令完成
SET lock:job:1 "owner" NX PX 30000

# 不推荐:两步之间存在竞态
SET lock:job:1 "owner"
PEXPIRE lock:job:1 30000

5. Pipeline 批量设置

对大量 Key 设置相同的毫秒级 TTL 时可用 Pipeline 减少网络往返,每个命令有独立返回值:

PEXPIRE key:1 60000
PEXPIRE key:2 60000
PEXPIRE key:3 60000

注意批量设置可能导致 Key 在同一毫秒集中过期,引发"缓存雪崩",建议对 TTL 添加随机抖动。

十、在常见客户端中的使用方式

1. redis-cli

redis-cli PEXPIRE mykey 5000
redis-cli PTTL mykey
redis-cli PEXPIRE lock:job:1 30000 XX

2. Python(redis-py)

import redis

client = redis.Redis(host="localhost", port=6379, decode_responses=True)

client.set("mykey", "Hello")
result = client.pexpire("mykey", 5000)
print(result)  # True

print(client.pttl("mykey"))  # 例如 4985

# Redis 7.0+ 条件选项通过参数传递
result = client.pexpire("mykey", 30000, xx=True)
print(result)  # True 或 False

3. Node.js(node-redis)

import { createClient } from "redis";

const client = createClient();
await client.connect();

await client.set("mykey", "Hello");
const result = await client.pExpire("mykey", 5000);
console.log(result); // true

console.log(await client.pTTL("mykey")); // 例如 4985

await client.quit();

4. Java(Jedis)

import redis.clients.jedis.Jedis;
import redis.clients.jedis.params.SetParams;

try (Jedis jedis = new Jedis("localhost", 6379)) {
    jedis.set("mykey", "Hello");

    long result = jedis.pexpire("mykey", 5000);
    System.out.println(result); // 1

    System.out.println(jedis.pttl("mykey")); // 例如 4985

    // 新建锁时推荐原子命令
    String lockResult = jedis.set(
        "lock:job:1", "owner",
        SetParams.setParams().nx().px(30000)
    );
    System.out.println(lockResult); // OK
}

十一、典型业务场景

1. 短时分布式锁

任务执行仅需数百毫秒时,用 PEXPIRE 设置细粒度锁超时,减少锁被抢占后其他客户端的等待:

SET lock:short-task "owner" NX PX 500

2. 精确限流

滑动窗口限流器中,计数 Key 需要精确的窗口毫秒数:

INCR ratelimit:user:1001:1000
PEXPIRE ratelimit:user:1001:1000 60000 NX

首次创建计数时设置 60 秒窗口,NX 保证窗口不被后续请求重置。

3. 高频缓存

TTL 在 1 秒以内的热点缓存(如排行榜快照、股票行情):

SET quote:AAPL "189.50" PX 800

4. 验证码与一次性令牌

短信验证码通常 5 分钟有效,毫秒级命令便于统一用毫秒管理:

SET sms:code:13800001111 "582714" PX 300000

5. 毫秒级倒计时

秒杀活动的精确开始倒计时、考试倒计时等:

SET exam:countdown "started" PX 7200000

6. 幂等性控制

防止重复请求的幂等 Key 设置短毫秒 TTL:

SET idempotency:req-abc "processed" NX PX 10000

十二、性能与使用建议

  1. 时间复杂度:O(1),PEXPIRE@keyspace@write@fast 类别的快速命令。
  2. 新建 Key 并设置 TTL 优先使用 SET key value PX ms(需要互斥时加 NX),避免两步竞态。
  3. 已存在 Key 修改 TTL 用 PEXPIRE;只延长不缩短用 PEXPIRE key ms GT,只缩短不延长用 LT
  4. 续期场景使用 XX 选项可避免误为已删除的 Key 重新设置 TTL。
  5. 毫秒级 TTL 意味着 Key 过期更快,大量短 TTL Key 会提高过期删除频率;过期 Key 依赖惰性 + 定期两种机制清理,高峰期可能出现短暂内存滞后。
  6. 批量设置相同 TTL 会造成同时过期(缓存雪崩),建议加入随机抖动:
PEXPIRE key:1 61340
PEXPIRE key:2 58720
PEXPIRE key:3 62980
  1. PEXPIRE 是写命令,会写入 AOF 并复制到从节点,频繁续期(如每秒一次的锁续期)会增加复制流量。
  2. 查询剩余时间用 PTTL 保持单位一致;TTL 返回的秒数对短 TTL Key 可能直接是 01,失去毫秒信息。
  3. ACL 中 PEXPIRE 属于 @keyspace@write 类别,授权时与 EXPIREPERSIST 等一并考虑。

十三、常见问题排查

问题 1:PEXPIRE 返回 0

按以下顺序检查:

  1. Key 是否存在:
EXISTS mykey
  1. 条件选项是否满足(NX 需 Key 无 TTL,XX 需有 TTL,GT/LT 需比较通过):
PTTL mykey
PTTL 返回值含义NX 结果XX 结果
正数带 TTL0可能 1
-1无 TTL可能 10
-2Key 不存在00
  1. Redis 版本是否支持条件选项(7.0+),低版本会报语法错误。

问题 2:设置的毫秒数与 PTTL 不一致

PTTL 返回的是查询那一刻的剩余时间,命令执行、网络往返都会消耗几毫秒到几十毫秒,返回值略小于设置值属正常现象。偏差过大时检查:

  • 是否有其他客户端覆盖了 TTL。
  • 是否执行了 SET(会清除 TTL 后又重新设置)。

问题 3:PTTL 返回 0 但 Key 仍存在

TTL 剩余不足 1 秒时,TTL 返回 0PTTL 仍返回精确毫秒数。这是 TTL 秒级取整的表现,不是异常:

TTL mykey    # (integer) 0
PTTL mykey   # (integer) 420

问题 4:锁的续期失效

排查要点:

  1. 续期间隔是否小于 TTL(建议 TTL 的 1/3)。
  2. 是否有客户端执行了 SET 覆盖锁并清除了 TTL。
  3. 是否使用了 XX 选项但锁已被删除(返回 0 是正常保护)。
  4. 网络延迟是否导致续期请求晚于过期时刻。

问题 5:条件选项报语法错误

NXXXGTLT 需要 Redis 7.0+,且四者互斥不能组合。检查版本:

INFO server

低版本可用 Lua 脚本实现类似的条件判断。

问题 6:集群模式下使用

PEXPIRE 按 Key 所在槽路由,正常可用。多 Key 的 Lua 脚本要求所有 Key 在同一槽,跨槽操作会报 CROSSSLOT 错误,需使用 hash tag 保证同槽。

十四、完整练习

下面的示例覆盖基本设置、条件选项、覆盖更新和数据类型验证:

FLUSHDB

# 1. 基本设置与查询
SET demo:temp "data"
PEXPIRE demo:temp 5000
PTTL demo:temp
TTL demo:temp

# 2. 不存在的 Key
PEXPIRE demo:not-exist 60000

# 3. 零值与负值
SET demo:zero "value"
PEXPIRE demo:zero 0
EXISTS demo:zero

SET demo:neg "value"
PEXPIRE demo:neg -100
EXISTS demo:neg

# 4. 覆盖更新
SET demo:cover "value"
PEXPIRE demo:cover 60000
PEXPIRE demo:cover 30000
PTTL demo:cover

# 5. NX 条件
SET demo:nx "value"
PEXPIRE demo:nx 60000 NX
PEXPIRE demo:nx 30000 NX
PTTL demo:nx

# 6. XX 条件
SET demo:xx "value"
PEXPIRE demo:xx 30000 XX
PEXPIRE demo:xx 60000
PEXPIRE demo:xx 30000 XX
PTTL demo:xx

# 7. GT 与 LT 条件
SET demo:cond "value"
PEXPIRE demo:cond 60000
PEXPIRE demo:cond 30000 GT
PEXPIRE demo:cond 90000 GT
PEXPIRE demo:cond 30000 LT
PTTL demo:cond

# 8. 与 PERSIST 的互逆操作
PEXPIRE demo:temp 60000
PERSIST demo:temp
PTTL demo:temp

# 9. 不同数据类型
HSET demo:hash name "Alice" age 30
PEXPIRE demo:hash 60000
PTTL demo:hash
TYPE demo:hash

RPUSH demo:list a b c
PEXPIRE demo:list 60000
PTTL demo:list

# 10. 毫秒精度验证
SET demo:precise "value"
PEXPIRE demo:precise 1500
PTTL demo:precise
TTL demo:precise

预期结果:

  • demo:tempPTTL 返回略小于 5000 的值,TTL 返回 45
  • demo:not-exist:返回 (integer) 0
  • demo:zerodemo:neg:立即过期,EXISTS 返回 (integer) 0
  • demo:coverPTTL 略小于 30000
  • demo:nx:第一次 NX 返回 1,第二次返回 0,TTL 保持约 60000
  • demo:xx:第一次 XX 返回 0(无 TTL),设置后 XX 返回 1,TTL 更新为约 30000
  • demo:condGT 30000 返回 0GT 90000 返回 1LT 30000 返回 1,最终 PTTL 略小于 30000
  • demo:tempPERSISTPTTL 返回 (integer) -1
  • demo:hashdemo:listPEXPIRE 返回 1,类型不变。
  • demo:precisePTTL 返回 1400 左右,TTL 返回 01

十五、命令速查表

需求命令
设置过期时间(毫秒)PEXPIRE key milliseconds
设置过期时间(秒)EXPIRE key seconds
按毫秒时间戳设置过期PEXPIREAT key timestamp
按秒时间戳设置过期EXPIREAT key timestamp
写入并设置毫秒 TTLSET key value PX milliseconds
写入并设置秒 TTLSET key value EX seconds
写入但保留 TTLSET key value KEEPTTL
移除过期时间PERSIST key
查询剩余时间(毫秒)PTTL key
查询剩余时间(秒)TTL key
查询过期时刻(毫秒时间戳)PEXPIRETIME key
查询过期时刻(秒时间戳)EXPIRETIME key
读取值并修改 TTLGETEX key [PX ms] [EX s] [PERSIST] ...

总结

PEXPIRE 的核心作用是为 Key 设置毫秒级过期时间:

PEXPIRE key milliseconds [NX | XX | GT | LT]

使用时重点注意六点:

  • PEXPIREEXPIRE 的唯一区别是时间单位,需要亚秒精度时必须使用 PEXPIRE,并用 PTTL 查询。
  • 新建 Key 并设置 TTL 优先使用 SET key value PX ms 原子命令,避免两步竞态。
  • 条件选项 NX/XX/GT/LT(Redis 7.0+)可实现"仅延长"“仅缩短”"仅有 TTL 时设置"等语义,四者互斥。
  • 覆盖式更新总是生效;已过期的 Key 无法恢复,PEXPIRE 对不存在的 Key 返回 0 且不创建 Key。
  • 续期场景(分布式锁)建议周期为 TTL 的 1/3 并配合 XX 选项。
  • 批量设置相同 TTL 会引发缓存雪崩,应添加随机抖动。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值