当前位置:首页 > Java资讯 > 正文内容

Java分布式ID生成方案:从原理到实战详解

admin1周前 (08-04)Java资讯7

Java分布式ID生成方案:从原理到实战详解

一、引言

在分布式系统中,ID生成是一个常见且关键的问题。分布式ID不仅需要保证唯一性,还要满足高性能、高可用性等要求。本文将深入探讨Java分布式ID生成方案,从原理到实战,为大家带来一套完整的解决方案。

二、分布式ID生成方案概述

分布式ID生成方案主要分为以下几种:

1. 数据库自增ID

2. UUID

3. 雪花算法(Snowflake)

4. 百度开源的Leaf算法

5. Twitter开源的Snowflake算法

本文将重点介绍雪花算法和Leaf算法。

三、雪花算法原理及实现

雪花算法是由Twitter开源的,它能够生成一个64位的唯一ID。这个ID由以下部分组成:

1. 时间戳(41位):精确到毫秒的时间戳,可以表示41位。

2. 数据中心ID(5位):表示数据中心ID,可以表示5位。

3. 机器ID(5位):表示机器ID,可以表示5位。

4. 序列号(12位):表示同一毫秒内生成的ID序列,可以表示12位。

雪花算法的原理如下:

1. 首先获取当前时间戳,并与上一次生成ID的时间戳进行比较。

2. 如果时间戳没有变化,则递增序列号。

3. 如果时间戳发生变化,则重置序列号,并更新上一次生成ID的时间戳。

4. 按照雪花算法的格式生成ID。

以下是雪花算法的Java实现:

```java

public class SnowflakeIdWorker {

private long workerId;

private long datacenterId;

private long sequence = 0L;

private long twepoch = 1288834974657L;

private long workerIdBits = 5L;

private long datacenterIdBits = 5L;

private long maxWorkerId = -1L ^ (-1L << workerIdBits);

private long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);

private long sequenceBits = 12L;

private long workerIdShift = sequenceBits;

private long datacenterIdShift = sequenceBits + workerIdBits;

private long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;

private long sequenceMask = -1L ^ (-1L << sequenceBits);

private long lastTimestamp = -1L;

public SnowflakeIdWorker(long workerId, long datacenterId) {

if (workerId > maxWorkerId || workerId < 0) {

throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));

}

if (datacenterId > maxDatacenterId || datacenterId < 0) {

throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId));

}

this.workerId = workerId;

this.datacenterId = datacenterId;

}

public synchronized long nextId() {

long timestamp = timeGen();

if (timestamp < lastTimestamp) {

throw new RuntimeException(String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));

}

if (lastTimestamp == timestamp) {

sequence = (sequence + 1) & sequenceMask;

if (sequence == 0) {

timestamp = tilNextMillis(lastTimestamp);

}

} else {

sequence = 0L;

}

lastTimestamp = timestamp;

return ((timestamp - twepoch) << timestampLeftShift) | (datacenterId << datacenterIdShift) | (workerId << workerIdShift) | sequence;

}

private long tilNextMillis(long lastTimestamp) {

long timestamp = timeGen();

while (timestamp <= lastTimestamp) {

timestamp = timeGen();

}

return timestamp;

}

private long timeGen() {

return System.currentTimeMillis();

}

}

```

四、Leaf算法原理及实现

Leaf算法是由百度开源的,它是一种基于Twitter Snowflake算法的改进方案。Leaf算法的主要特点是将数据中心ID和机器ID合并为一个ID,从而减少ID长度。

Leaf算法的原理如下:

1. 首先获取当前时间戳,并与上一次生成ID的时间戳进行比较。

2. 如果时间戳没有变化,则递增序列号。

3. 如果时间戳发生变化,则重置序列号,并更新上一次生成ID的时间戳。

4. 按照Leaf算法的格式生成ID。

以下是Leaf算法的Java实现:

```java

public class LeafIdWorker {

private long workerId;

private long datacenterId;

private long sequence = 0L;

private long twepoch = 1288834974657L;

private long workerIdBits = 5L;

private long datacenterIdBits = 5L;

private long maxWorkerId = -1L ^ (-1L << workerIdBits);

private long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);

private long sequenceBits = 12L;

private long workerIdShift = sequenceBits;

private long datacenterIdShift = sequenceBits + workerIdBits;

private long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;

private long sequenceMask = -1L ^ (-1L << sequenceBits);

private long lastTimestamp = -1L;

public LeafIdWorker(long workerId, long datacenterId) {

if (workerId > maxWorkerId || workerId < 0) {

throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));

}

if (datacenterId > maxDatacenterId || datacenterId < 0) {

throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId));

}

this.workerId = workerId;

this.datacenterId = datacenterId;

}

public synchronized long nextId() {

long timestamp = timeGen();

if (timestamp < lastTimestamp) {

throw new RuntimeException(String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));

}

if (lastTimestamp == timestamp) {

sequence = (sequence + 1) & sequenceMask;

if (sequence == 0) {

timestamp = tilNextMillis(lastTimestamp);

}

} else {

sequence = 0L;

}

lastTimestamp = timestamp;

return ((timestamp - twepoch) << timestampLeftShift) | (datacenterId << datacenterIdShift) | (workerId << workerIdShift) | sequence;

}

private long tilNextMillis(long lastTimestamp) {

long timestamp = timeGen();

while (timestamp <= lastTimestamp) {

timestamp = timeGen();

}

return timestamp;

}

private long timeGen() {

return System.currentTimeMillis();

}

}

```

五、总结

本文深入探讨了Java分布式ID生成方案,包括雪花算法和Leaf算法。通过了解这些算法的原理和实现,我们可以更好地应对分布式系统中ID生成的问题。在实际应用中,我们可以根据业务需求选择合适的分布式ID生成方案,以提高系统的性能和可用性。

相关文章

灰度发布:Java行业中的秘密武器,如何精准控制新功能上线?

灰度发布:Java行业中的秘密武器,如何精准控制新功能上线?

一、什么是灰度发布? 灰度发布(灰度上线)是指在软件上线过程中,将新功能、新版本或新服务逐渐推广到部分用户,而不是一次性推广给所有用户。这种发布方式可以降低新功能上线可能带来的风险,同时也能更好地收...

5G时代下的Java行业:变革与机遇并存

5G时代下的Java行业:变革与机遇并存

随着5G技术的飞速发展,各行各业都在积极拥抱这一新技术,Java行业也不例外。5G作为新一代移动通信技术,不仅为用户提供了更快的网络速度,也为Java开发者带来了前所未有的机遇和挑战。本文将从5G对...

Java LTS版本:揭秘企业级应用的稳定之选

Java LTS版本:揭秘企业级应用的稳定之选

随着互联网行业的飞速发展,Java作为一种广泛使用的编程语言,已经深入到了企业级应用的各个领域。从最初的Java 8到如今的Java 17,Java版本不断更新,功能也日益丰富。而在众多版本中,LT...

Java虚拟机面试题解析:从入门到精通

Java虚拟机面试题解析:从入门到精通

在Java开发领域,JVM(Java虚拟机)是每个开发者都必须面对的知识点。在面试过程中,JVM相关的问题往往能够考察面试者对Java基础的理解程度。本文将从JVM的基本概念、面试常见问题以及一些实...

Java文件下载:从入门到精通,实战案例分析

Java文件下载:从入门到精通,实战案例分析

在Java编程领域,文件下载是一个常见且实用的功能。它不仅能帮助我们实现数据的传输,还能在Web应用中提供便捷的数据下载服务。本文将深入探讨Java文件下载的原理、实现方法以及实战案例,旨在帮助读者...

Java并发编程:深入解析结构化并发机制

Java并发编程:深入解析结构化并发机制

在Java编程中,并发编程是一个非常重要的领域。随着现代计算机技术的发展,多核处理器和分布式计算已经成为主流。在这样的背景下,如何高效地利用多核处理器,实现并发编程,成为了Java开发者必须掌握的技...