spring.shardingsphere.sharding.tables.t_order.key-generator.props.worker.id=0000
序列号位(12bit)
同一毫秒内生成不同的ID。
时钟回拨
了解了雪花算法的主键 ID 组成后不难发现,这是一种严重依赖于服务器时间的算法,而依赖服务器时间的就会遇到一个棘手的问题:时钟回拨
。
为什么会出现时钟回拨呢?
互联网中有一种网络时间协议 ntp
全称 (Network Time Protocol
) ,专门用来同步、校准网络中各个计算机的时间。
这就是为什么,我们的手机现在不用手动校对时间,可每个人的手机时间还都是一样的。
我们的硬件时钟可能会因为各种原因变得不准( 快了
或 慢了
),此时就需要 ntp
服务来做时间校准,做校准的时候就会发生服务器时钟的 跳跃
或者 回拨
的问题。
雪花算法如何解决时钟回拨
服务器时钟回拨会导致产生重复的 ID,SNOWFLAKE
方案中对原有雪花算法做了改进,增加了一个最大容忍的时钟回拨毫秒数。
如果时钟回拨的时间超过最大容忍的毫秒数阈值,则程序直接报错;如果在可容忍的范围内,默认分布式主键生成器,会等待时钟同步到最后一次主键生成的时间后再继续工作。
最大容忍的时钟回拨毫秒数,默认值为 0,可通过属性 max.tolerate.time.difference.milliseconds
设置。
最大容忍的时钟回拨毫秒数
spring.shardingsphere.sharding.tables.t_order.key-generator.max.tolerate.time.difference.milliseconds=5
下面是看下它的源码实现类 SnowflakeShardingKeyGenerator
,核心流程大概如下:
最后一次生成主键的时间 lastMilliseconds
与 当前时间currentMilliseconds
做比较,如果 lastMilliseconds
> currentMilliseconds
则意味着时钟回调了。
那么接着判断两个时间的差值(timeDifferenceMilliseconds
)是否在设置的最大容忍时间阈值 max.tolerate.time.difference.milliseconds
内,在阈值内则线程休眠差值时间 Thread.sleep(timeDifferenceMilliseconds)
,否则大于差值直接报异常。
/**
- @author xiaofu
*/
public final class SnowflakeShardingKeyGenerator implements ShardingKeyGenerator{
@Getter
@Setter
private Properties properties = new Properties();
public String getType() {
return “SNOWFLAKE”;
}
public synchronized Comparable<?> generateKey() {
/**
- 当前系统时间毫秒数
/
long currentMilliseconds = timeService.getCurrentMillis();
/* - 判断是否需要等待容忍时间差,如果需要,则等待时间差过去,然后再获取当前系统时间
/
if (waitTolerateTimeDifferenceIfNeed(currentMilliseconds)) {
currentMilliseconds = timeService.get