用Redis怎么快速又稳地拿订单号,顺带聊聊实现细节和注意点
- 问答
- 2026-01-10 15:06:07
- 5
用Redis拿订单号,核心就是要利用Redis单线程原子性和高性能的特点,确保每个订单号都是唯一的,并且生成速度要快,下面聊聊几种常见的做法和里面的门道。
最直接的方法:用INCR命令
这是最简单、最常用的一种方式,原理就是利用Redis的INCR命令,这个命令会把一个键的值增加1,并且这个操作是原子的,也就是说即使有成千上万个请求同时来执行这个命令,Redis也会让它们排好队,一个一个执行,绝对不会出现两个请求拿到同一个号码的情况。
-
实现细节:

- 你需要在Redis里设置一个键,比如叫
order_id_seed,可以给它设置一个初始值,比如当天的日期20240520000000,表示从今天开始的第一单。 - 每次要生成新订单号时,应用程序就向Redis发送一个
INCR order_id_seed命令。 - Redis会返回一个比上一次大1的数字,这个数字就是你的订单号。
- 你需要在Redis里设置一个键,比如叫
-
订单号组成:通常订单号不会只是一个纯数字,会包含日期、业务前缀等,你可以这样做:
订单号 = 业务前缀(如"ORD") + 年月日(如"20240520") + Redis INCR生成的6位或更多位自增序列。ORD20240520000001、ORD20240520000002。- 这里有个关键点:如何实现按天重置? 你不能让这个序列号无限增长下去,通常需要每天清零,聪明的做法是,把Redis的键名也带上日期,
order_id_seed:20240520,这样,第二天键名就变成了order_id_seed:20240521,INCR命令自然会从1重新开始,这种方式非常优雅,不需要额外的清理操作。
-
注意点:
- Redis持久化:这是最重要的!如果你只是把数据存在Redis内存里,一旦Redis服务器重启或者崩溃,内存里的
order_id_seed值就丢了,重启后可能会生成重复的订单号,所以必须开启Redis的持久化机制(RDB快照或AOF日志),这样即使重启,也能从磁盘上恢复最新的序列值,为了更保险,甚至可以同时使用RDB和AOF。 - 键名管理:使用带日期的键名,久而久之会产生很多键(
order_id_seed:20240520,order_id_seed:20240521...),这些键在过期后需要清理,可以给这些键设置一个过期时间,比如7天或30天后自动删除,避免占用太多内存。
- Redis持久化:这是最重要的!如果你只是把数据存在Redis内存里,一旦Redis服务器重启或者崩溃,内存里的
应对更高并发:用INCRBY命令

如果业务量非常大,觉得每次INCR增加1,网络通信次数太多成为瓶颈,可以考虑使用INCRBY命令。
-
实现细节:
- 应用程序不是每次来要一个号,而是一次性向Redis申请一个号段,比如1000个,命令是
INCRBY order_id_seed 1000。 - Redis返回一个值,比如是1000,这意味着当前应用程序本地持有了1到1000这1000个订单号的使用权。
- 应用程序在本地内存中维护这个号段,从1开始分配,直到1000分配完毕,再去Redis申请下一个1000个号段。
- 应用程序不是每次来要一个号,而是一次性向Redis申请一个号段,比如1000个,命令是
-
优势:

- 极大地减少了与Redis的交互次数,性能更高。
- 即使Redis临时不可用,应用程序在本地号段用完之前还能继续工作一段时间,增强了系统的稳定性。
-
注意点:
- 号段丢失问题:如果应用程序在本地分配了500个号之后突然崩溃重启,那么本地内存中还没分配的501-1000这个号段就浪费了,造成了“订单号空洞”,对于很多业务来说,订单号可以不连续,但绝对不能重复,所以这点空洞是可以接受的,属于用空间换时间和稳定性。
- 号段大小设置:需要根据业务量合理设置号段大小,设得太小,频繁请求Redis,压力大;设得太大,万一应用重启,浪费的号段就多。
聊点其他的实现和注意点
-
为什么不直接用UUID或雪花算法?
- UUID虽然能保证唯一,但太长、无序,作为数据库主键插入时会影响性能(因为B+树需要频繁调整)。
- 雪花算法(Snowflake)能生成趋势递增的ID,性能极高,不依赖数据库,但它通常要求解决机器ID的分配问题(防止不同机器生成重复ID),并且有时钟回拨的风险,对于简单的订单号场景,Redis方案更简单直接,依赖的中间件少。
-
Redis集群模式下的考虑: 如果你的Redis是集群模式,上面提到的
INCR键可能会被哈希到某个特定的节点上,这意味着所有订单号生成的请求都会打到同一个Redis节点上,虽然Redis单节点性能很强,但这可能成为整个集群的瓶颈,这时可以考虑:- 容忍方案:评估单个Redis节点的性能是否足以支撑业务峰值,如果可以,就接受这个热点key。
- 分散方案:不用一个key,而是用多个key,可以根据用户ID的最后一位或者商户ID哈希到不同的key上,如
order_id_seed:0,order_id_seed:1... 这样就把压力分散到集群的不同节点上了,但这样做的代价是订单号不再是全局严格递增的,只是趋势递增,并且管理起来稍复杂。
总结一下
对于大多数场景,使用带日期的键名进行INCR操作,并确保Redis开启了持久化,就是一个快速又稳的方案,如果并发量极高,可以考虑用INCRBY进行批量化获取来提升性能和可用性,选择哪种方案,最终要根据你的实际业务量、技术架构和对订单号连续性的要求来权衡,核心就是抓住“原子性”和“持久化”这两个牛鼻子。
本文由召安青于2026-01-10发表在笙亿网络策划,如有疑问,请联系我们。
本文链接:https://www.haoid.cn/wenda/78131.html
