订单号要求
- 全局唯一
- 长度固定
- 趋势递增
- 高并发
- 高效率(整型、不能太长)
策略一:UUID
- 缺点:无序、效率低、字符串、过长(占用空间)、可读性差
策略二:数据库自增
- 自增参数设置
show varivables like 'auto_inc'; -- 起始 set @@auto_increment_offset=2 -- 步长 set @@auto_increment_increment=5
- 可通过设置不同数据库自增参数来并发获取订单号
- 缺点
- 不利于数据库服务器伸缩(步长限制)
- 不利于数据迁移
策略三:雪花算法
-
SnowFlake:最原始的版本来源于Twitter,是用Scala实现的。地址为 https://github.com/twitter-archive/snowflake。
-
SnowFlake:是一个64bit的整数分别由四部分组成: 1(最高位固定为0表示整数)+41(时间戳以毫秒为单位)+10(机器编号用来区分不同服务器)+12(序列号,同一毫秒同一机器可支持4095个序列号)。
-
根据源码可知最后的结果是由时间戳,机器码,工作码,序列数位或运算(|)得到的结果。
- 时间戳:时间戳等于当前时间戳减去开始计算时间然后左位移偏移量。偏移量等于12+5+5。
- 机器码:-1L^(-1L <<5L),首先-1左移5位得到的结果再和-1异或计算,得到的结果是31,也就是5位能表达出的最大正整数。然后随机机器码再向左偏移12+5得到机器码。
- 工作码:工作码和机器码类似,只是最后向左偏移量是5。
- 序列码:序列是从0开始的自增序列,他是12位的最大整数 4095,从源码可以看出如果是同一毫秒,序列号要自增,如果是新的毫秒序列号要从0开始重新计算。sequence=(sequence+1)&sequenceMask可以保证不管sequence传入多少都能保证最后的结果小于4095,这样可以达到防溢出的效果。
-
缺点:依赖服务器时间,id递增规律,可能因此泄漏商业机密(根据订单ID猜出订单量);长度长且固定,不容易加入自定义变量
策略四:基于redis自增
- 思路:利用增长计数API,结合其他信息组成唯一ID
- Redis的 incr(key) API
- 缺点:
- 引入第三方依赖
- 增加网络开销
- 服务器成本、维护开销(redis高可用、集群)
总结
- 没有银弹,根据场景和需求选择合适的,满足KISS原则即可