Redis实现自增ID式键存储:有无无需Lua脚本的可靠方案?
Redis 生成带连续自增ID的键(原生命令实现方案)
需求场景
Redis中我们可以通过SET存储键值,用INCR实现键值自增,基础操作示例:
127.0.0.1:6379> set _inc 0 OK 127.0.0.1:6379> INCR _inc (integer) 1 127.0.0.1:6379> INCR _inc (integer) 2 127.0.0.1:6379> get _inc "2"
我们也可以自定义带唯一标识的键,比如:
item:UNIQUE-ID item:UNI-QUE-ID
但如果需要生成带连续自增ID的键(如item:1、item:2、item:3...),目前可通过Lua脚本实现,示例如下:
127.0.0.1:6379> eval 'return redis.call("set", "item:" .. redis.call("incr","itemNCounter"), "item value")' 0 OK ... 127.0.0.1:6379> keys item:* 1) "item:10" 2) "item:14" 3) "item:13" 4) "item:6" 5) "item:15" 6) "item:9" 7) "item:4" 8) "item:1" 9) "item:5" 10) "item:3" 11) "item:12" 12) "item:7" 13) "item:8" 14) "item:11" 15) "item:2"
以下是无需Lua脚本的原生命令实现方案:
方案1:分两步执行(依赖INCR原子性)
INCR命令本身是原子操作,多个客户端并发调用时,每个调用都会得到唯一的递增ID,因此可以安全地分两步执行:
- 执行自增命令获取唯一ID:
127.0.0.1:6379> INCR itemNCounter (integer) 1
- 用返回的ID构造键并存储值:
127.0.0.1:6379> SET item:1 "item value" OK
可靠性说明
- 该方案能保证ID的唯一性:因为
INCR的原子性确保每个客户端拿到的ID不会重复,即使多个客户端同时发起请求,Redis也会依次处理INCR请求,分配不重复的ID。 - 唯一可能的问题是:如果
INCR成功但SET失败(如网络中断、内存不足),该ID会被浪费,但不会出现重复分配的情况。
方案2:事务包裹(保证命令顺序执行)
如果希望将“自增计数器”和“存储键值”两个操作作为一个整体执行(保证命令按顺序执行,不会被其他客户端的请求打断),可以使用Redis事务:
127.0.0.1:6379> MULTI OK 127.0.0.1:6379> INCR itemNCounter QUEUED 127.0.0.1:6379> SET item:1 "item value" # 此处的ID需要客户端提前通过INCR或GET获取,事务内无法直接引用前一个命令的返回值 QUEUED 127.0.0.1:6379> EXEC 1) (integer) 1 2) OK
注意事项
- Redis事务不支持回滚:如果队列中的某条命令执行失败(如语法错误),其他命令仍会继续执行,因此无法实现“要么都成功、要么都失败”的强原子性保证。如果需要这种强一致性,Lua脚本仍是更合适的选择。
内容的提问来源于stack exchange,提问作者dose
相关产品推荐
相关产品推荐

