我爱编程架构

分布式订单号生成策略

2018-03-29  本文已影响77人  Meathill大魔王

分布式订单号生成策略

1.关于订单号

订单号用于记录用户在电商网站中的下单信息(通常有商品列表、金额、时间等),用户下单后可根据订单号查询支付状态、物流状态等,也可以根据订单号进行投诉、反馈、售后咨询等。

订单号的生成通常要满足的需求:

1)唯一性:订单号不可重复,以免发生业务冲突

2)简短:便于记录、存储

3)业务相关性:可根据订单号定位相关业务

4)时间相关性:可根据订单号定位发生时间范围

5)有序性:订单号应当有序,便于建立索引,提高查询速度

6)安全性:订单号不应透露用户量、交易量等信息,也不要让别人随便就能拼出来。

马克思告诉我们,具体问题具体分析,生成订单号也应该以具体业务需求为准。先来看一下淘宝的3个订单号:

123736088576847054

121102577636847054

119636777937847054

对比这3个订单号你能发现什么规律吗?除了后6位相同似乎没有别的规律。相同的后6位可能是截取自用户id或以用户id作为因子。这样做有什么好处呢?如果业务量大、并发较高可在订单号生成中加入用户id作为因子,由于单个用户在某一时间段内的请求是有限的(一般系统也可能会对用户操作的频率、下单次数进行限制,限制用户在某一时间段最多可以操作多少次或限制用户某一时间段内最多可以下多少单),所以这样做可以一定程度降低生成的订单号的重复率。

当然,可以借鉴和自己公司业务比较接近的公司的产品的订单号格式,如打车业务可以借鉴滴滴出行, 支付业务可以接近支付宝或微信支付等。

2.订单号生成策略比较

1)UUID: UUID是通用唯一识别码(Universally Unique Identifier)的缩写,由时间戳、机器标识码、随机数组成。优点是简单粗暴(可使用JDK自带的UUID实现- java.util.UUID),缺点是无序,不适合建立索引。

2)DB sequence:可以使用数据库提供的自增序列(如oracle和PostgreSQL的sequence,Redis的incr)作为订单号,缺点是位数不确定,有溢出风险,高并发情况下有性能瓶颈。

3)Snowflake: 也叫雪花算法,是由Twitter开源的分布式id生成算法,生成id时的因子是:时间戳+递增序列+机器号+业务号,默认生成的id是18位的long型数字。我测了一下4核CPU每秒可生成100w+个id,可以说性能还是不错的。查看其源码会发现,该算法只有简单的逻辑判断与位运算,没有字符串拼接也没有时间格式化。这应该是该算法相较于普通算法性能较高的主要原因。下面截图是snowflake算法生成id的关键代码:

twitter-scala版本: https://github.com/twitter/snowflake

java版本:https://github.com/downgoon/snowflake

想要在自己的项目中引入Snowflake很简单,可以引入其maven依赖,也可以直接复制其源代码(主要就一个Snowflake.java)到项目中。

使用Snowflake生成订单号(id)非常简单,需要注意的是其中两个参数的含义:

// dataCenterId可用于区分机器,workerId可用于区分业务

// datacenter: 2; workerId: 5

Snowflake snowflake = new Snowflake(2, 5);

long id1 = snowflake.nextId();

long id2 = snowflake.nextId();

如果需要解析生成的id,可以使用如下方式:

上图中arr[0-3]分别代表id生成的时间戳,机器标识,业务标识,序列号

当然,Snowflake算法虽然性能较高,但不一定符合实际业务,如果条件允许可以根据Snowflake源码做定制化实现,结合实际业务并汲取snowflake优秀的地方重新实现。

上一篇下一篇

猜你喜欢

热点阅读