4. 分布式ID
1. 分布式ID
分布式ID的特性
① 唯一性:确保生成的ID是全局唯一的。
② 有序递增性:确保生成的ID是对于某个用户或者业务是按一定的数字有序递增的。
③ 高可用性:确保任何时候都能正确的生成ID。
④ 带时间:ID里面包含时间,一眼扫过去就知道哪天的数据
分布式id方案大概有:
① 数据库自增ID(定义全局表)
② UUID
③ Twitter**-Snowflake算法**
2. 定义全局表
在数据库中专门创建一张序列表,利用数据库表中的自增ID来为其他业务的数据生成一个全局ID,那么每次要用ID的时候,直接从这个表中获取即可。
CREATE TABLE `uid_table` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `business_id` int(11) NOT NULL, PRIMARY KEY (`id`) USING BTREE, UNIQUE (business_type) )
在应用程序中,每次调用下面这段代码,就可以持续获得一个递增的ID。
begin
replace into uid_table (business_id) values(2);
select last_insert_id();
commit;
其中,replace into是每次删除原来相同的数据,同时加1条,就能保证我们每次得到的就是一个自增的ID。
优点:
非常简单,利用现有数据库系统的功能实现,成本小,有DBA专业维护。
ID号单调自增,可以实现一些对ID有特殊要求的业务。
缺点:
强依赖DB,当DB异常时整个系统不可用,属于致命问题。配置主从复制可以尽可能的增加可用性,但是数据一致性在特殊情况下难以保证。主从切换时的不一致可能会导致重复发号。
ID发号性能瓶颈限制在单台MySQL的读写性能。
3. UUID
UUID的格式是: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx 8-4-4-4-12共36个字符,它是一个128bit的
二进制转化为16进制的32个字符,然后用4个 - 连接起来的字符串。
UUID的五种生成方式
① 基于时间的UUID(date-time & MAC address): 主要依赖当前的时间戳及机器mac地址,因此可以保证全球唯一性。(使用了Mac地址,因此会暴露Mac地址和生成时间。)
**② **分布式安全的UUID(date-time & group/user id)将版本1的时间戳前四位换为POSIX的UID或GID。
**③ **基于名字空间的UUID-MD5版(MD5 hash & namespace),基于指定的名字空间/名字生成MD5散列值得到,标准不推荐。
④ 基于随机数的UUID(pseudo-random number):基于随机数或伪随机数生成。
⑤ 基于名字空间的UUID-SHA1版(SHA-1 hash & namespace):将版本3的散列算法改为SHA1。
在Java中,提供了基于MD5算法的UUID、以及基于随机数的UUID。
优点:
本地生成,没有网络消耗,生成简单,没有高可用风险。
缺点:
① 不易于存储:UUID太长,16字节128位,通常以36长度的字符串表示,很多场景不适用。
② 信息不安全:基于MAC地址生成UUID的算法可能会造成MAC地址泄露,这个漏洞曾被用于寻找梅丽莎病毒的制作者位置。
③ 无序查询效率低:由于生成的UUID是无序不可读的字符串,所以其查询效率低。
④ UUID不适合用来做数据库的唯一ID,如果用UUID做主键,无序的不递增,大家都知道,主键是有索引的,然后mysql的索引是通过b+树来实现的,每一次新的UUID数据的插入,为了查询的优化,都会对索引底层的b+树进行修改,因为UUID数据是无序的,所以每一次UUID数据的插入都会对主键的b+树进行很大的修改,严重影响性能
4. 雪花算法
SnowFlake 算法,是 Twitter 开源的分布式 id 生成算法。其核心思想就是:使用一个 64 bit 的 long 型的数字作为全局唯一 id。雪花算法的组成,一共64bit,这64个bit位由四个部分组成。
第一部分,1bit位,用来表示符号位,而ID一般是正数,所以这个符号位一般情况下是0。
第二部分,占41 个 bit:表示的是时间戳,是系统时间的毫秒数,但是这个时间戳不是当前系统的
时间,而是当前 系统时间-开始时间 ,即表示这个ID生成方案的使用的时间,时间戳是为了保证有序性,可读性,即开发者一看就能猜到ID是什么时候生成的。41位可以2^ 41 - 1表示个数字,可以表示的数值范围是:0 至 2^ 41-1,也就是说41位可以表示2^ 41-1个毫秒的值,转化成单位年则是(2^ 41-1)/1000 60 60 24*365=69年,也就是能容纳69年的时间。
第三部分,用来记录工作机器id,id包含10bit,意味着这个服务最多可以部署在 2^10 台机器上,
也就是 1024 台机器。其中这10bit又可以分成2个5bit,前5bit表示机房id、5bit表示机器id,意味着最多支持2^5个机房(32),每个机房可以支持32台机器。
第四部分,由12bit组成,表示一个递增序列,用来记录同毫秒内产生的不同id。如果是同一毫秒同一台机器来请求,需要使用序列号来保证唯一性,即保证同一毫秒内同一机器生成的ID是唯一的,这个其实就是为了满足我们ID的这个高并发,就是保证我同一毫秒进来的并发场景的唯一性。12位(bit)可以表示的最大正整数是2^12-1=4095,即可以用0、1、2、3、…4094这4095个数字,来表示同一机器同一时间截(毫秒)内产生的4095个ID序号。12位2进制,如果全部都是1的情况下,那么最终的值就是4095,也就是12bit能够存储的最大的数字是4095。