分布式ID特点:
- 唯一性
- 趋势递增
- 单调递增(严格递增)
分布式系统中,如果不引用分布式锁(顺序执行),单调递增意义不大。 - 安全性。如果ID是连续的,恶意用户的扒取工作就非常容易做了,直接按照顺序下载指定URL即可;如果是订单号就更危险了,竞对可以直接知道我们一天的单量。所以在一些应用场景下,会需要ID无规则、不规则。
系统特点:
- 高可用
- 高吞吐量
单调递增
满足:唯一性、单调递增。
- 微信序列号生成器
参见微信序列号生成器架构设计及演变
ID是由单台机器产生的,本文主要讲解了对存储和高可用的一些优化。 - Zookeeper的事务Id
ZK的事务Id由master产生,是严格递增的。
趋势递增
需要存储
产生的ID特点:唯一性、趋势递增。
阿里的tddl sequence和美团的Leaf-segment都属于该方案,都使用数据库存储(当然使用redis也可以),原理类似。下面以阿里tddl sequence为例说明原理。
- sequence表是分库分表的
/******************************************/
/* 表名称 = sequence */
/******************************************/
CREATE TABLE `sequence` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'Id',
`name` varchar(64) NOT NULL COMMENT 'sequence name',
`value` bigint(20) NOT NULL COMMENT 'sequence current value',
`gmt_create` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`gmt_modified` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT '修改时间',
PRIMARY KEY (`id`),
UNIQUE KEY `unique_name` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=gbk COMMENT='tddl-sequence table'
;
比如有N个分表,第一个分表负责生成%N=0的,第二个负责生成%N=1...,以此类推。业务机器可以设置为双buffer,每个buffer一批号段。
- 系统水平扩展比较困难
比如定义好了步长和机器台数之后,如果要添加机器该怎么做?假设现在只有一台机器发号是1,2,3,4,5(步长是1),这个时候需要扩容机器一台。可以这样做:把第二台机器的初始值设置得比第一台超过很多,比如14(假设在扩容时间之内第一台不可能发到14),同时设置步长为2,那么这台机器下发的号码都是14以后的偶数。然后摘掉第一台,把ID值保留为奇数,比如7,然后修改第一台的步长为2。让它符合我们定义的号段标准,对于这个例子来说就是让第一台以后只能产生奇数。扩容方案看起来复杂吗?貌似还好,现在想象一下如果我们线上有100台机器,这个时候要扩容该怎么做?简直是噩梦。所以系统水平扩展方案复杂难以实现
不需要存储
snowflake是Twriter的分布式ID系统,美团也有类似的Leaf-snowflake方案。
snowflake产生的ID满足唯一性、趋势递增、安全性。
snowflake严格依赖机器时钟的准确性,美团通过在机器启动时校验时间戳、关闭NTP时钟同步、运行时发现时钟错误自动摘除节点等策略来防止时钟问题。
大家可以参考Leaf——美团点评分布式ID生成系统获取更多细节。
美团的Leaf-snowflake方案在69年之后时间就会重复,怎么办?