雪花算法的使用(java)

1、雪花算法简介

雪花算法(Snowflake)是一种分布式唯一 ID 生成算法,能够生成唯一的、有序的、高可用的 ID,常用于分布式系统中作为全局唯一标识符(GUID)。雪花算法生成的 ID 是一个 64 位的整数,其中高位是时间戳,中间位是机器 ID,低位是序列号。

  1. 雪花算法生成的 ID 包含以下信息:
  • 1 位符号位:0 表示正数,1 表示负数(不使用,因为生成的 ID 都是正整数);
  • 41 位时间戳:精确到毫秒级别,可以支持 69 年的时间戳;
  • 10 位机器 ID:支持 1024 台机器;
  • 12 位序列号:支持每台机器每毫秒生成 4096 个 ID。
  1. 雪花算法生成的 ID 具有以下优点:
  • 全局唯一:由于每个 ID 都包含了时间戳和机器 ID 等信息,所以生成的 ID 是全局唯一的,不会出现重复的情况。
  • 有序递增:由于时间戳和序列号等信息的设计,生成的 ID 是有序递增的,可以方便地按照时间顺序排序。
  • 高性能:雪花算法生成 ID 的速度非常快,可以在短时间内生成大量的唯一 ID。
  • 易于部署:由于雪花算法是基于时间戳和机器 ID 等信息生成 ID,可以方便地进行分布式部署。
    因此,雪花算法常用于分布式系统中作为全局唯一标识符(GUID),例如订单号、流水号、消息 ID 等。

2、哪些业务需要实现雪花算法

通常,分布式系统需要实现全局唯一的 ID 时,可以考虑使用雪花算法。以下是一些常见的业务场景:

  1. 订单系统:订单系统中,通常需要生成唯一的订单号。使用雪花算法可以生成全局唯一的、有序递增的订单号,方便系统进行订单的管理和查询。

  2. 日志系统:在日志系统中,每个日志记录通常都需要一个唯一的 ID,用于标识这条日志记录。使用雪花算法可以快速生成唯一的、有序递增的日志 ID,方便系统进行日志的分析和查询。

  3. 分布式任务系统:在分布式任务系统中,通常需要将任务分配给多个节点进行处理,为了避免重复执行任务,需要给每个任务分配一个唯一的 ID。使用雪花算法可以生成全局唯一的、有序递增的任务 ID,方便系统进行任务的分配和跟踪。

  4. 消息队列系统:在消息队列系统中,每个消息通常都需要一个唯一的 ID,用于保证消息的唯一性和顺序性。使用雪花算法可以生成全局唯一的、有序递增的消息 ID,方便系统进行消息的管理和追踪。

  5. 分布式缓存系统:在分布式缓存系统中,每个缓存项通常都需要一个唯一的 ID,用于标识这个缓存项。使用雪花算法可以生成全局唯一的、有序递增的缓存项 ID,方便系统进行缓存的管理和查询。

总之,任何需要实现全局唯一的、有序递增的 ID 的业务场景,都可以考虑使用雪花算法来生成 ID。

3、雪花算法怎么使用

雪花算法生成的 ID 是一个 64 位的整数,其中高位是时间戳,中间位是机器 ID,低位是序列号。使用雪花算法生成 ID 的步骤如下:

  1. 定义一个 Snowflake 类,包含以下 3 个属性:
  • 机器 ID:用来区分不同的机器,范围是 0~1023。
  • 序列号:用来区分同一毫秒内生成的不同 ID,范围是 0~4095。
  • 上次生成 ID 的时间戳:用来记录上次生成 ID 的时间戳,单位是毫秒。
  1. 实现 Snowflake 类的 nextId() 方法,用来生成下一个 ID。该方法的具体实现如下:
Copy code
public synchronized long nextId() {
    // 获取当前时间戳
    long timestamp = System.currentTimeMillis();
    // 如果当前时间戳小于上次生成 ID 的时间戳,则说明系统时钟回退过,需要重新生成 ID
    if (timestamp < lastTimestamp) {
        throw new RuntimeException("Clock moved backwards. Refusing to generate id.");
    }
    // 如果当前时间戳和上次生成 ID 的时间戳相同,则在序列号上加 1
    if (timestamp == lastTimestamp) {
        sequence = (sequence + 1) & sequenceMask;
        // 如果序列号超过了最大值,则需要等待到下一毫秒再生成 ID
        if (sequence == 0) {
            timestamp = tilNextMillis(lastTimestamp);
        }
    } else { // 如果当前时间戳大于上次生成 ID 的时间戳,则序列号重置为 0
        sequence = 0;
    }
    // 更新上次生成 ID 的时间戳
    lastTimestamp = timestamp;
    // 生成 ID
    long id = ((timestamp - twepoch) << timestampLeftShift) | (workerId << workerIdShift) | sequence;
    return id;
}
  1. 在使用雪花算法生成 ID 的地方创建 Snowflake 实例,并调用 nextId() 方法生成 ID。例如:
Copy code
Snowflake snowflake = new Snowflake(0, 0);
long id = snowflake.nextId();

在上述代码中,创建了一个机器 ID 和序列号都为 0 的 Snowflake 实例,然后调用 nextId() 方法生成 ID。

需要注意的是,雪花算法的机器 ID 和序列号都需要进行配置,保证在不同的机器和同一毫秒内生成的 ID 不重复。另外,如果系统时钟回退,需要等待到下一毫秒再生成 ID,避免生成重复的 ID。

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
雪花算法是一种生成分布式唯一ID的算法,Java中可以使用Snowflake算法来生成唯一ID。Snowflake算法的核心思想是:使用一个64位的long型的数字作为全局唯一ID,其中高位的42位是时间戳,中间的10位是工作机器ID,低位的12位是序列号。具体实现可以参考以下代码: ```java public class SnowflakeIdGenerator { // 起始的时间戳 private final static long START_STMP = 1480166465631L; // 每一部分占用的位数 private final static long SEQUENCE_BIT = 12; // 序列号占用的位数 private final static long MACHINE_BIT = 10; // 机器标识占用的位数 private final static long DATACENTER_BIT = 2; // 数据中心占用的位数 // 每一部分的最大值 private final static long MAX_DATACENTER_NUM = -1L ^ (-1L << DATACENTER_BIT); private final static long MAX_MACHINE_NUM = -1L ^ (-1L << MACHINE_BIT); private final static long MAX_SEQUENCE = -1L ^ (-1L << SEQUENCE_BIT); // 每一部分向左的位移 private final static long MACHINE_LEFT = SEQUENCE_BIT; private final static long DATACENTER_LEFT = SEQUENCE_BIT + MACHINE_BIT; private final static long TIMESTMP_LEFT = DATACENTER_LEFT + DATACENTER_BIT; private long datacenterId; // 数据中心 private long machineId; // 机器标识 private long sequence = 0L; // 序列号 private long lastStmp = -1L; // 上一次时间戳 public SnowflakeIdGenerator(long datacenterId, long machineId) { if (datacenterId > MAX_DATACENTER_NUM || datacenterId < 0) { throw new IllegalArgumentException("datacenterId can't be greater than MAX_DATACENTER_NUM or less than 0"); } if (machineId > MAX_MACHINE_NUM || machineId < 0) { throw new IllegalArgumentException("machineId can't be greater than MAX_MACHINE_NUM or less than 0"); } this.datacenterId = datacenterId; this.machineId = machineId; } public synchronized long nextId() { long currStmp = getNewstmp(); if (currStmp < lastStmp) { throw new RuntimeException("Clock moved backwards. Refusing to generate id"); } if (currStmp == lastStmp) { sequence = (sequence + 1) & MAX_SEQUENCE; if (sequence == 0L) { currStmp = getNextMill(); } } else { sequence = 0L; } lastStmp = currStmp; return (currStmp - START_STMP) << TIMESTMP_LEFT // 时间戳部分 | datacenterId << DATACENTER_LEFT // 数据中心部分 | machineId << MACHINE_LEFT // 机器标识部分 | sequence; // 序列号部分 } private long getNextMill() { long mill = getNewstmp(); while (mill <= lastStmp) { mill = getNewstmp(); } return mill; } private long getNewstmp() { return System.currentTimeMillis(); } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值