分布式—雪花算法生成ID

一、简介

1、雪花算法的组成:

由64个Bit(比特)位组成的long类型的数字

0 | 0000000000 0000000000 0000000000 000000000 | 00000 | 00000 | 000000000000

1个bit:符号位,始终为0。

41个bit:时间戳,精确到毫秒级别,可以使用69年。

10个bit:工作机器ID,可以部署在1024个节点上。

12个bit:序列号,每个节点每毫秒内最多可以生成4096个ID。

2、雪花算法的优缺点

优点:

全局唯一:雪花算法生成的ID是全局唯一的,可以用于分布式系统中的数据分片和数据合并。

时间有序:雪花算法生成的ID中包含了时间戳信息,可以根据ID的大小推算出生成的时间。

高性能:雪花算法生成ID的速度很快,可以满足高并发的场景需求。

可扩展性:雪花算法的数据结构相对简单,易于扩展和修改。

缺点:

依赖于系统时钟:雪花算法生成ID的过程中依赖于系统时钟,如果系统时钟发生回拨,可能会导致生成的ID出现重复。

长度固定:雪花算法生成的ID长度固定为64位,可能会导致存储和传输成本较高。

不支持分布式计算:雪花算法生成ID的过程是单线程的,不能支持分布式计算。

二、项目中使用

1、引入依赖

XML 复制代码
<dependency>
    <groupId>com.github.beyondfengyu</groupId>
    <artifactId>snowflake-spring-boot-starter</artifactId>
    <version>1.0.0</version>
</dependency>

2、配置参数

cs 复制代码
snowflake:
  data-center-id: 1 # 数据中心ID,可以使用机器IP地址最后一段数字,范围为0-31
  machine-id: 1 # 机器ID,可以使用服务器编号,范围为0-31

3、使用

java 复制代码
@Service
public class OrderSevice {

    @Autowired
    private SnowflakeIdWorker snowflakeIdWorker;
 
    public Long creatOrderId() {
        return snowflakeIdWorker.nextId();
    }
}

三、手写雪花算法生成ID

java 复制代码
/**
 * 功能描述:雪花算法生成订单号
 */
public class SnowFlakeTemplate {

    //起始的时间戳
    private final static long START_STAMP = 1480166465631L;

    //每一部分占用的位数
    private final static long SEQUENCE_BIT = 12; //序列号占用的位数
    private final static long MACHINE_BIT = 5; //机器标识占用的位数
    private final static long DATA_CENTER_BIT = 5;//数据中心占用的位数

    //每一部分的最大值
    private final static long MAX_DATA_CENTER_NUM = -1L ^ (-1L << DATA_CENTER_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 DATA_CENTER_LEFT = SEQUENCE_BIT + MACHINE_BIT;
    private final static long TIMESTAMP_LEFT = DATA_CENTER_LEFT + DATA_CENTER_BIT;
    private long dataCenterId; //数据中心
    private long machineId; //机器标识
    private long sequence = 0L; //序列号
    private long lastStamp = -1L;//上一次时间戳

    public SnowFlakeTemplate(long dataCenterId, long machineId) {
        if (dataCenterId > MAX_DATA_CENTER_NUM || dataCenterId < 0) {
            throw new IllegalArgumentException("dataCenterId can't be greaterthan MAX_DATA_CENTER_NUM or less than 0");
        }
        if (machineId > MAX_MACHINE_NUM || machineId < 0) {
            throw new IllegalArgumentException("machineId can't be greater thanMAX_MACHINE_NUM or less than 0");
        }
        this.dataCenterId = dataCenterId;
        this.machineId = machineId;
    }

    private String Prefix() {
        String randomPrefix = "";
        for (int i = 0; i < 2; i++) {
            char c = (char) (Math.random() * 26 + 'A');
            randomPrefix += c;
        }
        return randomPrefix;
    }

    //产生下一个ID
    public synchronized String nextId() {
        long currStamp = getNewStamp();
        if (currStamp < lastStamp) {
            throw new RuntimeException("Clock moved backwards. Refusing to generate id");
        }
        if (currStamp == lastStamp) {
            //相同毫秒内,序列号自增
            sequence = (sequence + 1) & MAX_SEQUENCE;
            //同一毫秒的序列数已经达到最大
            if (sequence == 0L) {
                currStamp = getNextMill();
            }
        } else {
            //不同毫秒内,序列号置为0
            sequence = 0L;
        }
        lastStamp = currStamp;
        return Prefix() + ((currStamp - START_STAMP) << TIMESTAMP_LEFT //时间戳部分
                | dataCenterId << DATA_CENTER_LEFT //数据中心部分
                | machineId << MACHINE_LEFT //机器标识部分
                | sequence); //序列号部分
    }

    private long getNextMill() {
        long mill = getNewStamp();
        while (mill <= lastStamp) {
            mill = getNewStamp();
        }
        return mill;
    }

    private long getNewStamp() {
        return System.currentTimeMillis();
    }

    public static void main(String[] args) {
        System.out.println(new SnowFlakeTemplate(2, 3).nextId() );
    }
}
相关推荐
Hsu_kk几秒前
Kafka Eagle 安装教程
分布式·kafka
CodingBrother4 分钟前
Kafka 与 RabbitMQ 的联系
分布式·kafka·rabbitmq
pblh12316 分钟前
2023_Spark_实验十五:SparkSQL进阶操作
大数据·分布式·spark
silver98861 小时前
分布式相关杂项
分布式
jerry6098 小时前
7天用Go从零实现分布式缓存GeeCache(改进)(未完待续)
分布式·缓存·golang
古人诚不我欺9 小时前
jmeter常用配置元件介绍总结之分布式压测
分布式·jmeter
星染xr11 小时前
kafka 生产经验——数据积压(消费者如何提高吞吐量)
分布式·kafka
东方巴黎~Sunsiny11 小时前
如何监控Kafka消费者的性能指标?
分布式·kafka
飞升不如收破烂~11 小时前
kafka
分布式·kafka
龙哥·三年风水12 小时前
群控系统服务端开发模式-应用开发-前端个人信息功能
分布式·vue·群控系统