Redis咋用唯一数字搞定不重复ID,生成那些号码其实没那么难
- 问答
- 2026-01-25 11:16:10
- 84
直接用Redis搞唯一不重复的数字ID,其实就像医院挂号处发号码牌,只不过这个发号器是数字的、速度极快而且绝不会发重,最直接的办法就是用Redis那个叫INCR的命令,这个命令是Redis官方文档里明确说能原子性递增的(来源:Redis命令参考文档),你想象一下,你让Redis准备一个键,比如叫“order_id”,一开始这个键不存在,你第一次对“order_id”执行INCR命令,Redis会把它设置成1,然后返回1给你,下次你再执行,它就变成2,返回2,这个操作是原子性的,意思是就算有十万个请求同时来要号码,Redis也会排好队一个一个递增,绝对不会出现两个请求拿到同一个号码的情况,这是最基础、最省事的办法,你的业务系统每次需要新ID,就调一下INCR,拿到的数字保证唯一且递增。

但只用INCR,万一Redis重启了,这个数字会不会丢呢?这取决于你的Redis怎么配置,如果你用了Redis的持久化功能(比如RDB或AOF),这个数字状态是可以恢复的,不会丢,但有人会觉得,纯数字太简单了,想在里面融入日期信息,20240521000001”这种格式,一看就知道是2024年5月21日的第一单,这也不难,你可以用日期当键的一部分,键名设计成“order_id:20240521”,这样,每天都会有一个新的键,从1开始递增,生成的时候,先拼好键名,然后对这个键执行INCR,如果返回1,你再自己把它格式化成“20240521000001”,这样做的好处是ID里带了日期,一目了然,而且每天的序号是重新开始的,数字不会无限变大。

那如果业务量超大,一个Redis实例万一成了瓶颈怎么办?Redis官方文档提到了分片(Sharding)的概念(来源:Redis集群教程),我们可以借鉴这个思路来避免单点压力,一个常见的做法是“分段发号”,你有三台业务服务器,你可以提前给每台服务器分配一个唯一的“机器号”,比如01、02、03,生成ID时,把“机器号”作为ID的前缀或后缀,更高级一点,你可以让每台机器去Redis里领一个“号码段”,比如说,机器A向Redis申请一个段,Redis就把当前ID值从1增加到1000,把这1000个号码(1-1000)都给机器A,机器A在内存里慢慢用,用完了再来申请,机器B来申请,Redis就把ID从1001增到2000,分配下去,这样,大部分时间生成ID都不需要访问Redis,性能极高,而且由Redis中央管理分配段,也不会重复,这个做法在很多互联网公司的实际应用里都能看到影子(来源:互联网公司分布式ID生成方案实践)。
还有一种结合时间戳和序列号的方法,也很流行,ID由“时间戳(秒级或毫秒级)” + “Redis提供的序列号”组成,时间戳部分,你可以用当前时间减去一个固定起始时间,得到一个很大的数字,序列号部分,还是用INCR来生成,但这里有个技巧:你可以用时间戳本身当键,键是“incr:1653123456”(这个1653123456就是当前秒级时间戳),你对这个键执行INCR,它在这一秒内会从1开始递增,如果下一秒来了,键变了,序列号又从1开始,这样组合起来的ID,既是唯一的,又基本是时间顺序递增的,这里要注意,在同一秒内如果请求量极大,序列号部分可能会不够用,所以要根据业务量选择毫秒时间戳或者把序列号部分预留足够长度。
不管用哪种方法,有几点是通用的:第一,键的设计要清晰,方便管理,第二,要考虑Redis的持久化设置,根据你对ID连续性的要求来决定,第三,在分布式环境下,如果用了Redis集群,像INCR这样的操作要确保同一个键总是落在同一个集群节点上,才能保证原子性,这个通常由Redis的哈希槽机制保证,你只要设计好键就行。
用Redis搞唯一数字ID,核心就是利用它单线程执行命令和原子性操作的特性,把并发请求变成排队领取,通过灵活设计键的名称,你可以做出纯数字的、带日期的、分段预支的、结合时间戳的各种ID,简单可靠,完全能满足大多数场景的需要。

本文由酒紫萱于2026-01-25发表在笙亿网络策划,如有疑问,请联系我们。
本文链接:https://jqcp.haoid.cn/wenda/85690.html
