算法—雪花算法

简介: 雪花算法

结构图

image.png

  1. 共64位
  2. 第一位 占位符
  3. 之后的41位存储二进制毫秒时间,最大存储到2039年
  4. 后十位 5位存储机房id,5位存储机器id,一共10位最多存储1024个节点的机房机器码
  5. 最后12位存储不规则序列号


实现效果


  1. 有序 按照时间戳排序,整体有序
  2. 唯一 在分布式系统架构中也能达到无碰撞,获取唯一id
  3. 无规则 因为后12位是无规则,就无法通过序列号获取当前系统的数据
  4. 长度为19位,易于存储 例如uuid为32位,加上-共36位 太长不容易存储


缺陷


此时生成的id的时间是本地时间,如果本地时钟回调,还是有可能出现重复


解决办法:


百度的UidGenerator


美团的Leaf


java源码实现


twitter的雪花算法是scala语言的


/**

* twitter的snowflake算法 -- java实现

*

* @author beyond

* @date 2016/11/26

*/

public class SnowFlake {


   /**

    * 起始的时间戳

    */

   private final static long START_STMP = 1480166465631L;


   /**

    * 每一部分占用的位数

    */

   private final static long SEQUENCE_BIT = 12; //序列号占用的位数

   private final static long MACHINE_BIT = 5;   //机器标识占用的位数

   private final static long DATACENTER_BIT = 5;//数据中心占用的位数


   /**

    * 每一部分的最大值

    */

   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 SnowFlake(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;

   }


   /**

    * 产生下一个ID

    *

    * @return

    */

   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 {

           //不同毫秒内,序列号置为0

           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();

   }


   public static void main(String[] args) {

       SnowFlake snowFlake = new SnowFlake(2, 3);


       for (int i = 0; i < (1 << 12); i++) {

           System.out.println(snowFlake.nextId());

       }


   }

}


hutool提供工具类级封装


<dependency>

   <groupId>cn.hutool</groupId>

   <artifactId>hutool-captcha</artifactId>

   <version>5.3.6</version>

</dependency>


package com.zhangyao.snowflake.util;


import cn.hutool.core.lang.Snowflake;

import cn.hutool.core.net.NetUtil;

import cn.hutool.core.util.IdUtil;

import cn.hutool.core.util.IdcardUtil;

import lombok.extern.slf4j.Slf4j;

import org.springframework.beans.factory.annotation.Value;

import org.springframework.stereotype.Component;


import javax.annotation.PostConstruct;


/**

* @author: zhangyao

* @create:2020-06-04 09:23

**/

@Slf4j

@Component

public class SnowflakeUtil {



   private long workerId;


   @Value("${datacenterId}")

   private long datacenterId;


   private Snowflake snowflake = IdUtil.createSnowflake(workerId, datacenterId);


   @PostConstruct

   private void init(){

       try{

           workerId = NetUtil.ipv4ToLong(NetUtil.getLocalhostStr());

           log.info("当前机器id为:{}",workerId);

       }catch (Exception e){

           e.printStackTrace();

           log.warn(e.toString());

           workerId = NetUtil.getLocalhost().hashCode();

       }

   }



   public synchronized long getSnowflakeId(){

       return snowflake.nextId();

   }


   public synchronized long getSnowflake(long workerId,long datacenterId){

       Snowflake snowflake = new Snowflake(workerId, datacenterId);

       return  snowflake.nextId();

   }

}

若有收获,就点个赞吧

目录
相关文章
|
7月前
|
存储 算法 数据库
C++ “雪花算法“原理
C++ “雪花算法“原理
156 2
|
7月前
|
算法
雪花算法id生成器
雪花算法id生成器
512 0
|
7月前
|
算法 Java
雪花算法生成id
雪花算法生成id
|
5月前
|
算法 数据库
|
5月前
|
文字识别 算法 Java
文本,保存图片09,一个可以用id作为图片名字的pom插件,利用雪花算法生成唯一的id
文本,保存图片09,一个可以用id作为图片名字的pom插件,利用雪花算法生成唯一的id
|
6月前
|
算法 数据中心 Python
基于python雪花算法工具类Snowflake-来自chatGPT
基于python雪花算法工具类Snowflake-来自chatGPT
132 4
|
6月前
|
算法 Java
基于java雪花算法工具类SnowflakeIdUtils-来自chatGPT
基于java雪花算法工具类SnowflakeIdUtils-来自chatGPT
327 3
|
6月前
|
算法 PHP 数据中心
基于php雪花算法工具类Snowflake -来自chatGPT
基于php雪花算法工具类Snowflake -来自chatGPT
120 2
|
6月前
|
算法 数据中心 C++
基于C++雪花算法工具类Snowflake -来自chatGPT
基于C++雪花算法工具类Snowflake -来自chatGPT
|
5月前
|
存储 算法 Java
分布式自增ID算法---雪花算法(SnowFlake)Java实现
分布式自增ID算法---雪花算法(SnowFlake)Java实现
302 0
下一篇
DataWorks