分布式ID:互联网巨头是如何解决的?
2023-09-18 22:04:40
应对海量并发:分布式ID方案详解
随着互联网的爆炸式增长,用户数量和数据体量急剧攀升,对唯一ID的需求也随之激增。然而,传统的主键自增ID方案已难以满足海量并发的性能和可扩展性要求。分布式ID方案应运而生,为互联网巨头解决这一难题提供了有效手段。
什么是分布式ID?
分布式ID是一种在分布式系统中生成全局唯一ID的技术。它不同于传统的主键自增ID,而是通过分散式机制,在不同节点上独立生成ID,从而应对海量并发场景下的性能瓶颈。
分布式ID方案分类
根据生成方式,分布式ID方案可分为以下几类:
- 数据库自增ID: 由数据库系统自动生成ID。
- 算法生成ID: 根据特定算法生成ID,如雪花算法和UUID。
- 外部服务生成ID: 通过调用外部服务(如Segment)来生成ID。
分布式ID方案详解
数据库自增ID
这种方案最简单,由数据库创建自增ID表,通过数据库的自增机制生成ID。优点是实现简单,性能较好。但缺点是扩展性差,当并发量较大时会出现性能瓶颈。
算法生成ID
雪花算法是一种广泛使用的算法生成ID方案。它将ID分为三部分:时间戳、机器ID和序列号。时间戳记录ID生成的当前时间,机器ID记录ID生成所在的机器ID,序列号记录自上次生成ID以来的序号。雪花算法的优点是生成速度快,但缺点是需要维护机器ID,且时间戳的精度会影响ID的唯一性。
UUID
UUID(通用唯一标识符)是一种128位的随机生成ID,由一系列十六进制数字组成。它具有全局唯一性,不需要依赖任何外部系统。UUID的优点是随机性高,缺点是生成速度慢,且ID长度较长,不利于存储和传输。
Segment
Segment是一种基于Twitter开源的Snowflake算法实现的ID生成服务。它提供了RESTful API和客户端SDK,可以方便地生成ID。Segment的优点是易于使用,可扩展性好,但缺点是需要依赖外部服务,可能会产生额外的延迟。
不同方案对比
方案 | 优点 | 缺点 |
---|---|---|
数据库自增ID | 实现简单,性能较好 | 扩展性差 |
雪花算法 | 生成速度快 | 需要维护机器ID,时间戳精度影响唯一性 |
UUID | 全局唯一性高 | 生成速度慢,ID长度较长 |
Segment | 易于使用,可扩展性好 | 需要依赖外部服务 |
选型建议
根据不同的业务场景,应选择合适的分布式ID方案:
- 并发量较低,对性能要求不高:可以使用数据库自增ID方案。
- 并发量较大,对性能要求较高:可以使用雪花算法或Segment方案。
- 需要全局唯一性,对性能要求不高:可以使用UUID方案。
代码示例
雪花算法
public class SnowflakeIdGenerator {
private static final long EPOCH = 1420070400000L; // 起始时间戳,2015-01-01 00:00:00
private static final long DATA_CENTER_ID_BITS = 5L; // 数据中心ID长度,最多可以支持32个数据中心
private static final long WORKER_ID_BITS = 5L; // 机器ID长度,最多可以支持32台机器
private static final long SEQUENCE_BITS = 12L; // 序列号长度,最多可以生成4096个序列号
private static final long DATA_CENTER_ID_SHIFT = SEQUENCE_BITS;
private static final long WORKER_ID_SHIFT = SEQUENCE_BITS + DATA_CENTER_ID_BITS;
private static final long TIMESTAMP_LEFT_SHIFT = SEQUENCE_BITS + DATA_CENTER_ID_BITS + WORKER_ID_BITS;
private static final long MAX_DATA_CENTER_ID = ~(-1L << DATA_CENTER_ID_BITS);
private static final long MAX_WORKER_ID = ~(-1L << WORKER_ID_BITS);
private static final long MAX_SEQUENCE = ~(-1L << SEQUENCE_BITS);
private long dataCenterId; // 数据中心ID
private long workerId; // 机器ID
private long sequence; // 序列号
private long lastTimestamp = -1L; // 上次生成ID的时间戳
public SnowflakeIdGenerator(long dataCenterId, long workerId) {
if (dataCenterId < 0 || dataCenterId > MAX_DATA_CENTER_ID) {
throw new IllegalArgumentException("Data center ID must be between 0 and " + MAX_DATA_CENTER_ID);
}
if (workerId < 0 || workerId > MAX_WORKER_ID) {
throw new IllegalArgumentException("Worker ID must be between 0 and " + MAX_WORKER_ID);
}
this.dataCenterId = dataCenterId;
this.workerId = workerId;
}
public synchronized long nextId() {
long timestamp = System.currentTimeMillis();
if (timestamp < lastTimestamp) {
throw new IllegalStateException("Clock moved backwards.");
}
if (lastTimestamp == timestamp) {
sequence = (sequence + 1) & MAX_SEQUENCE;
if (sequence == 0) {
timestamp = tilNextMillis(lastTimestamp);
}
} else {
sequence = 0;
}
lastTimestamp = timestamp;
return ((timestamp - EPOCH) << TIMESTAMP_LEFT_SHIFT) | (dataCenterId << DATA_CENTER_ID_SHIFT) | (workerId << WORKER_ID_SHIFT) | sequence;
}
private long tilNextMillis(long lastTimestamp) {
long timestamp = System.currentTimeMillis();
while (timestamp <= lastTimestamp) {
timestamp = System.currentTimeMillis();
}
return timestamp;
}
}
Segment
import com.segment.analytics.Analytics;
import com.segment.analytics.messages.IdentifyMessage;
import java.util.UUID;
public class SegmentIdGenerator {
private static final Analytics analytics = new Analytics.Builder("YOUR_WRITE_KEY").build();
public static String nextId() {
IdentifyMessage message = new IdentifyMessage()
.userId(UUID.randomUUID().toString());
analytics.enqueue(message);
return message.getUserId();
}
}
总结
分布式ID方案是互联网巨头应对海量并发场景下ID生成需求的有效手段。根据不同的业务场景,选择合适的分布式ID方案至关重要。本文详解了多种分布式ID方案,希望能够为读者在实践中提供指导。
常见问题解答
1. 分布式ID和主键自增ID有什么区别?
分布式ID在分布式系统中生成全局唯一ID,而主键自增ID由数据库自动生成ID,具有局部唯一性。
2. 雪花算法和UUID有什么区别?
雪花算法是一种算法生成ID方案,它将ID分为时间戳、机器ID和序列号,而UUID是一种随机生成ID方案,具有全局唯一性。
3. Segment是一个什么样的服务?
Segment是一种基于Twitter开源的Snowflake算法实现的ID生成服务,它提供了RESTful API和客户端SDK,可以方便地生成ID。
4. 如何选择合适的分布式ID方案?
根据不同的业务场景,应考虑并发量、性能要求和全局唯一性要求,选择合适的分布式ID方案。
5. 分布式ID方案有哪些需要注意的要点?
需要考虑机器ID的维护、时间戳精度的影响、ID长度和存储成本等因素。