对于分布式,我们说下其中的分布式ID的定义

要求往往是

全局唯一,区别于单点系统的唯一,要求分布式系统内唯一

有序,保证生成的ID是有序递增的,在数据库存储中,有序性可以方便确定数据位置,更加高效

常见的有

基于数据库自增序列的实现,优缺点都很明显,但是特别简单

或者基于Twitter的Snowflake实现,这是常见的方式,结构定义如下

图片

一般长度为64位,适合使用Java的long来存储

头部是表示正负的

然后是41位的时间戳,使用System.currentTimeMillis()

后面是10位的WorkerID,标准定义为5位数据中心 + 5位机器ID

最后12位就是单位毫秒生成的序列号的理论极限

其余的唯一ID解决方案,很多可以算是Snowflake的变种

诸如Reids Zookeeper MonogoDB等中间件等,MonogoDB的ObjectId提供了一个12byte的ID定义,32位用于记录秒为单位的事件,机器ID是24位,16位进程ID,24位随机技术序列

Snowflake是否受着冬令时的影响

可以从Snowflake的具体算法实现认为,因为时间是依赖于System.currentTimeMillis()的,这个时间是返回的1970年1月1号UTC时间相差的毫秒数,和冬令时没有关系

对于我们业务需要的分布式ID,除了唯一和有序,需要考虑哪些要素?

我们首先要理解下,需要一个什么样的分布式ID

除了唯一和有序之外,考虑到分布式系统的功能,我们需要分布式ID

有意义,能够包含更多业务上的信息

高可用,分布式系统的必然要求

紧凑型,ID的大小受到应用的制约,太长的ID会降低MySQL等数据库索引的性能

对于主流的方案

首先是数据库自增方案,除了实现起来比较简单,生成的Id还能保证步长的递增,使用起来方便,但是每一次获取一个ID,就要触发数据库的一次写请求,代价高昂,性能上限明显

一般大厂有着自己的复合架构,美团的架构Leaf-Segment,有着缓存作用的Leaf层,对数据库操作通过数据库中间件提供的批量操作,能保证性能和高可用

snowflake的方案则是算法简单,依赖比较少,生成序列可预测,性能很好

但是其有着一定的不足,比如时钟偏斜问题,普通的计算机系统不能保证长久的一致性,可能发生时钟回拨的问题,导致时间戳不准确

所以Twitter建议开启NTP,为了保证时间一致的问题,不然可能导致时间戳不准确,产生重复ID

对于这个问题,可以缓存上一个时间戳,来判断是否时间不合理

但是序列号的可以预测是把双刃剑,虽然简化了部分工程,但是如果是安全相关的,可能被黑客利用

ID设计阶段需要谨慎的考虑暴露的信息,Erlang的flake基于了Mac地址计算,所以在安全敏感领域不可取

而且存在这时间数据位数的问题,可能和2038年相似极限问题,迟早有一日要面对

更加深入的对时钟和分布式时序的问题,比如不同机器的事件是不一致的,对于如何保证事件的有序性,我们可以看Time, Clocks, and the Ording of Events in a Distributed System

发表评论

邮箱地址不会被公开。 必填项已用*标注