在高并发分布式情况下生成唯一标识id

最近看了国外一个论文,研究了一番,在一些方面深度受益。在这里与大家分享下我对其中一点的分析。

在做项目的时候经常会用id作为唯一标识。

但是当有这样一个需求出现的时候:工程分布式部署,要求抗住高并发。并且生成的id是根据时间自增的。解决这个问题有很多种方法,但是要选择一个性价比比较高的策略比较不容易,例如:

1.数据库自增id控制

小型的应用直接自增足以。稍微中型一点的可以做下分表,突破下数据库的瓶颈,那么稍微大型一点的用什么方法来突破性能的瓶颈那?

例如我们曾经一个业务用postgresql序列来产生自增id,1个月生成3000w个id,平均下来一秒10左右,高峰*5倍。还是很轻松的。

如果这种方法数据库有点吃不消、或者效率有点低,那么可以采用sql大步长+cache:意思就是一次在数据库中取100个id,缓存在cache中,生成id的时候先判断cache中有无id,如果有则取出来用,如果没有去mysql取。当然虽然这种方法减少了mysql的访问次数和锁的次数,但是带来的就是程序中的并发问题。

2.当前时间的毫秒或者纳秒

毫秒这个也有点low了,稍微明白的工程师一眼就看出来了,很容易被破解。就算破解无所谓,对于高并发来说1ms也还是有可能生成多个id的。
纳秒倒是解决了高并发的问题,应该没有应用在一纳秒生成多个id的。但是如果完全依赖于纳秒,那么就等于完全失去了可控性,出了问题的话也不是很好办。
但是对于这样一个需求用纳秒还是能轻松解决问题的,不失为一个好的选择。

3.UUID

这个有点太长了,虽然能保证性能,但是串太长,不自增。


下面进入这个技术分享的主题:

4.通过约束条件生成唯一id

据听说twitter用的也是此方法
什么是通过约束条件生成唯一id,简单说就是在很极限的条件下生成很多id,足以满足需求,类似是唯一id。
比如在同一台机器上20ms内生成4000个id甚至更多,比如有10台机器,那么就是20ms生成40000个id,这样足以应对任何需求了,那么具体的做法是什么?

首先确定id存储用的是64位,那么一个64位的二进制是这样的:
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 1 1 0 0 1 1 1 0 0 0 0 0 1 0 1 1 1 1 1 0 0 1 1 1 1 1 0 1 1 1 1 1 0 1 0 0
看到这个就可以有很多事情可做了,约束条件生成id的方法就是 切割这个64位,把某段的二进制表示成一个约束条件,可空性非常强,能抗住高并发,并且不易破解

如上面的需求,如果要根据时间进行自增,那么就必须把当前的毫秒数放在高位了,比如前41位是当前时间。
41时间后面紧接9位是ip,ip之后的所有位数是自增数的二进制,记录着当前面位数相同的情况下这是第几个id。
所以如果现在有10台机器,那么这个id生成器生成id的极限是:同一台机器1ms内可以生成2的14次方个id。轻松满足需求。
最后切割成的效果可能是这样:

但是,这不是这个方法最大的好处, 最大的好处是可以根据需求定制不同的约束条件,可以增加条件,继续分割这个64位数
那么当条件比较多,64位不够分割的时候怎么办。有办法,进行移位操作,比如讲时间条件右移4位,那么1ms的约束条件就变成了16ms了,完全根据需求而定。
所以这个方法最大好处莫过于灵活,可控性强,根据需求可以轻易定制不同类型id。
最后我们把拼凑的这个64位二进制转成10进制存入数据库或者缓存中。
具体实现因需求而异,实现起来也相当简单,就不把实现贴出来了,只是做个分析,抛砖引玉。




  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值