说到分布式ID大家都不陌生
一般来说有以下几种生成唯一ID的方式
1. UUID,最常见,实现方式是形式为8-4-4-4-12的36个字符
优点:本机生成,没什么性能损耗;
缺点:太长;不适合做数据库主键;可能造成MAC地址泄露;无序性对Mysql索引不利;
2. Snowflake变种 实现方式把64-bit分别划分成多段,分开来标示机器、时间等
优点:毫秒数在高位,自增序列在低位,整体是趋势递增的;
不依赖数据库等第三方组件,稳定性好;灵活,可以根据业务分配bit位
缺点:强依赖时钟机器,如果发生时钟回拨,会导致ID重复
整体64位(雪花算法要求)
拆分为:
前41bit表示时间(1L<<41)/(1000L*3600*24*365)约等于69年的时间,一般来说,不会去查10年前的订单吧,10年的订单也不会放在一个库里,所以即使过了69年出现了重复的ID也不会影响届时的业务了。
接下来的10bit可以用来表示成1024台机器,如果对IDC划分有要求,还可以将5bit分给IDC,这样可以标识32个IDC,每个IDC可以有32台机器;
另外的12个自增序列号表示2的12次方个ID~~那么一秒一台机器可以产生的ID约等于1000*4096=409w也就是一台机器的QPS是409W,可以保证在任何一个IDC下的任何一台机器上产生的ID是唯一的;
(还缺了一位是第一位作为保留字段)
3. 数据库获取
还有一种方式就是通过DB获取,有些同学可能会问,DB怎么生成位移ID呢,就是通过DB的自增ID
优点是:非常简单,利用现有数据库系统的功能实现,成本小,有DBA专业维护;
ID号单调自增,可以实现一些对ID有特殊要求的业务
缺点是:强依赖DB,当DB异常时整个系统不可用,属于致命问题。配置主从复制可以尽可能的增加可用性,但是数据一致性在特殊情况下难以保证。主从切换时的不一致可能会导致重复发号;
ID发号性能瓶颈限制在单台MySQL的读写性能。
解决方案:
根据以上三种方式的问题,我们看下能否进行优化进而其解决存在的问题来满足我们的场景需要。
首先PASS掉UUID,我们针对雪花算法和数据库自增ID来考虑
对于雪花算法来说,由于引入了机器时钟导致存在回拨的问题,那我们就重点把问题解决放在如何解决时钟回拨问题:
解决方式也很简单,就是通过一种方式去记录下一台机器上所产生的雪花算法ID,当检测到某台机器可能发生了时钟回拨后,不再使用当时的时间,而是取一个未来的时间或者暂时停止生成ID;
首先如何检测到发生了时钟回拨?
什么是时钟回拨?一般来说机器获取时间都是获取当前机器的时间,而当前机器的时间是怎么获取的呢?是通过与NTP Server交互进行的校对
可以通过ntpstat命令来获取当前的同步状态
synchronised to NTP server (xxx) at stratum 5
time correct to within 231 ms
polling server every 1024 s
说明当前是同步的
针对时钟回拨可以采取换workerId的方式
2.DB优化
针对DB压力问题,批量获取代替单条每次获取;
另外双buffer预取;
基本可以满足性能要求
网友评论