在分布式系统中,一般会用到分布式ID来标注数据的惟一性,而分布式ID的生成方式又多种多样,今天咱们就来讨论一下主流的分布式ID生成策略。html
这是基本要求,没必要解释git
为何要趋势递增呢? 第一,因为咱们的分布式ID,是用来标识数据惟一性的,因此多数时候会被定义为主键或者惟一索引。 第二,而且绝大多数互联网公司使用的数据库是:MySQL,存储引擎为innoDB。 对于B + Tree
这个数据结构来说,数据以自增顺序来写入的话,b+tree的结构不会时常被打乱重塑,存取效率是最高的。github
因为数据是递增的,因此,恶意用户的能够根据当前ID推测出下一个,很是危险,因此,咱们的分布式ID尽可能作到不易被破解。算法
基于数据库主键自增的方案,名为Flicker
。 主要是利用MySQL的自增主键来实现分布式ID。数据库
如下为Flicker
实现分布式ID的主流作法:segmentfault
create database `flicker`;
复制代码
create table sequence_id(
id bigint(20) unsigned NOT NULL auto_increment,
stub char(10) NOT NULL default '',
PRIMARY KEY (id),
UNIQUE KEY stub (stub)
) ENGINE=MyISAM;
复制代码
为何用MyISAM
?不用InnoDB
?我的推测缘由是:flicker
算法出来的时候,MySQL的默认引擎还依旧是MyISAM
而不是InnoDB
,做者只是想用默认引擎而已,并没有其余缘由。安全
REPLACE INTO ticket_center (stub) VALUES ('test');
SELECT LAST_INSERT_ID();
复制代码
Replace into
先尝试插入数据到表中,若是发现表中已经有此行数据(根据主键或者惟一索引判断)则先删除此行数据,而后插入新的数据, 不然直接插入新数据。 通常stub
为特殊的相同的值。bash
这样,一个分布式ID系统算是能够搭建运行了。可是,有人要问:“这是一个单实例、单点的系统,万一挂了,岂不是影响全部关联的业务方?”服务器
是的。确实如此,所以又有人说:“能够利用MySQL主从模式,主库挂了,使用从库。” 这只能算是一种比较low的策略,由于若是主库挂了,从库没来得及同步,就会生成重复的ID。 有没有更好的方法呢? 咱们可使用“双主模式“,也就是有两个MySQL实例,这两个都能生成ID。 如图所示,咱们原来的模式: 微信
双主模式是该怎么样呢?如何保持惟一性? 咱们可让一台实例生成奇数ID,另外一台生成偶数ID。
奇数那一台:
set @@auto_increment_offset = 1; -- 起始值
set @@auto_increment_increment = 2; -- 步长
复制代码
偶数那一台:
set @@auto_increment_offset = 2; -- 起始值
set @@auto_increment_increment = 2; -- 步长
复制代码
当两台都OK的时候,随机取其中的一台生成ID;若其中一台挂了,则取另一台生成ID。 如图所示:
优势:
缺点:
Redis为单线程的,因此操做为原子操做,利用incrby
命令能够生成惟一的递增ID。
1 + x * N = 2 + y * N 且 x、y、N都为整成数且N不为1,试问等式存不存在?
答:
假设存在在起始值是1的节点上叠加x次以后等于起始值为二、叠加y次的值,
既 “1 + x * N = 2 + y * N” 等式成立
则:
x * N = 1 + y * N
x * N - y * N = 1
(x - y) * N = 1
(x - y) = 1 / N
又由于 x、y都为整成数;
因此x - y 必为整成数;
又由于只有N等于1的时候,1/N才为整成数;
与条件N为1不符合,因此不存在。
复制代码
同理可证1 + x * N = 3 + y * N
和2 + x * N = 3 + y * N
也是如此。
Flicker
方案想必这个你们都熟悉。 UUID
是通用惟一识别码(Universally Unique Identifier)的缩写,是一种软件建构的标准,亦为开放软件基金会组织在分布式计算环境领域的一部分。
UUID
是利用同一时空中的全部机器都是惟一的这一规则来确保惟一性的。
具体外形为:
生成方式多种多样,业界公认的是五种,分别是uuid1,uuid2,uuid3,uuid4,uuid5。 目前使用最普遍的UUID是微软的GUID
。
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. 因为是64位bit,因此彻底能够用数字来表示ID。
基本是根据:
10位
机器IDbit位。在国内也获得了比较广泛的应用,各大厂根据其基本原理,生成了本身的规则:
互联网技术窝
,问题直接在公众号内留言便可参考文献: [flicker算法原文] code.flickr.com/blog/2010/0…
[分布式惟一ID极简教程] mp.weixin.qq.com/s/cqIK5Bv1U…
[分布式 ID 生成策略] mp.weixin.qq.com/s/UAvSUDFJ8…
[分布式ID系列(2)——UUID适合作分布式ID吗] mp.weixin.qq.com/s/kZAnYz_Jj…
[Leaf——美团点评分布式ID生成系统] tech.meituan.com/2017/04/21/…
[UUID的含义及实现原理]blog.csdn.net/reggergdsg/…
[通用惟一标识码UUID的介绍及使用] mp.weixin.qq.com/s/BjCL076US… [UUID简史] www.infoq.cn/article/tal…