分布式ID

1. 为什么需要分布式ID

在单体结构的应用中,我们可以使用 MySQL 数据库的主键自增来为我们的数据设置唯一标识 ID,但是在分布式环境中,单个数据库的吞吐量成为整个应用的性能瓶颈,我们就可以搭建数据库集群来提升数据库的性能,此时如果还使用 MySQL 的主键自增来设置数据 ID 的话,就会出现重复的 ID,这样就会出现主键冲突的情况。

如果使用分布式的全局唯一 ID 就不用担心会出现这个问题了

2 分布式ID

一个好的分布式ID,一般要满足下列特性:

  • 唯一性:保证全局唯一
  • 高可用,可以由主从、集群等模式保证可用性
  • 高性能,比如基于内存
  • 递增性:适合作为数据库索引
  • 安全性:id如果是顺序递增,则容易暴露业务信息

3 全局唯一ID生成策略

1. 数据库自增ID

利用数据库的自增主键特性,每次插入记录时,数据库会自动生成一个唯一的ID。

优点

  • 简单易用,直接使用数据库提供的功能。
  • 保证唯一性。

缺点

  • 存在单点故障,数据库成为瓶颈。
  • 考虑数据量大时,可能需要分库分表.

2. UUID(Universally Unique Identifier)

UUID 是一种标准的唯一标识符,通常为128位长,可以保证全局唯一性。在 Java 中可以使用 java.util.UUID 的 randomUUID() 方法来获得:

1
java.util.UUID.randomUUID().toString();

优点

  • 生成简单,不依赖中心化服务。
  • 唯一性强。

缺点

  • 较长,占用空间大,不适合作为数据库索引。
  • 无序,无法实现范围查询
  • 插入时需要维护B+树,而B+树是有序的,因此插入操作的性能比自增ID要差,有些博客测评插入性能要差4倍

建议用自增ID作为主键,业务上采取UUID作为唯一标识

3. Twitter的Snowflake算法

Snowflake 是 Twitter 开源的分布式ID生成算法,通过组合时间戳、机器ID和序列号生成ID。

ID结构

  • 1位符号位:始终为0。
  • 41位时间戳:毫秒级时间戳,可使用69年。
  • 10位机器ID:支持1024台机器。
  • 12位序列号:每毫秒支持生成4096个ID。

优点

  • 高性能,低延迟。
  • 时间有序生成,适合数据库索引。

缺点

  • 依赖机器时间,时钟回拨可能导致ID重复或冲突。

时钟回拨问题,在一些Snowflake的变种已经解决掉了,如百度的uid-generator

4. 使用Redis生成ID

利用Redis的原子性递增操作,生成分布式唯一ID。使用 Redis 的 Incr 命令来把 <key,value> 中 key 的数值加 1 并返回,如果这个 key 不存在,则 key 值会被初始化为 0,再执行 Incr 命令来进行加 1 操作

1
2
// 使用 incr(key) 来让 key 加 1
long id = jedis.incr("id");

优点

  • 简单,利用Redis的原子操作保证唯一性。
  • 性能高,Redis操作速度快。

缺点

  • 依赖Redis服务,可能成为瓶颈。
  • 需要处理Redis的持久化和高可用性。

分布式ID
http://example.com/分布式ID/
作者
Panyurou
发布于
2023年3月17日
许可协议