04. 分布式ID
分布式ID
在分布式系统中,譬如数据库拆分的场景下,我们往往需要分布式节点各自独立生成全局唯一的
-
全局唯一性:不能出现重复的
ID 号,既然是唯一标识,这是最基本的要求。 -
趋势递增:在
MySQL InnoDB 引擎中使用的是聚集索引,由于多数RDBMS 使用B-tree 的数据结构来存储索引数据,在主键的选择上面我们应该尽量使用有序的主键保证写入性能。 -
单调递增:保证下一个
ID 一定大于上一个ID ,例如事务版本号、IM 增量消息、排序等特殊需求。 -
不可枚举:如果
ID 是连续的,恶意用户的扒取工作就非常容易做了,直接按照顺序下载指定URL 即可;在很多应用场景下,会需要ID 无规则、不规则。
常见的分布式
-
节点本身有一个唯一标识,依赖节点自身标识实现生成
ID 的全局唯一性。比如zookeeper ,每个zookeeper 节点有一个预先设定好的nodeId ,nodeId 必须是一个正整数,zookeeper 节点生成的ID 都是本节点nodeId 的同余类( 比如集群数量是5 ,当前节点的nodeId=1 时,生成的ID=5*n + 1
) ,由于本节点生成的ID 递增,不同节点生成的ID 集合互不相交,因此保证了ID 的全局唯一。但是这种场景下节点需要持久化当前偏移量,在崩溃恢复后保证ID 的唯一性,此外如果集群数量发生变化,可能导致ID 重复,需要额外的代价做到集群数量增加。 -
节点本身无状态,由中心节点生成
ID ,这种方式对高可用和性能的挑战很高,但是可以生成全区唯一并且有序的序列,客户端不需要记录任何信息,每次需要ID 就向中心申请即可。微信的序列号就是这么做的,生成的ID 严格有序,并且做到高可用和高吞吐。
目前,有
方案 | 优点 | 缺点 |
---|---|---|
UUID | 性能高,本地生成,没有网络消耗 | 不易于存储,无法作为数据库主键 |
Snowflake | 不依赖第三方,趋势递增,灵活可配置 | 强依赖机器时钟,如果机器上时钟回拨,会导致发号重复或者服务会处于不可用状态 |
数据库自增 | 简单,趋势递增 | 强依赖数据库,单台 |