在分布式系统中,通常会用到分布式ID来标注数据的唯一性,而分布式ID的生成方式又多种多样,今天我们就来讨论一下主流的分布式ID生成策略。

分布式ID基本需求

  • 全局唯一

  • 趋势递增

  • 信息安全

全局唯一

这是基本要求,不必解释

趋势递增

为什么要趋势递增呢?第一,由于我们的分布式ID,是用来标识数据唯一性的,所以多数时候会被定义为主键或者唯一索引。第二,并且绝大多数互联网公司使用的数据库是:MySQL,存储引擎为innoDB。对于 B+Tree这个数据结构来讲,数据以自增顺序来写入的话,b+tree的结构不会时常被打乱重塑,存取效率是最高的。

信息安全

由于数据是递增的,所以,恶意用户的可以根据当前ID推测出下一个,非常危险,所以,我们的分布式ID尽量做到不易被破解。

数据库主键自增(Flicker)

基于数据库主键自增的方案,名为 Flicker。主要是利用MySQL的自增主键来实现分布式ID。

以下为 Flicker实现分布式ID的主流做法:

1、需要单独建立一个数据库实例:flicker

  1. create database `flicker`;

2、创建一张表:sequence_id

  1. create table sequence_id(

  2. id bigint(20) unsigned NOT NULL auto_increment,

  3. stub char(10) NOT NULL default '',

  4. PRIMARY KEY (id),

  5. UNIQUE KEY stub (stub)

  6. ) ENGINE=MyISAM;

为什么用 MyISAM?不用 InnoDB?个人推测原因是:flicker算法出来的时候,MySQL的默认引擎还依旧是 MyISAM而不是 InnoDB,作者只是想用默认引擎而已,并无其他原因。

  • stub: 票根,对应需要生成 Id 的业务方编码,可以是项目名、表名甚至是服务器 IP 地址。

  • stub 要设置为唯一索引

3、使用以下SQL来获取ID

  1. REPLACE INTO ticket_center (stub) VALUES ('test');

  2. SELECT LAST_INSERT_ID();

Replaceinto 先尝试插入数据到表中,如果发现表中已经有此行数据(根据主键或者唯一索引判断)则先删除此行数据,然后插入新的数据, 否则直接插入新数据。一般 stub为特殊的相同的值。

这样,一个分布式ID系统算是可以搭建运行了。但是,有人要问:“这是一个单实例、单点的系统,万一挂了,岂不是影响所有关联的业务方?”

改进升华

是的。确实如此,因此又有人说:“可以利用MySQL主从模式,主库挂了,使用从库。” 这只能算是一种比较low的策略,因为如果主库挂了,从库没来得及同步,就会生成重复的ID。有没有更好的方法呢?我们可以使用“双主模式“,也就是有两个MySQL实例,这两个都能生成ID。如图所示,我们原来的模式:

双主模式是该怎么样呢?如何保持唯一性?我们可以让一台实例生成奇数ID,另一台生成偶数ID。

奇数那一台:

  1. set @@auto_increment_offset = 1; -- 起始值

  2. set @@auto_increment_increment = 2; -- 步长

偶数那一台:

  1. set @@auto_increment_offset = 2; -- 起始值

  2. set @@auto_increment_increment = 2; -- 步长

当两台都OK的时候,随机取其中的一台生成ID;若其中一台挂了,则取另外一台生成ID。如图所示:细心会发现,N个节点,只要起始值为1,2,...N,然后步长为N,就会生成各不相同的ID。(PS:后文有推导公式)

总结

优点:

  • 简单。充分利用了数据库自增 ID 机制,生成的 ID 有序递增。

  • ID递增

缺点:

  • 并发量不大。

  • 水平扩展困难,系统定义好了起始值、步长和机器台数,跑起来之后,添加额外的机器困难。

  • 安全系数低

Redis

Redis为单线程的,所以操作为原子操作,利用 incrby命令可以生成唯一的递增ID。

原理

单机单点,吞吐不够,加集群

假设N个节点,则步长为N,节点起始值为1,2,…… N。则三个节点生成的ID一定不同!想想为什么?以上信息条件可以转化为数学推理:1+x*N=2+y*N且x、y、N都为整成数且N不为1,试问等式存不存在?

  1. 答:

  2. 假设存在在起始值是1的节点上叠加x次之后等于起始值为2、叠加y次的值,

  3. 既 “1 + x * N = 2 + y * N” 等式成立

  4. 则:

  5. x * N = 1 + y * N

  6. x * N - y * N = 1

  7. (x - y) * N = 1

  8. (x - y) = 1 / N

  9. 又因为 x、y都为整成数;

  10. 所以x - y 必为整成数;

  11. 又因为只有N等于1的时候,1/N才为整成数;

  12. 与条件N为1不符合,所以不存在。

同理可证 1+x*N=3+y*N2+x*N=3+y*N也是如此。

优点

  • 性能显然高于基于数据库的 Flicker方案

  • ID递增

缺点

  • 水平扩展困难

  • Redis集群宕机可能会产生重复的id

  • 易破解

UUID

想必这个大家都熟悉。UUID是通用唯一识别码(Universally Unique Identifier)的缩写,是一种软件建构的标准,亦为开放软件基金会组织在分布式计算环境领域的一部分。

原理

UUID是由一组32位数的16进制数字所构成,是故UUID理论上的总数为16^32 = 2^128,约等于3.4 x 10^38。也就是说若每纳秒产生1兆个UUID,要花100亿年才会将所有UUID用完。

UUID是利用同一时空中的所有机器都是唯一的这一规则来确保唯一性的。

具体外形为:通常由以下几部分组成:

  • 系统时间

  • 时钟序列

  • 全局唯一的IEEE机器识别,如网卡MAC、机器SN等

生成方式多种多样,业界公认的是五种,分别是uuid1,uuid2,uuid3,uuid4,uuid5。目前使用最广泛的UUID是微软的 GUID

优点

  • 本地生成,性能极佳。无网络消耗

  • 全局唯一

缺点

  • 存储麻烦。16字节128位,通常以36长度的字符串表示,很多场景不适用

  • 通常是字符串,非自增,无序,不利于做主键。每次插入都会对B+tree结构进行修改

  • 破解相对困难,但是也不安全。参考"梅丽莎病毒事件,病毒作者制作的UUID包含Mac地址,被警方破解后,直接定位,抓捕归案?"

snowflake

snowflake即雪花算法,Twitter发明的。

原理

外形长这样:

  • 1位不用。二进制中最高位为1的都是负数,但是我们生成的id一般都使用整数,所以这个最高位固定是0。

  • 41位,用来记录毫秒的时间戳。41位可以表示的数值范围是:0 至 2^{41}-1,减1是因为可表示的数值范围是从0开始算的,而不是1,转化为年则是 2^{41}-1)/(1000*60*60*24*365)=69年。

  • 10位,用来记录工作机器id。最多可以部署在2^{10} = 1024个节点,我们可以根据具体的业务来定制具体分配的机器数量和每台机器1毫秒产生的id序号number数。例如可以把10bit分5bit给IDC,分5bit给工作机器。这样就可以表示32个IDC,每个IDC下可以有32台机器,可以将内容配置在配置文件中,服务去获取。

  • 12位。用来表示单台机器每毫秒生成的id序号,12位bit可以表示的最大正整数为2^12 - 1 = 4096,若超过4096,则重新从0开始。即,每台机器1毫秒内最多产生4096个ID,足够用了。

最后将上述4段bit通过位运算拼接起来组成64位bit.

广告

分布式系统概念与设计

作者:George Coulouris,金蓓弘

京东

由于是64位bit,所以完全可以用数字来表示ID。

基本是根据:

优点

  • ID为数字且时间位在高位,整个ID都是趋势递增的。

  • 不依赖任何第三方库,完全可以自己写,且性能非常高。

  • 可根据业务定制分配bit位,非常灵活。得益于 10位机器IDbit位。

  • 不太容易破解

缺点

  • 依赖机器的时间,如果机器时间不准或者回拨,可能导致重复

总结

在国内也得到了比较普遍的应用,各大厂根据其基本原理,生成了自己的规则:

  • 百度的uid-generator:https://github.com/baidu/uid-generator

  • 美团Leaf:https://github.com/zhuzhong/idleaf

参考文献

[flicker算法原文] http://code.flickr.com/blog/2010/02/08/ticket-servers-distributed-unique-primary-keys-on-the-cheap/

[分布式唯一ID极简教程] https://mp.weixin.qq.com/s/cqIK5Bv1U0mT97C7EOxmnA

[分布式 ID 生成策略] https://mp.weixin.qq.com/s/UAvSUDFJ8Fr0a-Na2Vr22g

[分布式ID系列(2)——UUID适合做分布式ID吗] https://mp.weixin.qq.com/s/kZAnYzJj4aBrtsk8Q9wA

https://segmentfault.com/a/1190000011282426

https://juejin.im/post/5d6fc8eff265da03ef7a324b#comment

https://segmentfault.com/a/1190000010978305

[Leaf——美团点评分布式ID生成系统] https://tech.meituan.com/2017/04/21/mt-leaf.html

[UUID的含义及实现原理]https://blog.csdn.net/reggergdsg/article/details/92091404

[通用唯一标识码UUID的介绍及使用] https://mp.weixin.qq.com/s/BjCL076USuhLj9GjhXDaTA [UUID简史] https://www.infoq.cn/article/talk-about-the-history-of-uuid/?utmsource=tuicool&utmmedium=referral

图解各路分布式ID生成算法相关推荐

  1. 理解分布式id生成算法--雪花算法(SnowFlake)

    分布式ID生成算法的有很多种,Twitter的SnowFlake就是其中经典的一种. 注: 1B就是1个字节. Byte.KB.B.MB.GB之间的关系是: Bit--比特 : B --字节:KB-- ...

  2. python雪花算法生成id_理解分布式id生成算法SnowFlake

    分布式id生成算法的有很多种,Twitter的SnowFlake就是其中经典的一种. 概述 SnowFlake算法生成id的结果是一个64bit大小的整数,它的结构如下图: 1位,不用.二进制中最高位 ...

  3. 美团技术分享:深度解密美团的分布式ID生成算法

    本文来自美团技术团队"照东"的分享,原题<Leaf--美团点评分布式ID生成系统>,收录时有勘误.修订并重新排版,感谢原作者的分享. 1.引言 鉴于IM系统中聊天消息I ...

  4. 分布式ID生成算法——leaf算法

    leaf是美团在雪花算法的基础上提出的一种分布式ID生成算法,它具有全局唯一.高可用.高并发.低延迟.接入简单(http或公司内rpc)的优点. Twitter:世界上不存在两片一样的雪花. 美团:世 ...

  5. java怎样生成32位全是整形的主键_你肯定会需要的分布式Id生成算法雪花算法(Java)...

    最近公司正好在做数据库迁移从oracle到mysql,因为之前oracle主键是使用的 SYS_GUID() 这个oracle提供的函数来生成全球唯一的标识符(原始值)由16个字节组成. 不过由于my ...

  6. 九种分布式ID生成算法详解

    一.分布式ID简介 1.什么是分布式ID? 在我们业务数据量不大的时候,单库单表完全可以支撑现有业务,数据再大一点搞个MySQL主从同步读写分离也能对付. 但随着数据日渐增长,主从同步也扛不住了,就需 ...

  7. java不规则算法_分布式id生成算法 snowflake 详解

    背景 在复杂分布式系统中,往往需要对大量的数据和消息进行唯一标识.如在支付流水号.订单号等,随者业务数据日渐增长,对数据分库分表后需要有一个唯一ID来标识一条数据或消息,数据库的自增ID显然不能满足需 ...

  8. java 唯一id生成算法_分布式全局唯一ID生成方案之snowflake算法

    已有的方案: 可大致分为: 完全依赖关系/非关系型数据库递增的方案 完全不依赖数据源作为生成因子的UUID 半依赖数据源作为生成因子的snowflake 为什么推荐snowflake? 这个问题,可以 ...

  9. 微信用户全局唯一标识_分布式系统的唯一ID生成算法对比

    在复杂分布式系统中,往往需要对大量的数据和消息进行唯一标识. 那么如何实现全局唯一id呢?有以下几种方案. (1)方案一:独立数据库自增id 这个方案就是说你的系统每次要生成一个id,都是往一个独立库 ...

最新文章

  1. java r$_基于javacv的人脸检测Demo
  2. 8.3 TensorFlow BP神经网络构建与超参数的选取
  3. 趣学python3(10)-函数注释方法
  4. Gateway网关-全局过滤器
  5. 怎么在QQ浏览器上使用微信聊天?
  6. 深入理解l内核v4l2框架之video for linux 2(转载)
  7. 循环神经网络(RNN)和LSTM初学者指南 | 入门资料
  8. 数据库DBeaverEE 22.0.2
  9. java中的 element_Java中队列的element()方法的用法
  10. 软件工程 选课系统的uml类图_UML学生选课系统.doc
  11. ShowWindow 显示窗口
  12. 什么互动管理必将风行于天下?(转)
  13. Windows管理用户账号
  14. 对大数据指标的理解、大数据常用指标都有哪些
  15. LCD1602的使用详解
  16. 供应链金融业务发展态势及提升路径
  17. CryEngine5.3(学习)
  18. STM32CubeMX | 基于STM32使用HAL库硬件SPI驱动WK2124一拖四SPI转四路串口芯片
  19. 图片编辑器哪个比较好?这篇文章告诉你
  20. SE5实现MiDas模型的运行

热门文章

  1. 哪个群发渠道更适合你的业务?WhatsApp vs SMS vs 电子邮件
  2. 姿态解算过程中四元数的更新
  3. 无线网标准IEEE802.11 (转)
  4. ceph-deploy部署指定版本ceph集群
  5. 分享84个NET源码,总有一款适合您
  6. Springboot-14 shiro整合mybati 密码可以用md5盐值加密 更加安全 授权认证登录
  7. Docker for windows 安装包
  8. ANdroid如何实现网络重定向以及使用DownLoadManager类下载
  9. 百草味基于“ EMR+Databricks+DLF ”构建云上数据湖的最佳实践
  10. baiduMap试手《办理进京证和市区警察查询进京证的地址浏览》