a.twitter的雪花算法的计算由来
雪花算法是由 Twitter 公司开源的可在分布式系统中产生一个全局唯一 ID 的算法。最初 Twitter 把存储系统从 MySQL 迁移到 Cassandra,因为 Cassandra 没有顺序ID生成机制,所以开发了这样一套全局唯一ID生成服务。
「雪花算法」采用64bit作为id生成类型,并且将64bit划分为,如下图的几段
- 第一个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 重复
雪花算法的时间回拨问题
时间回拨问题是指系统在运行过程中,可能由于网络时间校准或者人工设置,导致系统时间主动或被动地跳回到过去的某个时间:
由于雪花算法重度依赖机器的当前时间,所以一旦发生时间回拨,将有可能导致生成的 ID 可能与此前已经生成的某个 ID 重复(前提是刚好在同一毫秒生成 ID 时序列号也刚好一致),这就是雪花算法最经常讨论的问题——时间回拨。
时间回拨解决方法
- 对workId配置默认值,比如在配置文件上使用配置
spring.shardingsphere.sharding.tables.traffic.key-generator.props.worker.id=1
- 使⽤MybatisPlus的配置,TrafficDO类配置
@TableId(value = "id", type =IdType.ASSIGN_ID) 默认实现类为DefaultIdentifierGenerator雪花算法
- 使⽤
**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); }
配置
#id⽣成策略 key-generator: column: id props: worker: id: ${workerId} #id⽣成策略 type: SNOWFLAKEshardingjdbc-Snowflake⾥⾯解决时间回拨问题
利⽤
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.视屏教程
假如视频没有了,我也有保存到本地上
