分布式ID生成器Ray

背景

在应用程序中,常常须要全局惟一的ID做为数据库主键。git

咱们须要什么样的ID生成器

  • 高性能 -> 1.生成性能高 2.插入性能高 3.索引性能高
  • 高可用 -> 1.依赖中间件要少 2.避免单节点问题
  • 不重复 -> 1.集群内全局不重复
  • 易使用 -> 1.接入简单 2.零学习成本
  • 语义性 -> 1.ID带有一些其它信息

如何知足这几点要求

  • 生成性能高 -> 大多数时间为内存分配,减小IO,减小锁
  • 插入性能高 -> 全局递增,避免页分裂
  • 索引性能高 -> 数值类型
  • 全局不重复 -> 分布式一致性
  • 服务高可用 -> 减小依赖中间件,减小中间件交互时间

总结特性

  • 全局递增
  • 数字类型
  • 全局惟一
  • 无锁并发
  • 内存分配
  • 单机生成(大多数时间)

SnowFlake

Twitter把存储系统从MySQL迁移到Cassandra,由于Cassandra没有顺序ID生成机制,因此开发了这样一套全局惟一ID生成服务。Ray的基本思想来自于SnowFlake,解决了一些SnowFlake中存在的一些问题github

如何保证单机递增不重复

最简单的思路:时间戳+序列号 伪代码:数据库

If 当前时间 > 上次ID生成时间 -> 当前时间+序列号0
If 当前时间 = 上次ID生成时间 -> 当前时间 + 上次序列号+1
If 当前时间 < 上次ID生成时间 -> 是否存在这种状况
复制代码

如何保证全局不重复

如何判断两个ID是重复的?咱们认为两个ID每一位都是重复的则两个ID重复。bash

两个重复的数值若是分别拼接上不一样的数值,则最终这两个数值不相同,如:并发

1111和1111,分别拼上1和2分布式

则1111-1和1111-2是不相同的性能

以前咱们在经过时间戳+序列号实现单机内不重复学习

那么咱们只须要保证单机内不重复的ID + 不重复的实例ID(workId)就能保证最终生成的ID不重复spa

如何保证workId不重复

这是一个分布式一致性问题设计

这个可使用分布式锁实现每一个实例独占一个workId

而且这仅在启动时和续约时会依赖中间件

即便依赖的中间件中间暂时不可用,只是新的服务不能使用,旧的正常

阶段性总结

  • 全局递增(时间戳自带全局递增)-> 插入,索引高性能
  • 内存分配(分配时无IO)-> 生成高性能
  • 单机生成(仅启动时强依赖中间件)-> 高可用

SnowFlake存在的问题

时钟偏斜问题

现代计算机至少有两种不一样的时钟:时钟和单调钟。尽管它们都衡量时间,但区分这二者很重要,由于它们有不一样的目的。

时钟

它根据某个日历返回当前日期和时间。例如: Java中的System.currentTimeMillis()返回自epoch(1970年1月1日 午夜 UTC,格里高利历)以来的秒数(或毫秒),根据公历日历,不包括闰秒。

单调钟

适用于测量持续时间(时间间隔),例如Java中的System.nanoTime()都是单调时钟。这个名字来源于他们保证老是前进的事实。

问题

时钟的问题在于,虽然它们看起来简单易用,但却具备使人惊讶的缺陷:一天可能不会有精确的86,400秒,时钟可能会先后跳跃,而一个节点上的时间可能与另外一个节点上的时间彻底不一样。 若是时间往前拨咱们就没法确保时间戳+序列号生成的ID是单机惟一的。

单位毫秒内生成数上限

SnowFlake单位毫秒内生成的ID数不能超过12位的序列位

问题总结

也就是说SnowFlake严重依赖于当前时间戳,而且只能处理当前时间戳大于等于上次时间戳的状况,对于当前时间戳小于上次时间戳的状况没法处理。

解决时钟偏斜问题

If 当前时间 > 上次ID生成时间 -> 当前时间+序列号0
If 当前时间 = 上次ID生成时间 -> 当前时间 + 上次序列号+1
If 当前时间 < 上次ID生成时间 ->上次ID生成时间 + 上次序列号 +1
复制代码

时钟偏斜,时间前跳其实就是等价于当前时间 < 上次ID生成时间

如何记录上次ID生成时间

首先上次ID生成时间记录在当前实例内存中 若是时钟回拨发生在重启时,上次ID生成时间记录会丢 此时新实例拿到了它的workId,而且新机器的时间戳更早就会出现ID重复的状况 因此须要后台按期同步全局最大的时间戳到中间件,实例退出和启动前同步时间戳

无尽的序列号

SnowFlake为何会出现序列号只有4096位的状况? 1.位数就那么多,你能够从机器位上分配 2.没有进位的空间,只支持当前时间戳>=上次时间戳 Ray支持当前时间<上次时间 意味着4096位用完能够往时间戳上进位,解决突发流量

Ray

Ray参考了SnowFlake的设计,解决了时钟回调和序列号不足的问题,而且提供了更好的并发性能 Github地址:github.com/KeshawnVan/…

相关文章
相关标签/搜索