人文艺术 > 高并发下如何生成唯一订单号?

高并发下如何生成唯一订单号?

2020-10-20 19:34阅读(60)

高并发下如何生成唯一订单号?:互联网快速发展的今天,各类商城平台不计其数,商城及支付平台都有订单系统,订单系统里有一个关键元素就是订单号,订单号要具备:

1

互联网快速发展的今天,各类商城平台不计其数,商城及支付平台都有订单系统,订单系统里有一个关键元素就是订单号,订单号要具备全局唯一性。另外一方面,在分布式系统中也需要各种各样的ID,同样要求全局唯一性。

订单号生成方案

在一般项目中,我们要生成订单号可选的方案很多,比如说:

1、数据库自增长ID

  • 优点:借助数据库实现,无需代码实现;

  • 缺点:不能做水平分表,因为ID可能会重复;高并发场景下生成效率低速度慢;

2、时间戳 + 随机数

  • 优点:实现起来简单

  • 缺点:即使在相同的时间戳下随机数依旧存在重复的可能

3、会员ID + 时间戳

  • 优点:同一时间内,同个用户不会存在两个订单号

  • 缺点:会员ID泄露,存在一定风险

4、GUID、UUID

  • 优点:简单

  • 缺点:生成的订单号不友好、索引效率低下

高并发场景下生成的订单号存在重复的可能

所谓的高并发是指在较短时间段内服务器需要并行处理的请求数很多。在高并发场景下,同一秒可能会生成很多订单号,这样一来订单号就存在重复的可能性。

另外一方面,如果是多线程或者分布式环境下同一秒生成的重复订单可能性更大!

高并发、分布式环境下生成订单号的方案

1、利用Redis原子递增来实现(推荐)

因为Redis本身就是单线程的,再借助其原子操作INCR、INCRBY完全可以生成全局唯一的ID,而且速度快。

2、时间戳 + 多个随机数 + 乐观锁

3、GUID转换为数字


以上就是我的观点,对于这个问题大家是怎么看待的呢?欢迎在下方评论区交流 ~ 我是科技领域创作者,十年互联网从业经验,欢迎关注我了解更多科技知识!

2

高并发下如何生成唯一订单号(唯一主键),有几个方案和大家分享一下。

利用数据库生成

先说最笨的方法,利用数据库的自增长序列生成,数据库内唯一;数据库生成唯一主键,别的系统过来取;

  • 优点:理解起来最容易,用起来也最容易。

  • 缺点:也非常明显了,每种数据库的实现不同,如果数据库需要迁移的话比较麻烦;最大的问题是性能问题,因为题目中提到了【高并发下】,所以使用这个方法估计会很难满足性能需求。

利用Redis/MongoDB/zookeeper生成

Redis的单线程的,利用incr和increby;MongoDB的ObjectId;ZK通过znode数据版本;都可以生成全局的唯一标识码。

  • 优点:性能高于数据库;可以使用集群部署。

  • 缺点:需要引入对应的组件,增加系统的复杂度。

UUID

这个是分布式架构中,生成唯一标识码最常用的算法。UUID有基于MAC地址的,加上时间和时钟序列的,也有基于伪随机数的,基于加密哈希的。

  • 优点:本地生成,不需要第三方组件,生成比较简单,性能好。

  • 缺点:长度长,不利于存储,并且没有排序,是个字符串,不利于查询。解决无序问题,可参考Comb算法(combined guid/timestamp)。

Snowflake

Twitter开源,基于zk,41位时间戳(毫秒数)+10位机器的ID+12位毫秒内的流水号+1位符号位(永远是0)。

  • 优点:性能不错,单机内递增。

  • 缺点:依赖zk;依赖于机器时钟,分布式环境内可能会不是全局递增。

UidGenerator

百度开源,基于snowflake算法。

Leaf

美团开源。

  • 优点:能保证全局唯一性、高可用、趋势递增(不太安全,比如泄露公司订单数量)、单调递增等。

  • 缺点:依然会依赖第三方组件,zk或数据库。

我将持续分享Java开发、架构设计、程序员职业发展等方面的见解,希望能得到你的关注。

3

互联网架构


分布式/集群环境ID生成要求

  1. 全局唯一
  2. 高并发支持
  3. 高可用
  4. 趋势递增
  5. 信息安全
  6. 可读性

ID 生成策略

1、UUID

  1. 通用唯一识别码
  2. 组成: 当前日期 + 时间 + 时钟序列 + 机器识别码(MAC地址或其他)
  3. 在分布式系统中,所有元素都不需要通过中央控制端来 判断数据的唯一性

2、数据库自增

  • 关系型数据库都实现数据库自增ID;Mysql通过AUTO_INCREMENT实现、Oracle通过Sequence序列实现。
  • 在数据集群环境下,不同数据库节点可设置不同起步值、相同步长来实现集群下生成全局唯一、递增ID
  • SET GLOBAL auto_increment_increment = 3
  • SET GLOBAL auto_increment_offset = 1;


3、Snowflake

  • 41位时间戳+10位机器ID +12位序列号(自增),转换为长度为18的长整型
  • Twitter为满足每秒上万条消息的创建,每条消息都必须分配全局唯一ID,这些ID需要趋势递增,方便客户端排序。


4、Redis

  • Redis 实现自增ID
  • Redis实现了incr(key) API用于将key 的值递增1,并返回结果,如果key不存在,则创建并赋值为0,然后再执行incr操作。

几种策略总结


4
生成全局唯一ID有以下几种方式:

时间戳+用户ID+随机数

这其实并不是真正意义上的全局唯一ID,但是在并发量不高的场景中已经够用了。其中时间戳可以是毫秒级别

UUID

这种方式比较方便,有现成可用的JAR包,但是也有缺点:ID可读性不好,而且会造成索引树频繁页分裂,影响数据库性能和空间使用


数据库序列表

维护一张序列表。考虑到性能问题,不必每次生成ID都去操作数据库,可以设置一定的步长比如1000,每次从表中拿1000个序列号,从每台服务器内存中线性去取


Redis

维护一个序列号键值对,利用Redis自增的原子性,生成序列号


Snowflake

同一毫秒可以产生ID数量4194304个,优点是完全内存操作性能好,缺点是依赖于系统时钟一致性。如果某台机器的系统时钟回拨,有可能造成ID冲突,或者ID乱序


总结

最重要的还是根据项目的场景,尤其是并发量,选择最合适的方法


敬请关注

请点击关注按钮【IT徐胖子】会持续为大家奉献互联网和技术干货内容,感谢支持

5

由于是高并发情况,所以不建议使用数据库自增ID,可以参考如下方案:

1、redis自增id

2、UUID

3、时间戳+随机数

4、Twitter的snowflake算法

5、利用zookeeper生成唯一id,性能不如redis

6、MongoDB的ObjectId,和snowflake算法类似

6

雪花算法足够了。我这边两个业务线都是用的雪花算法 完全能保证唯一。