说起分布式自增ID只知道UUID?SnowFlake(雪花)算法了解一下(Python3.0实现)

原文转载自「刘悦的技术博客」https://v3u.cn/a_id_155

但凡说起分布式系统,我们肯定会对一些海量级的业务进行分拆,比如:用户表,订单表。因为数据量巨大一张表完全无法支撑,就会对其进行分库分表。但是一旦涉及到分库分表,就会引申出分布式系统中唯一主键ID的生成问题,当我们使用mysql的自增长主键(auto_increment)时,充分感受到了它的好处:整个系统ID唯一,ID是数字类型,而且是趋势递增的,ID简短,查询效率快,在分布式系统中显然由于单点问题无法使用mysql自增长了,此时需要别的解决方案来支撑分布式业务。

首先映入脑海的一定是uuid

>>> import uuid
>>> print(uuid.uuid1())  
d13a0096-abca-11ea-8997-acbc32785ec1  
  

客观地说,如果一定要用uuid生成订单号这类东西也能凑合用,但是它有着罄竹难书的“罪行”:肉眼可见,它是无序的;长度是64位数字字母随机组合的字符串,占用空间巨大;完全不具备业务属性,也就是说使用uuid你完全无法推算出它到底是干嘛的;因为无序,所以趋势递增就更不用指望了;所以用uuid生成订单号就是自杀行为,适合它的是类似生成token令牌的场景。

那么我们就要说起业界鼎鼎有名的SnowFlake(雪花算法)发号器了。 Twitter-Snowflake算法产生的背景相当简单,为了满足Twitter每秒上万条消息的请求,每条消息都必须分配一条唯一的id,这些id还需要一些大致的顺序,让twitter可以通过一定的索引来进行检索,而在Twitter庞大的分布式系统中不同机器产生的id必须又必须不同。

image

它的好处显而易见,不仅全局唯一,并且有序按时间递增,同时占用空间少,生成的id仅仅是19位的整形数字,正好契合mysql的bigint数据类型,简直完美。

为啥它叫做Snowflake(雪花)算法?因为每个人都知道没有两片一样的雪花,这一事实源于晶体在天空中形成的方式。雪是一团冰晶,在大气中形成,并在它们下落时保持其形状。雪花形成于大气冷到能阻止它们融化变成雨或雨夹雪的时候。尽管云中的温度和湿度是不均匀的,但是在雪花大小的范围内,这些变量大约都是常数,这就是雪花的生长通常是对称的原因。另一方面,塔夫茨大学(Tufts University)化学家玛丽·简·舒尔茨(Mary Jane Shultz)指出:每片雪花都受到风,日光和其他变量变化的影响。她解释说,由于每个雪晶都到云层紊乱的影响,它们的形式都略有不同。

而Snowflake的逻辑也非常简单,雪花算法生成64位的二进制正整数,然后转换成10进制的数。64位二进制数由如下部分组成:

image

1位标识符:始终是0

41位时间戳:41位时间戳不是存储当前时间的时间戳,而是存储时间截的差值(当前时间截 - 开始时间截 )得到的值,这里的的开始时间截,一般是我们的id生成器开始使用的时间,由我们程序来指定的
10位机器标识码:可以部署在1024个节点,如果机器分机房(IDC)部署,这10位可以由 5位机房ID + 5位机器ID 组成
12位序列:毫秒内的计数,12位的计数顺序号支持每个节点每毫秒(同一机器,同一时间截)产生4096个ID序号

看到时间戳,就可以联想到它的缺陷,也就是它依赖机器的时钟,如果服务器时钟回拨,可能会导致重复ID生成。

这里我们用Python3.0来生成SnowFlake生成的唯一id

首先安装库

pip3 install pysnowflake

安装完成后,就可以在本地命令行启动snowflake服务

snowflake_start_server --worker=1

这里的worker就是当前节点的标识,此时编写代码就可以打印出当前客户端使用的snowflake的服务信息

import snowflake.client  
print(snowflake.client.get_stats())  
  
{'dc': 0, 'worker': 1, 'timestamp': 1591871273195, 'last_timestamp': 550281600000, 'sequence': 0, 'sequence_overload': 0, 'errors': 0}

当然了,如果一台服务器上起了很多节点服务,也可以指定相关的节点进行装载

host = '127.0.0.1'  
port = 30001  
snowflake.client.setup(host, port)

随后我们究竟可以根据该服务生成唯一id了

import snowflake.client  
  
print(snowflake.client.get_guid())

4368750411956359169 

可以看到这些id很明显带有递增的连续性,有的人会问了,假设我搭建了上千个节点的分布式系统,此时接口接到参数id,我怎么判断该id的订单信息存储在那个节点中呢?

其实很容易就可以判断,从SnowFlake的算法结构入手,本身就是二进制转换十进制的整形,现在我们反着进行解析即可,这里以这个19位的id为例子:4368750411956359169

首先将其转换为二进制

print(bin(4368750411956359169))  
0b11110010100000111010110101101001100001000000000001000000000001

可以看到上文所述的第一位是标识符,此后是41位的时间戳,紧接着10位的节点标识码,最后12位的递增序列,从后面数12位是:000000000001,再数5位是:00001 这5位就是某个节点的存储标识,但是它目前是二进制,我们再将它转换为十进制

print(int('00001',2))  
1

可以看到,转换结果显示该id存储在节点1的数据库中,如此就具备了相当强的业务属性,通过反推逻辑我们可以快速准确的定位到数据的具体存储位置从而进行查询。

结语:

其实关于分布式唯一id的解决方案,也不仅仅只有uuid或者snowflake,像redis的incr原子性操作自增,亦或者Mongodb极具特色的_objectid的生成方式,专为分布式而设计的ID生成方案。都是可以参考的解决方案,但是方案总归是方案,总有其自身的特点和缺陷,这就需要根据实际应用场景而具体问题进行具体分析了。

原文转载自「刘悦的技术博客」 https://v3u.cn/a_id_155

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