20200103 高并发情况下id唯一生成器

互联网快速发展的今天,分布式应用系统已经见怪不怪,在分布式系统中,我们需要各种各样的ID,既然是ID那么必然是要保证全局唯一,除此之外,不同的业务还需要不同的特性,比如像并发巨大的业务要求ID生成效率高,吞吐大;比如某些银行类业务,需要按每日日期制定交易流水号;又比如我们希望用户的ID是随机的,无序的,纯数字的,且位数长度是小于10位的。等等,不同的业务场景需要的ID特性各不一样,于是,衍生了各种ID生成器。本文讲的订单号就是其中一种业务id,下面结合订单业务需求,介绍订单号的生成策略。

特征:全局唯一,不重复;安全性;性能;id生成效率高。订单号生策略。

支付中心多台部署,能够保证订单id唯一么?

 

业务需求:

1)订单号不能重复

2)订单号没有规则,即编码规则不能加入任何和公司运营相关的数据,外部人员无法通过订单ID猜测到订单量。不能被遍历。

3)订单号长度固定,且不能太长

4)易读,易沟通,不要出现数字字母换乱现象

5)生成耗时(生成效率高低)

 

关于订单号的生成,一些比较简单的方案:

1、数据库自增长ID

优势:无需编码

缺陷:

1)大表不能做水平分表,否则插入删除时容易出现问题(单表处理,不能分表)。

2)高并发下插入数据需要加入事务机制

3)在业务操作父、子表(关联表)插入时,先要插入父表,再插入子表;

 

2、时间戳+随机数

优势:编码简单

缺陷:随机数存在重复问题,即使在相同的时间戳下。每次插入数据库前需要校验下是否已经存在相同的数值。(每次校验是否存在该订单号,不存在才能插入,同一张表)

 

3、时间戳+会员ID

优势:同一时间,一个用户不会存在两张订单

缺陷:会员ID也会透露运营数据,鸡生蛋,蛋生鸡的问题

例如:S+yyMMddHHmmss+Math.abs(memberId.hashCode());[说明memberId为uuid的,String的hashCode唯一,而hashcode可能为负数] 哈希值长度不同。

 

4、UUID

优势:简单。劣势:用户不友好,索引关联效率较低。

UUID全称:Universally Unique Identifier,即通用唯一识别码。

UUID是由一组32位数的16进制数字所构成,所以理论上UUID的总数为16^32=2^128,约等于3.4*10^38。也就是说每纳秒产生1兆个UUID,要花100亿年才会将所有UUID用完。

UUID的标准形式包含32个16进制数字,以连字号分为五段,形式为8-4-4-4-12的32个字符,如:550e8400-e19b-41d4-a716-446655440000。

 

5、twitter的SnowFlake

Twitter-Snowflake算法产生的背景相当简单,为了满足Twitter每秒上万条消息的请求,每条消息都必须分配一条唯一的id,这些id还需要一些大致的顺序(方便客户端排序),并且在分布式系统中不同机器产生的id必须不同.Snowflake算法核心把时间戳,工作机器id,序列号(毫秒级时间41位+机器ID 10位+毫秒内序列12位)组合在一起。

 

 

除了最高位bit标记为不可用以外,其余三组bit占位均可浮动,看具体的业务需求而定。默认情况下41bit的时间戳可以支持该算法使用到2082年,10bit的工作机器id可以支持1023台机器,序列号支持1毫秒产生4095个自增序列id。

时间戳+机器id+序列号。

snowflake算法是一款本地生成的(ID生成过程不依赖任何中间件,无网络通信),保证ID全局唯一,并且ID总体有序递增,性能每秒生成300w+。 总体有序递增。

 

此方法可能存在id重复的问题,谨慎使用

        StringBuilder idBuilder = new StringBuilder();
        idBuilder.append(System.currentTimeMillis());
        System.out.println(idBuilder.toString());


        String userIdStr = "123456789".toString();
        if (userIdStr.length() <= 4) {
            idBuilder.append(userIdStr);
        } else {
            idBuilder.append(userIdStr.substring(userIdStr.length() - 4));
        }

        Random random = new Random();
        int randomPart = random.nextInt(99) + 1;
        if (randomPart < 10) {
            idBuilder.append('0');
        }
        idBuilder.append(randomPart);
        System.out.println(  Long.parseLong(idBuilder.toString()));

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值