a.twitter的雪花算法的计算由来

雪花算法是由 Twitter 公司开源的可在分布式系统中产生一个全局唯一 ID 的算法。最初 Twitter 把存储系统从 MySQL 迁移到 Cassandra,因为 Cassandra 没有顺序ID生成机制,所以开发了这样一套全局唯一ID生成服务。

「雪花算法」采用64bit作为id生成类型,并且将64bit划分为,如下图的几段
1.Twitter的Snowflake 算法 - 图1

  • 第一个bit位是标识部分,在java中由于long的最高位是符号位,正数是0,负数是1,一般生成的ID为正数,所以固定为0
  • 时间戳部分占41bit,这个是毫秒级的时间,一般实现上不会存储当前的时间戳,而是时间戳的差值(当前时间-固定的开始时间),这样可以使产生的ID从更小值开始;41位的时间戳可以使用69年,(1L << 41) / (1000L 60 60 24 365) = 69年
  • 工作机器id占10bit,这里比较灵活,比如,可以使用前5位作为数据中心机房标识,后5位作为单机房机器标识,可以部署1024个节点
  • 工作机器id占10bit,这里比较灵活,比如,可以使用前5位作为数据中心机房标识,后5位作为单机房机器标识,可以部署1024个节点
  • 12 bit,记录同一时间(毫秒)内产生的不同 id,也就是说同一毫秒内可以产生4096个不同 id

    b.遇到的问题—时钟回拨(重点)

    分布式情况下,需要保证各个系统时间⼀致,如果服务器的时钟回拨,就会导致⽣成的 id 重复

雪花算法的时间回拨问题

时间回拨问题是指系统在运行过程中,可能由于网络时间校准或者人工设置,导致系统时间主动或被动地跳回到过去的某个时间:
image.png
由于雪花算法重度依赖机器的当前时间,所以一旦发生时间回拨,将有可能导致生成的 ID 可能与此前已经生成的某个 ID 重复(前提是刚好在同一毫秒生成 ID 时序列号也刚好一致),这就是雪花算法最经常讨论的问题——时间回拨。

时间回拨解决方法

  1. 对workId配置默认值,比如在配置文件上使用配置
    1. spring.shardingsphere.sharding.tables.traffic.key-generator.props.worker.id=1
  • 使⽤MybatisPlus的配置,TrafficDO类配置
    @TableId(value = "id", type =IdType.ASSIGN_ID)
    默认实现类为DefaultIdentifierGenerator雪花算法
    
  1. 使⽤**Sharding-Jdbc**配置⽂件,注释DO类⾥⾯的id分配策略 (个人采用方案)
    #id⽣成策略
    key-generator:
    column: id
    props:
     worker:
       id: 0
    #id⽣成策略
    type: SNOWFLAKE
    
    优化版本:
  • 在启动时给每个服务分配不同的workId, 引⼊redis/zk都⾏,缺点就是多了依赖
  • 启动程序的时候,通过JVM参数去控制,覆盖变量 ```java @Configuration public class SnowFlakeWordIdConfig { /**
  • 动态指定sharding jdbc 的雪花算法中的属性work.id属 性* 通过调⽤System.setProperty()的⽅式实现,可⽤容器的 id 或者机器标识位
  • workId最⼤值 1L << 100,就是1024,即 0<= workId < 1024
  • {@link SnowflakeShardingKeyGenerator#getWorkerId()} / static { try {
      InetAddress ip4 = Inet4Address.getLocalHost();
      String addressIp = ip4.getHostAddress();
      System.setProperty("workerId",(Math.abs(addressIp.hashCode())%1024)+"");
      } catch (UnknownHostException e) {
          throw new BizException(BizCodeEnum.OPS_NETWORK_ADDRESS_ERROR);
      }
    
    } } ``` image.png
  • 配置

    #id⽣成策略
    key-generator:
    column: id
    props:
      worker:
        id: ${workerId}
    #id⽣成策略
    type: SNOWFLAKE
    

    shardingjdbc-Snowflake⾥⾯解决时间回拨问题

    image.png

  • 利⽤Sharding-Jdbc封装id⽣成器

    /**
    * @author fanwei
    * @version 1.0.0
    * @ClassName IDUtil.java
    * @Description 雪花主键生成器
    * @createTime 2022年03月18日 17:17:00
    */
    public class IDUtil {
    
      private static SnowflakeShardingKeyGenerator snowflakeShardingKeyGenerator = new SnowflakeShardingKeyGenerator();
    
      public static Comparable<?> geneSnowFlakeID(){
          return snowflakeShardingKeyGenerator.generateKey();
      }
    }
    


N.视屏教程

点击查看【bilibili】

假如视频没有了,我也有保存到本地上

截取资料

  1. Twitter Snowflake 算法
  2. 从一次 Snowflake 异常说起
  3. 多时钟解决雪花算法的时间回拨问题