欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

关于分布式uuid的一点设想

程序员文章站 2022-05-17 12:42:22
在一次公开课上,听别人讲过全局分布式uuid的设计,听过twitter的snowflake的设计。也听过,如果使用单独的计数器服务,不可能每次都保存当前计数器到文本,自己想到应该可以每隔一些数,例如1万次,10万次,反正64位的空间比较大,然后保存起来,那么就没有每次保存,对硬盘的写入压力。当出现故 ......

在一次公开课上,听别人讲过全局分布式uuid的设计,听过twitter的snowflake的设计。也听过,如果使用单独的计数器服务,不可能每次都保存当前计数器到文本,自己想到应该可以每隔一些数,例如1万次,10万次,反正64位的空间比较大,然后保存起来,那么就没有每次保存,对硬盘的写入压力。当出现故障的时候,跳过这么多数就可以了。只是,这个据说也是微信的uuid设计方案。我如果拿这个来讲,岂不是抄袭很严重。下面先给出uuid服务的图:

关于分布式uuid的一点设想

对于snowflake和微信的计数保存方案,各个各的优点,在我看来,可以考虑联合这两种方案。方案大致如下:

1. 对于不同的uuid server,给予不同的前缀,那么不同的uuid服务器的计数互不干扰,这个依赖于运维来实现,当然,如果开发打算自己做,我觉得也没有问题。

2. 对于每个uuid服务器,启动的时候,从当前电脑获取出当前的时间,在这里,可以考虑从epoch开始的秒数,然后有一个次数计数器,从0开始计数,假设这个计数器为32位,每次来一个请求,次数计数器+1,可以考虑当这个计数器达到最大值时,检查一下当前秒数,是不是和上一次获取秒数不同,如果相同(对于当前例子来说,基本不可能),则休眠若干毫秒,然后再次获取当前时间,如果不同,则将次数计数器重新置为0,继续进行计数。你们应该不难看出,我这里的计数器是

  

uuid server 的前缀 + 当前秒数 + 次数计数器值

3. 对于程序崩溃的处理,并不困难,只需要在程序启动的地方添加一个sleep(休眠),让程序1s后启动就可以了,那么就可以保证新的计数器,之前不会出现过。

4. 参数说明:上面所说的参数,可能不是最优的,例如,可以考虑,将时间改为从epoch开始的毫秒数,0.1s,或者其他的,这个看各自的需求,计数器,也可以考虑使用30个bit,24个bit,那么对应的最大值也需要根据这个进行调整,可能使总的计数器位数更少,或者更多。总之,这些东西有赖于各自测试,达到自己的目的就好。调整时间的精度,例如精度调整为0.1s,那么程序再次启动,sleep的时间可以更短,这个对某些项目可能有所帮助。

5. 需要处理的问题,这里主要是时间。有一点需要说明,这种实现方式,不同电脑存储的uuid之间没有严格的时间关系,没办法比较先后,同一台电脑的uuid可以区分先后。对于同一台电脑,重启之后运行正常,依赖于本地时间没有被改动,如果本地时间向前调整,那么可能会出现uuid重复的问题,先后顺序也不能被保证。只是,如果次数计数器值空间很大,那么出现重复的几率应该不大。如果打算将当前的前缀给另外一台电脑使用,那么需要那台电脑的时间不低于当前电脑,否则也可能出现重复。只是,如果那台电脑的时间在这台电脑时间之后,应该没有问题。

6. 如果担心时间问题,可以在程序中改变时间的时候,进行一次打印,打印出当前的时间,再次启动的时候可以进行查看。

7. 顺序的额外说明:不同电脑的时间同步对uuid跨电脑排序用处不大,因为uuid中的时间,只能说明记录的uuid发生在这个时间或者之后,并不一定是这个时间。

8. 对于计数器的实现来说,可以考虑使用atomic,也可以考虑使用中间件一类的,看实现方便,以及各自喜好。

9. 如果次数计数器为64位,或者类似的长度,可以考虑不进行检查,只在每次重启的时候,sleep例如1s,然后从0开始计数,因为按照当前甚至未来一段时间,64位的数字也很难在比较短的时间内耗尽,这样可以使处理逻辑更加简单,不过,可能会增加总的计数器的位数.

关于这个问题,就简单说到这里,如果文中有什么问题,希望能够指出来。