分布式id生成器设计分享

分布式环境下,大家可能经常会遇到需要一个全局唯一的id的需求,常见的方案雪花算法(SnowFlake)大家应该也很熟悉了,今天来分享一个分布式id生成器的设计思路,代码因为公司原因,就不贴出来了

先来分析一下分布式id生成器的应用场景

1.数据库分表分库后的主键

  • 业务数据库由于量级问题分库分表后,需要一个分布式主键id器,来生成主键,保证数据的主键id唯一
  • 这种场景下,生成的id最好基于时间自增,因为数据主键一般使用聚簇索引,基于时间自增的主键,可以避免随机IO导致的数据库写入性能低下

2.服务调用链路追踪的traceId

  • 在目前微服务架构流行的情况下,有很多分布式追踪方案应用而生,来追溯监控整个服务调用链路,来排查问题或者查看链路各个节点的响应时间,很多方案中,都会生成一个唯一id,作为traceId来追踪整个服务调用链
  • 这种场景下,因为要记录追踪每一次调用,生成的id除了要求唯一之外,还要求生成的效率高、吞吐量大

再来说一下我们这次设计的背景

我们设计分布式id生成器的背景

  • 1.随着业务的快速发展,我们一个服务的调用方越来越多,需要做水平扩容来提高服务的吞吐量;
  • 2.该服务中,分布式id生成逻辑耦合在服务逻辑代码中,目前分布式id生成的方案是基于snowflake雪花算法来生成;
  • 3.id为64bit位的long类型,算法只使用了3位bit位作为机器码,所以导致只能扩展到8个节点,严重制约了我们服务的水平扩展能力;
  • 4.而且每个节点的机器码是存储到配置文件中的,导致每一个版本上线时候,都需要根据要上线的节点,修改配置文件的机器码,造成了服务上线流程麻烦,潜在风险很大,并且没有办法实现自动扩容(因为新加节点,要修改配置文件中的机器码)

基于这个背景,我们确立了本次设计的目标

  • 1.把分布式id生成器单抽取出来,不和业务服务耦合,作为一个公共工具使用,支持多个服务的分布式id生成需求
  • 2.修改生成id的算法,接触节点的扩容限制
  • 3.机器码的配置从本地配置文件中提取到一个分布式配置中心,来简化上线流程,降低上线扩容时候的风险点。

分布式id技术选型

说一下分布式id的常用技术选型

UUID

UUID
标准格式说明:
  • UUID是128位的bit数组,格式化成36位字符串
  • 使用其8-4-4-4-12格式来分割32个16进制字符串
  • 目前为止,业界一共有5种方式生成UUID,这里就不详细说了,感兴趣的朋友可以查一下
优点
  • 本地算法生成,没有额外的网络请求开销,性能好
  • 能作为时间、空间上的唯一,而且接入成本低
缺点:
  • 如果使用作为数据库主键,36长度的字符串作为主键,占用物理空间,还占用大量的索引页(聚簇索引,辅助索引)的存储空间
  • 使用UUID作为主键,生成ID比较离散,会造成随机IO,导致的数据库写入性能低下
使用场景
  • 适用于非数据库主键场景,如幂等id、链路traceId、日志id等

基于mysql、redis等存储的自增序列

  • oracle中有序列,但是我基本没用过oracle,这里就拿mysql做例子了
mysql实现:
  • mysql实现,主要是利用自增主键auto_increment来实现,生成全局唯一id
  • 在分布式系统中,使用一个共用的数据库,创建一张表
  • 表的主键是自增式主键
  • 每次需要一个全局唯一id时候,在该表中插入一条数据,返回插入成功数据的主键来作为全局唯一的id
redis实现
  • redis的实现,主要依赖于redis单线程,使用redis的原子命令incr就可以生成一个全局唯一的id
  • 在分布式系统中,使用一个共用的redis,共用一个主键生成key
  • 每次使用命令incr就可以生成一个全局唯一的id
优点
  • 这里不对比mysql实现和redis实现了
  • 实现简单,利用存储各自的特性就可以实现,接入成本小
  • 而且主键是可以保证全局唯一并且是严格自增的
缺点
  • 利用数据存储系统实现的缺点都差不多
  • 性能严重受存储系统的性能制约,以我们公司的存储性能为例,mysql健康的qps在8千左右,redis健康qps在 8万左右
  • 扩展性差,难以通过数据分片实现扩展
优化方案
  • 实现数据切片,增加多个master节点,通过设计各个节点之间自增的数字不同;来保证master之间不能生成重复ID
  • 每个节点可以批量获取多个ID,减少与数据库的交互,提高性能
  • 但是多个master节点,太耗资源,基本很少人使用该方案(我见过一个toB的项目使用了)

基于zookeeper实现

实现思路一
  • 使用znode数据版本来生成序列号,生成32位和64位的数据版本
  • 客户端以这个版本号来作为唯一的序列号
  • 每当节点数据变化的时候dataversion的版本号会自增1,可以生成全局唯一的32位id
  • 每当修改数据,对应的mzxid(修改事务id)也会自增,可以生成全局唯一的64位id
实现思路二
  • 创建一个持久化节点,节点的数据为计数器的值,可以保证多个节点下计数器可以生成全局唯一的id
优点
  • 接入成本低
  • id可以保证严格全局唯一
  • 整个系统可以利用zk的高可靠性
缺点
  • zk性能上不上,还不如利用redis实现的性能好

sonwflake

  • Twitter在把存储系统从Mysql迁移到Cassandra的过程中,由于Cassandra没有顺序ID生成机制,于是自己开发一套全局唯一id生成算法,Snowflake 雪花算法,根据Twitter的业务需求,Sonwflake系统生成64位的ID由下面三部分组成:
  • 41位的时间戳(精准到毫秒,41位的长度可以使用69年)
  • 10位的机器码(10位的长度可以最多支持部署1024个节点)
  • 12位的计数顺序号(12位的计数器顺序号支持每个节点每毫秒产生4096个序列号)
雪花算法.png
优点
  • 因为是本地算法实现的,没有额外的网络开销,所以性能高
  • 时间戳在高位,自增序列号在低位,保证唯一的同时,又可以保证基于时间上是严格递增的
  • 不依赖于外部存储系统,没有外部依赖的限制
缺点
  • 因为高位是时间戳,生成时间戳的过程依赖本地服务的时钟系统
  • 如果服务器发生时钟回拨,基于本地时钟系统获取的时间戳可能会造成id重复

我们最后采用了sonwflake雪花算法,在结合我们的业务背景做了一些改动,实现了一个分布式id服务,供团队内的业务使用,这里说一下关键的改动点吧

为了解决机器码本地配置文件存放的问题,我们引入了zk来维护整个分布式id服务各个节点的机器码

  • 每个节点启动时,先获取机器id,连接zk
  • 判断是否为新增的节点
  • 如果是新增的节点,则生成一个唯一的机器码
  • 并且持久化到zk中
  • 并吧唯一机器码返回给服务节点,服务节点持久化到服务本地
  • 如果是已经注册过的节点(节点重启)
  • 直接获取生成过的机器码返回给服务节点,服务节点持久化到服务本地

为了减少时钟回拨的影响,利用zk来实现了一个时间校验器

  • 定时进行时钟校验
  • 服务节点连接zk,把自己的当前时间戳同步到zk,在获取其他节点,进行比较
  • 如果有异常,就直接报警处理
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容