老顾导读
1、前言
2、回顾雪花算法
3、优化思路
4、启动场景的整体流程
5、服务运行中流程
6、临时节点的作用
7、总结
一、前言
老顾之前在文章《围观【美团】分布式唯一ID设计方案》中介绍了分布式唯一ID的一种方案,此方案满足了ID的基本要求
1、整个系统ID唯一
2、ID是数字类型,而且是趋势递增的
3、ID简短,查询效率快
但不适用订单ID的场景,因为竞争对手可以预测我们系统的订单量。之前老顾也介绍过redis的生成ID的方案,此方案比较简单,业务没有特殊要求的话推荐使用redis方案。
这篇文章老顾介绍一下美团公司的开源的snowflake方案。
二、回顾雪花snowflake算法
雪花算法生成64位的二进制正整数,然后转换成10进制的数。64位二进制数由如下部分组成
1位标识符:始终是0
41位时间戳:41位时间截不是存储当前时间的时间截,而是存储时间截的差值(当前时间截 - 开始时间截 )得到的值,这里的的开始时间截,一般是我们的id生成器开始使用的时间,由我们程序来指定的
10位机器标识码:可以部署在1024个节点,如果机器分机房(IDC)部署,这10位可以由 5位机房ID + 5位机器ID 组成
12位序列:毫秒内的计数,12位的计数顺序号支持每个节点每毫秒(同一机器,同一时间截)产生4096个ID序号
优点:
1、此方案每秒能够产生409.6万个ID,性能快
2、时间戳在高位,自增序列在低位,整个ID是趋势递增的,按照时间有序递增
3、灵活度高,可以根据业务需求,调整bit位的划分,满足不同的需求
缺点:
1、依赖机器的时钟,如果服务器时钟回拨,会导致重复ID生成
在分布式场景中,服务器时钟回拨会经常遇到,一般存在10ms之间的回拨;小伙伴们就说这点10ms,很短可以不考虑吧。但此算法就是建立在毫秒级别的生成方案,一旦回拨,就很有可能存在重复ID。
三、优化思路
雪花算法的问题就是时钟回拨导致,那我们能不能尽量避免回拨呢?思路就是:我们在系统中监控每台时钟是否回拨?如果回拨了,我们作一下调整就行了。
上图是整体架构,利用zookeeper中间件的特性。
一个ID服务就是一个生成ID的应用,多个可以保证高可用
我们先看持久化节点的作用:就是保存各个ID服务的节点信息,并保存时钟。
四、启动场景的整体流程
1、ID服务启动,注册到zookeeper
2、检查是否之前注册过,如果没有注册过,就把此服务注册到zookeeper中
3、节点的信息利用顺序节点,保证唯一。ID服务再把此生成的顺序ID当作workID,保存到本地文件系统中,这样以后再次启动时,就拿着此workId到zk上面去查找,是否之前注册过。(其实这个逻辑,就实现了自动发workId的功能,不需要人为到每个ID服务去配置,极大的减少运维成本)
4、如果之前没有注册过,生成了ID服务的zk节点,并把本地的时钟保存到此zk节点中。(保存时需要判断检测,此时钟是否正常?如何做呢?留一个思考点)。
五、服务运行中的流程
1、ID服务启动成功,提供ID服务
六、临时节点的作用
小伙伴们还记得老顾留下的思考点,如何判断本地时钟是否正确?就是利用临时节点。
1、遍历所有正在提供服务的ID服务器(IP + port),获取所有的ID服务器当地时钟,求平均值sum(time)/nodeSize。
2、如abs( 本地系统时间-sum(time)/nodeSize ) < 阈值,认为当前系统时间准确,正常启动服务,同时写临时节点leaf_temporary/${self} 维持租约
3、如大于阈值,认为时钟不正确,启动不成功,报警
七、总结
美团的雪花算法核心思想,就介绍到这里,希望能够帮助小伙伴。如果需要源码,可以去github中leaf-snowflake。值得一看。整体实现逻辑比较清晰。
也许小伙伴们用不到,不过最主要的是了解他们的设计思想,和解决方案。
领取专属 10元无门槛券
私享最新 技术干货