生成分布式id
分布式系统中经常需要生成全局唯一 id ,要求:
- 全局唯一: 不能出现重复ID
- 高可用: 作为基础系统,被许多关键系统调用,一旦宕机,影响严重
在分布式系统中有很多的案例。
UUID
UUID 由算法生成,通常为36字节字符串表示。比如:
3A2504D0-4M89-11D3-9A0C-0305E82C3301
保证唯一性,根据不同的规范,定义不同位的值。可能包括MAC地址、时间戳、命名空间、随机数、时序等。
定义好规则后,可以直接由机器本地生成,相比其他来说不需要远程调用,使用方便。缺点是无法保证递增。
mysql 自增长
这个最早是 Flicker 采用的,基本所有聊到分布式 ID,都会说到这里。
思路是采取了mysql 的自增长 ID 的机制 ,(auto_increment + replace into)。
replace into 首先会尝试插入,如果存在会删除旧数据,插入新数据。
获取 ID :
1 | REPLACE INTO Tickets64(stub) values('a'); select last_insert_id(); |
避免单点故障,多个mysql 实例通过区分 auto_increment 的起始值和步长来生产 ID 。
优点:充分利用 mysql 的自增 id ,高可靠,有序
缺点:依赖数据库,性能可靠性取决于数据库。不好扩展。
snowflake
snowflake - 64bit Twitter的方案
41 位时间序列,精确到毫秒(可以使用69年)
10 位机器标示,(1024个节点)
12 位计数号 (每秒4096个ID)
优点: 整体递增,时间有序,高性能,可以根据业务灵活调整bit位划分
缺点: 依赖时钟,时间回拨可能导致重复 ID ,在分布式环境中非时间不一致导致非全局递增。
序列生成方式
- 使用数据库同步ID
- 每次取一定数量的可用 ID 在内存中,使用完后重新获取
- 每个业务可以定义自己的序列名,隔离业务 。
优点: 大大降低数据库压力,生产 ID 数量大大提高,不同业务不影响
缺点: 依赖数据库
阿里的 tddl,美团的Leaf 都是这种思路 。
对于有些对 id 连续有要求的,可以根据每秒生成数做限制。比如4096个只使用其中的一部分,每次取前对id进行随机的跳跃。可以得到不连续的id。
思考
uuid 和 snowflake 的方案思路是一样的,只是一个是依赖机器,一个是依赖时间。 mysql 的方法是在没有解决方法的时候简单又行之有效的方法。
序列生成已经是很标准成熟的解决方案
- 依赖数据库,又不完全依赖数据库,数据库只是用来做持久化,用来做数据段的分配。
- 取出一段 id 后,不管业务怎么用,保证了 id 生成的效率
- 保证 id 是整体递增的