说起分布式自增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必须又必须不同。
它的好处显而易见,不仅全局唯一,并且有序按时间递增,同时占用空间少,生成的id仅仅是19位的整形数字,正好契合mysql的bigint数据类型,简直完美。
为啥它叫做Snowflake(雪花)算法?因为每个人都知道没有两片一样的雪花,这一事实源于晶体在天空中形成的方式。雪是一团冰晶,在大气中形成,并在它们下落时保持其形状。雪花形成于大气冷到能阻止它们融化变成雨或雨夹雪的时候。尽管云中的温度和湿度是不均匀的,但是在雪花大小的范围内,这些变量大约都是常数,这就是雪花的生长通常是对称的原因。另一方面,塔夫茨大学(Tufts University)化学家玛丽·简·舒尔茨(Mary Jane Shultz)指出:每片雪花都受到风,日光和其他变量变化的影响。她解释说,由于每个雪晶都到云层紊乱的影响,它们的形式都略有不同。
而Snowflake的逻辑也非常简单,雪花算法生成64位的二进制正整数,然后转换成10进制的数。64位二进制数由如下部分组成:
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
说起分布式自增ID只知道UUID?SnowFlake(雪花)算法了解一下(Python3.0实现)的更多相关文章
- Twitter分布式自增ID算法snowflake原理解析(Long类型)
Twitter分布式自增ID算法snowflake,生成的是Long类型的id,一个Long类型占8个字节,每个字节占8比特,也就是说一个Long类型占64个比特(0和1). 那么一个Long类型的6 ...
- 详解Twitter开源分布式自增ID算法snowflake(附演算验证过程)
详解Twitter开源分布式自增ID算法snowflake,附演算验证过程 2017年01月22日 14:44:40 url: http://blog.csdn.net/li396864285/art ...
- Twitter分布式自增ID算法snowflake原理解析
以JAVA为例 Twitter分布式自增ID算法snowflake,生成的是Long类型的id,一个Long类型占8个字节,每个字节占8比特,也就是说一个Long类型占64个比特(0和1). 那么一个 ...
- 【Java】分布式自增ID算法---雪花算法 (snowflake,Java版)
一般情况,实现全局唯一ID,有三种方案,分别是通过中间件方式.UUID.雪花算法. 方案一,通过中间件方式,可以是把数据库或者redis缓存作为媒介,从中间件获取ID.这种呢,优点是可以体现全局的递增 ...
- 分布式自增ID算法-Snowflake详解
1.Snowflake简介 互联网快速发展的今天,分布式应用系统已经见怪不怪,在分布式系统中,我们需要各种各样的ID,既然是ID那么必然是要保证全局唯一,除此之外,不同当业务还需要不同的特性,比如像并 ...
- 分布式ID生成系统 UUID与雪花(snowflake)算法
Leaf——美团点评分布式ID生成系统 -https://tech.meituan.com/MT_Leaf.html 网游服务器中的GUID(唯一标识码)实现-基于snowflake算法-云栖社区-阿 ...
- 分布式ID生成器 snowflake(雪花)算法
在springboot的启动类中引入 @Bean public IdWorker idWorkker(){ return new IdWorker(1, 1); } 在代码中调用 @Autowired ...
- 分布式Snowflake雪花算法
前言 项目中主键ID生成方式比较多,但是哪种方式更能提高的我们的工作效率.项目质量.代码实用性以及健壮性呢,下面作了一下比较,目前雪花算法的优点还是很明显的. 优缺点比较 UUID(缺点:太长.没法排 ...
- Twitter的分布式自增ID算法snowflake (Java版)
概述 分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的. 有些时候我们希望能使用一种 ...
随机推荐
- 渗透:winpcap
winpcap(windows packet capture)是windows平台下一个免费,公共的网络访问系统.开发winpcap这个项目的目的在于为win32应用程序提供访问网络底层的能力.它提供 ...
- 分布式下Session一致性架构举例
一.问题及方案 见这篇文章:分布式下Session一致性问题 二.分布式环境搭建: 系统环境 [root@centos7 ~]# cat /etc/redhat-release CentOS Linu ...
- Pandas 分组聚合 :分组、分组对象操作
1.概述 1.1 group语法 df.groupby(self, by=None, axis=0, level=None, as_index: bool=True, sort: bool=True, ...
- 第06组Alpha冲刺 (4/6)
目录 1.1 基本情况 1.2 冲刺概况汇报 1.郝雷明 2.曹兰英 3. 方梓涵 4.鲍凌函 5.董翔云 6.杜筱 7.黄少丹 8.曾丽莉 9. 詹鑫冰 10.吴沅静 1.3 冲刺成果展示 1.1 ...
- js 定时器 Timer
1 /* Timer 定时器 2 3 parameter: 4 func: Function; //定时器运行时的回调; 默认 null 5 speed: Number; //延迟多少毫秒执行一次 f ...
- CF1682C. LIS or Reverse LIS?
题意:给\(n\)个数,问你能构出严格上升子序列长度和下降子序列长度最小值的最大值. 思路: 如果一个数出现至少两次,ans++. 统计出现一次的个数,因为再最长上升子序列中,只能有一个值能贡献到下降 ...
- 基于.NetCore开发博客项目 StarBlog - (9) 图片批量导入
系列文章 基于.NetCore开发博客项目 StarBlog - (1) 为什么需要自己写一个博客? 基于.NetCore开发博客项目 StarBlog - (2) 环境准备和创建项目 基于.NetC ...
- 队列的java实现
今天老师提出一个问题,就是如何用java实现队列呢?我在网上找了许多资料,发现java也是可以很轻松的实现队列. 如下代码: package com; import java.util.Collect ...
- POJ1821 Fence 题解报告
传送门 1 题目描述 A team of $k (1 <= K <= 100) $workers should paint a fence which contains \(N (1 &l ...
- 分享一款自带工作流引擎的NodeJS全栈框架,接单快手、创业神器
CabloyJS是什么 CabloyJS是一款自带工作流引擎的Node.js全栈框架, 接单快手.创业神器, 基于koa + egg + vue + framework7 + mysql 在线演示 场 ...