大茂名网

 找回密码
 用户注册

QQ登录

只需一步,快速开始

查看: 164|回复: 0

[【编导】] 今日访谈如何设计一个分布式 ID 发号器2022/12/26 8:32:26

[复制链接]

2万

主题

2万

帖子

9万

积分

钻石元老

Rank: 24Rank: 24Rank: 24Rank: 24Rank: 24Rank: 24

积分
98065
发表于 2022-12-26 08:32 | 显示全部楼层 |阅读模式

马上注册登陆,结交更多好友,享用更多功能,让你轻松玩转社区

您需要 登录 才可以下载或查看,没有账号?用户注册

x

设计「分布式ID发号器」就成为了一个非常常见的系统设计问题。今天我将带大家一起学习一下,如何设计一个分布式ID发号器。?大家好,我是树哥。ip地址归属地查询的最新消息可以到我们平台网站了解一下,也可以咨询客服人员进行详细的解答!


在复杂的分布式系统中,往往需要对大量的数据和消息进行仅有标识,例如:分库分表的ID主键、分布式追踪的请求ID等等。

于是,设计「分布式ID发号器」就成为了一个非常常见的系统设计问题。今天我将带大家一起学习一下,如何设计一个分布式ID发号器。



文章思维导图

系统诉求对于业务系统而言,对于全局仅有ID一般有如下几个需求:

全局仅有。生成的ID不能重复,这是比较基本的要求,否则在分库分表的场景下就会造成主键冲突。单调递增。保证下一个ID大于上一个ID,这样可以保证写入数据库的时候是顺序写入,提高写入性能。对于上面两个需求来说,首点是所有系统都要求的。而第二点则并不是所有系统都需要,例如分布式追踪的请求ID就可以不需要单调递增。而那些需要存到数据库里作为ID逐渐的场景,可能就需要保证全局仅有ID是单调递增的。

此外,我们可能还需要考虑安全方面的问题。如果一个全局仅有ID是顺序递增的,那么有可能会造成业务信息的露。例如订单ID每次递增1,那么竞争对手直接通过订单ID就可以知道我们每天的订单数,这对于业务来说是不可接受的。

对于上述的诉求,现在市面上有非常多的仅有ID解决方案,其中比较为常见的方案有如下4种:

UUID类雪花算法数据库自增主键R原子自增UUIDUUID全称叫UUI,即全局仅有标识符,它是J中自带的API。一个标准的UUID包含32个16进制的数字,以中横线作为分隔符分为5段,每段的长度分别为8字符、4字符、4字符、4字符、12字符,大小为36个字符,如下图所示。一个简单的UUID示例:6304100-29-334-635-246652140000。



UUID构成示意图

对于UUID这种仅有ID解决方案,点是没有外部依赖,纯本地生成,因此其性能非常高。但缺点也是非常明显的:

字段非常长,浪费存储空间。UUID一般长度为36个字符串,如果作为数据库主键存储,极大地增加索引的存储空间。

非自增,降低数据库写入性能。UUID不是自增的,如果作为数据库主键,那么法现顺序写,从而会降低数据库写入性能。

没有业务含义。UUID是没有业务含义的,我们法从UUID中获取到任何含义。

因此,对于UUID而言,其比较适用于非数据库ID存储的情况,例如生成一个本地的分布式追踪请求ID。

类雪花算法

雪花算法(SF)是T开源的分布式ID生成算法,其思路是用64位来表示一个ID,并将64位分割成4个部分,如下图所示。



雪花算法仅有ID构成示意图

首个部分:1位。固定为0,表示为正整数。二进制中比较高位是符号位,1表示负数,0表示正数。ID都是正整数,所以固定为0。第二个部分:41位。表示时间戳,精确到毫秒,可以使用69年。时间戳带有自增属性。第个部分:10位。表示10位的机器标识,比较多支持1024个节点。此部分也可拆分成5位I和5位I,I表示机房ID,I表示机器ID。第四部分:12位。表示序列化,即一些列的自增ID,可以支持同一节点同一毫秒生成比较多4095个ID序号。雪花算法的点是:

有业务含义,并且可自定义。雪花算法的ID每一位都有特殊的含义,我们从ID的不同位数就可以推断出对应的含义。此外,我们还可根据自身需要,自行增删每个部分的位数,从而现自定义的雪花算法。ID单调增加,有利于提高写入性能。雪花算法的ID比较后部分是递增的序列号,因此其生成的ID是递增的,将其作为数据库主键ID时可以现顺序写入,从而提高写入性能。不依赖第方系统。雪花算法的生成方式,不依赖第方系统或中间件,因此其稳定性较高。解决了安全问题。雪花算法生成的ID是单调递增的,但其递增步长又不是确定的,因此法从ID的差值推断出生成的数量,从而可以保护业务隐私。雪花算法几乎可以是非常完美了,但它有一个致命的缺点——强依赖机器时间。如果机器上的系统时间回拨,即时间较正常的时间慢,那么就可能会出现发号重复的情况。

对于这种情况,我们可以在本地维护一个文件,写入上次的时间戳,随后与当前时间戳比较。如果当前时间戳小于上次时间戳,说明系统时间出了问题,应该及时处理。

整体而言,雪花算法不仅长度更短,而且还具有业务含义,在数据库存储的场景下还能提高写入性能,因此雪花算法生成分布式仅有ID受到了大家的欢迎。

现在许多国内大厂的开源发号器的现,都是在雪花算法的基础上做改进,例如:百度开源的UG、美团开源的L等等。这些类雪花算法的核心都是将64位进行更合理的划分,从而使得其更适合自身场景。

数据库自增主键说起仅有ID,我们自然会想起数据库的自增主键,因为它就是仅有的。

对于并发量低的情况下,我们可以直接部署1台机器,每次获取ID的时候就往数据库表插入一条数据,随后返回主键ID。

这种方式的好处是非常简单,现成本低。此外,生成的仅有ID也是单调自增的,可以满足数据库写入性能的要求。

但其缺点也非常明显,即其强依赖数据库。当数据库异常的时候,会造成整个系统不可用。即使做了高可用切换,主从切换时数据同步不一致时,仍然可能造成重复发号。

另外,由于是单机部署,因此其性能瓶颈限制在单台MSQL机器的读写性能上,注定法承担起高并发的业务场景。

对于上面说到的性能问题,我们可以通过集群部署来解决。而集群部署之后的ID冲突问题,我们可以通过设置递增步长来解决。例如如果我们有3台机器,那么我们就设置递增步长为3,每台机器的ID生成策略为:

第1台机器,从0开始递增,步长为3,生成的ID分别是:0、3、6、9等等。第2台机器,从1开始递增,步长为3,生成的ID分别是:1、4、7、10等等。第3台机器,从2开始递增,步长为3,生成的ID分别是:2、5、8、11等等。这种方式解决了集群部署以及ID冲突的问题,可以在一定程度上提升并发访问的容量。但其缺点也比较明显:

只能依赖堆机器提高性能。当请求再次增多时,我们只能限堆机器,这貌似是一种物理防御一样。

水平扩展困难。当我们需要增加一台机器时,其处理过程非常麻烦。首先,我们需要先把新增的服务器部署好,设置新的步长,起始值要设置一个不可能达到的值。当把新增的服务器部署好之后,再一台台处理旧的服务器,这个过程真的非常痛苦,可以说是人肉运维了。

R原子自增由于R是内存数据库,其强大的性能非常适合用来现高并发的分布式ID生成。基于R现自增ID,其主要还是利用了R中的INCR命令。该命令可以将某个数自增一并返回结果,并且这个操作是原子操作。

通过R现分布式ID功能,其模式与通过数据库自增ID类似,只是存储介质从硬盘变成了内存。当单台R法支撑并发请求的时候,R同样可以通过集群部署和设置步长的方式去解决。

但数据库自增主键有的问题,R自增ID的方式也同样会有,即只能堆机器,同时水平扩展困难。此外,比起数据库存储的持久化,R是基于内存的存储,需要考虑持久化的问题,这同样是一个头疼的问题。

总结看了这么多个分布式ID的解决方案,那么我们到底应该选哪个呢

当我们在决策的时候,我们应该确定决策的维度。对于这个问题,我们应该关注的维度大致有:研发成本、并发量、性能、运维成本。

首先,对于UUID而言,其在各个方面其都不如雪花算法,仅有的点是JDK自带API。因此,如果你只是极其简单地使用,那么就直接使用UUID就可以,毕竟雪花算法还得写一写现代码呢。

其次,对于类雪花算法而言,其毋庸置疑是非常好的一种现。与UUID相比,其不仅有UUID本地生成、不依赖第方系统的点,还有业务含义、能提高写入性能、解决了安全问题。但其缺点在于要现雪花算法的代码,因此其研发成本稍稍比UUID高一些。

比较后,对于数据库自增ID与R原子自增这两种方式。数据库自增ID的方式,其点同样在于简单方便,不需要太高的研发成本。但其缺点是支撑的并发量太低,并且后续运维成本太高。因此,数据库自增ID这种方式,应该适用于小规模的使用场景下。而R原子自增的方式,其先在于能支撑高并发的场景。但缺点是需要自行处理持久化问题,运维成本可能比较高。

本人更倾向于数据库自增方式。这两种方式都是非常类似的,仅有的区别是存储介质。R原子自增方式非常,可能单机可以是数据库方式的好几倍。但是如果要考虑持久化的问题,那对于R来说就太复杂了。

我们把上面这四种现方式整理一下,可以汇总成下面的对比表格:

现方案



缺点

使用场景

UUID

性能高、不依赖第方、研发成本低

字段长浪费存储空间、ID不自增写入性能差、业务含义

非常简单的使用场景(用于简单测试)

类雪花算法

有业务含义、单调递增写入性能好、不依赖第方、业务安全

强依赖机器时间

高并发、业务场景复杂、需要将ID暴露给外部系统

数据库自增ID

研发成本低、单调递增写入性能好

依赖数据库、只能堆机器提高性能、维护成本高

对持久性有要求,不暴露给外部系统

R原子自增

高并发、单调递增写入性能好

依赖R、有业务问题、有持久性问题

对持久性没要求,不暴露给外部系统

总的来说,如果站在长期使用考虑,那么运维成本、高并发肯定是需要考虑的。在这个基础条件下,类雪花算法与数据库自增ID或许是相对好的选择。

参考资料分布式系统全局发号器的几点思考-掘金VIP!!非常好!L——美团点评分布式ID生成系统-美团技术团队(8条消息)六种方式现全局仅有发号器_北鹤M的博客-CSDN博客_发号器VIP!!不错,扩展视野!10|发号器:如何保证分库分表后ID的全局仅有性?
爱上大茂名,喜当大猫友,吃喝玩乐事,天天乐开怀!
您需要登录后才可以回帖 登录 | 用户注册

本版积分规则

QQ|客服:0668-2886677QQ:75281068|大茂微博|小黑屋|手机版|Archiver|大茂名网 ( 粤ICP备18149867号 )茂名市大茂科技有限公司 版权所有 

GMT+8, 2024-11-29 12:42 , Processed in 0.069674 second(s), 8 queries , Redis On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表