@@ -20,57 +20,7 @@ var newId = IdHelper.NextId(); | |||||
``` | ``` | ||||
如果基于DI框架集成,可以参考 IdHelper 去管理 IdGenerator 对象,必须使用**单例**模式。 | 如果基于DI框架集成,可以参考 IdHelper 去管理 IdGenerator 对象,必须使用**单例**模式。 | ||||
## options说明 | |||||
``` | |||||
public class IdGeneratorOptions | |||||
{ | |||||
/// <summary> | |||||
/// 雪花计算方法 | |||||
/// (1|2) | |||||
/// </summary> | |||||
public short Method { get; set; } = 1; | |||||
/// <summary> | |||||
/// 开始时间(UTC格式) | |||||
/// 不能超过当前系统时间 | |||||
/// </summary> | |||||
public DateTime StartTime { get; set; } = DateTime.MinValue; | |||||
/// <summary> | |||||
/// 机器码 | |||||
/// 与 WorkerIdBitLength 有关系 | |||||
/// </summary> | |||||
public ushort WorkerId { get; set; } = 0; | |||||
/// <summary> | |||||
/// 机器码位长 | |||||
/// 范围:2-21(要求:序列数位长+机器码位长不超过22)。 | |||||
/// 建议范围:6-12。 | |||||
/// </summary> | |||||
public byte WorkerIdBitLength { get; set; } = 6; | |||||
/// <summary> | |||||
/// 序列数位长 | |||||
/// 范围:2-21(要求:序列数位长+机器码位长不超过22)。 | |||||
/// 建议范围:6-14。 | |||||
/// </summary> | |||||
public byte SeqBitLength { get; set; } = 6; | |||||
/// <summary> | |||||
/// 最大序列数(含) | |||||
/// (由SeqBitLength计算的最大值) | |||||
/// </summary> | |||||
public int MaxSeqNumber { get; set; } = 0; | |||||
## options 默认值及说明 | |||||
/// <summary> | |||||
/// 最小序列数(含) | |||||
/// 默认11,不小于5,不大于MaxSeqNumber-2 | |||||
/// </summary> | |||||
public ushort MinSeqNumber { get; set; } = 11; | |||||
参考源码:/Contract/IdGeneratorOptions.cs | |||||
/// <summary> | |||||
/// 最大漂移次数(含), | |||||
/// 默认2000,推荐范围500-10000(与计算能力有关) | |||||
/// </summary> | |||||
public int TopOverCostCount { get; set; } = 2000; | |||||
``` |
@@ -50,7 +50,7 @@ namespace Yitter.OrgSystem.TestA | |||||
//MinSeqNumber = 11, | //MinSeqNumber = 11, | ||||
//MaxSeqNumber = 200, | //MaxSeqNumber = 200, | ||||
StartTime = DateTime.Now.AddYears(-10), | |||||
BaseTime = DateTime.Now.AddYears(-10), | |||||
}; | }; | ||||
// ++++++++++++++++++++++++++++++++ | // ++++++++++++++++++++++++++++++++ | ||||
@@ -25,7 +25,7 @@ namespace Yitter.IdGenerator | |||||
/// 开始时间(UTC格式) | /// 开始时间(UTC格式) | ||||
/// 不能超过当前系统时间 | /// 不能超过当前系统时间 | ||||
/// </summary> | /// </summary> | ||||
public virtual DateTime StartTime { get; set; } = DateTime.MinValue; | |||||
public virtual DateTime BaseTime { get; set; } = new DateTime(2020, 2, 20, 2, 20, 2, 20, DateTimeKind.Utc); | |||||
/// <summary> | /// <summary> | ||||
/// 机器码 | /// 机器码 | ||||
@@ -21,7 +21,7 @@ namespace Yitter.IdGenerator | |||||
/// <summary> | /// <summary> | ||||
/// 基础时间 | /// 基础时间 | ||||
/// </summary> | /// </summary> | ||||
protected readonly DateTime StartTimeUtc = new DateTime(2020, 2, 20, 2, 20, 2, 20, DateTimeKind.Utc); | |||||
protected readonly DateTime BaseTime; | |||||
/// <summary> | /// <summary> | ||||
/// 机器码 | /// 机器码 | ||||
@@ -78,9 +78,9 @@ namespace Yitter.IdGenerator | |||||
MinSeqNumber = options.MinSeqNumber; | MinSeqNumber = options.MinSeqNumber; | ||||
TopOverCostCount = options.TopOverCostCount; | TopOverCostCount = options.TopOverCostCount; | ||||
if (options.StartTime != DateTime.MinValue) | |||||
if (options.BaseTime != DateTime.MinValue) | |||||
{ | { | ||||
StartTimeUtc = options.StartTime; | |||||
BaseTime = options.BaseTime; | |||||
} | } | ||||
if (WorkerId < 1) | if (WorkerId < 1) | ||||
@@ -278,7 +278,7 @@ namespace Yitter.IdGenerator | |||||
protected virtual long GetCurrentTimeTick() | protected virtual long GetCurrentTimeTick() | ||||
{ | { | ||||
return (long)(DateTime.UtcNow - StartTimeUtc).TotalMilliseconds; | |||||
return (long)(DateTime.UtcNow - BaseTime).TotalMilliseconds; | |||||
} | } | ||||
protected virtual long GetNextTimeTick() | protected virtual long GetNextTimeTick() | ||||
@@ -35,9 +35,9 @@ namespace Yitter.IdGenerator | |||||
throw new ApplicationException("options error."); | throw new ApplicationException("options error."); | ||||
} | } | ||||
if (options.StartTime > DateTime.Now) | |||||
if (options.BaseTime < DateTime.Now.AddYears(-50) || options.BaseTime > DateTime.Now) | |||||
{ | { | ||||
throw new ApplicationException("StartTime error."); | |||||
throw new ApplicationException("BaseTime error."); | |||||
} | } | ||||
if (options.SeqBitLength + options.WorkerIdBitLength > 22) | if (options.SeqBitLength + options.WorkerIdBitLength > 22) | ||||
@@ -18,7 +18,7 @@ | |||||
<Copyright>Yitter</Copyright> | <Copyright>Yitter</Copyright> | ||||
<PackageProjectUrl>https://gitee.com/yitter/idgenerator</PackageProjectUrl> | <PackageProjectUrl>https://gitee.com/yitter/idgenerator</PackageProjectUrl> | ||||
<PackageLicenseExpression>MIT</PackageLicenseExpression> | <PackageLicenseExpression>MIT</PackageLicenseExpression> | ||||
<Version>1.0.3</Version> | |||||
<Version>1.0.6</Version> | |||||
<PackageReleaseNotes></PackageReleaseNotes> | <PackageReleaseNotes></PackageReleaseNotes> | ||||
</PropertyGroup> | </PropertyGroup> | ||||
@@ -1,7 +1,7 @@ | |||||
## 运行环境 | ## 运行环境 | ||||
JDK 1.8 | |||||
JDK 1.8+ | |||||
## 引用 maven 包 | ## 引用 maven 包 | ||||
``` | ``` | ||||
@@ -21,56 +21,8 @@ long newId = IdHelper.nextId(); | |||||
``` | ``` | ||||
如果基于DI框架集成,可以参考 IdHelper 去管理 IdGenerator 对象,必须使用**单例**模式。 | 如果基于DI框架集成,可以参考 IdHelper 去管理 IdGenerator 对象,必须使用**单例**模式。 | ||||
## options说明 | |||||
``` | |||||
/** | |||||
* 雪花计算方法 | |||||
* (1-漂移算法|2-传统算法),默认1 | |||||
*/ | |||||
public short Method = 1; | |||||
/** | |||||
* 开始时间 | |||||
* 不能超过当前系统时间 | |||||
*/ | |||||
public long StartTime = 0; | |||||
/** | |||||
* 机器码,必须由外部系统设置 | |||||
* 与 WorkerIdBitLength 有关系 | |||||
*/ | |||||
public short WorkerId = 0; | |||||
/** | |||||
* 机器码位长 | |||||
* 范围:2-21(要求:序列数位长+机器码位长不超过22)。 | |||||
* 建议范围:6-12。 | |||||
*/ | |||||
public byte WorkerIdBitLength = 6; | |||||
/** | |||||
* 序列数位长 | |||||
* 范围:2-21(要求:序列数位长+机器码位长不超过22)。 | |||||
* 建议范围:6-14。 | |||||
*/ | |||||
public byte SeqBitLength = 6; | |||||
/** | |||||
* 最大序列数(含) | |||||
* (由SeqBitLength计算的最大值) | |||||
*/ | |||||
public short MaxSeqNumber = 0; | |||||
/** | |||||
* 最小序列数(含) | |||||
* 默认11,不小于5,不大于MaxSeqNumber-2 | |||||
*/ | |||||
public short MinSeqNumber = 11; | |||||
## options 默认值及说明 | |||||
/** | |||||
* 最大漂移次数(含) | |||||
* 默认2000,推荐范围500-10000(与计算能力有关) | |||||
*/ | |||||
public short TopOverCostCount = 2000; | |||||
参考源码:/contract/IdGeneratorOptions.java | |||||
``` |
@@ -20,7 +20,7 @@ public class IdGeneratorOptions { | |||||
* 开始时间 | * 开始时间 | ||||
* 不能超过当前系统时间 | * 不能超过当前系统时间 | ||||
*/ | */ | ||||
public long StartTime = 0; | |||||
public long BaseTime = 1582136402000L; | |||||
/** | /** | ||||
* 机器码,必须由外部系统设置 | * 机器码,必须由外部系统设置 | ||||
@@ -14,7 +14,7 @@ public class SnowWorkerM1 implements ISnowWorker { | |||||
/** | /** | ||||
* 基础时间 | * 基础时间 | ||||
*/ | */ | ||||
protected final long StartTimeUtc; | |||||
protected final long BaseTime; | |||||
/** | /** | ||||
* 机器码 | * 机器码 | ||||
@@ -67,7 +67,7 @@ public class SnowWorkerM1 implements ISnowWorker { | |||||
MaxSeqNumber = options.MaxSeqNumber > 0 ? options.MaxSeqNumber : (int) Math.pow(2, SeqBitLength); | MaxSeqNumber = options.MaxSeqNumber > 0 ? options.MaxSeqNumber : (int) Math.pow(2, SeqBitLength); | ||||
MinSeqNumber = options.MinSeqNumber; | MinSeqNumber = options.MinSeqNumber; | ||||
TopOverCostCount = options.TopOverCostCount; | TopOverCostCount = options.TopOverCostCount; | ||||
StartTimeUtc = options.StartTime != 0 ? options.StartTime : 1582136402000L; | |||||
BaseTime = options.BaseTime != 0 ? options.BaseTime : 1582136402000L; | |||||
_TimestampShift = (byte) (WorkerIdBitLength + SeqBitLength); | _TimestampShift = (byte) (WorkerIdBitLength + SeqBitLength); | ||||
_CurrentSeqNumber = options.MinSeqNumber; | _CurrentSeqNumber = options.MinSeqNumber; | ||||
} | } | ||||
@@ -224,7 +224,7 @@ public class SnowWorkerM1 implements ISnowWorker { | |||||
protected long GetCurrentTimeTick() { | protected long GetCurrentTimeTick() { | ||||
long millis = System.currentTimeMillis(); | long millis = System.currentTimeMillis(); | ||||
return millis - StartTimeUtc; | |||||
return millis - BaseTime; | |||||
} | } | ||||
protected long GetNextTimeTick() { | protected long GetNextTimeTick() { | ||||
@@ -17,46 +17,38 @@ public class DefaultIdGenerator implements IIdGenerator { | |||||
private final ISnowWorker _SnowWorker; | private final ISnowWorker _SnowWorker; | ||||
public DefaultIdGenerator(IdGeneratorOptions options) throws IdGeneratorException { | public DefaultIdGenerator(IdGeneratorOptions options) throws IdGeneratorException { | ||||
if (options == null) | |||||
{ | |||||
if (options == null) { | |||||
throw new IdGeneratorException("options error."); | throw new IdGeneratorException("options error."); | ||||
} | } | ||||
if (options.StartTime > System.currentTimeMillis()) | |||||
{ | |||||
throw new IdGeneratorException("StartTime error."); | |||||
if (options.BaseTime < 315504000000L || options.BaseTime > System.currentTimeMillis()) { | |||||
throw new IdGeneratorException("BaseTime error."); | |||||
} | } | ||||
if (options.SeqBitLength + options.WorkerIdBitLength > 22) | |||||
{ | |||||
if (options.SeqBitLength + options.WorkerIdBitLength > 22) { | |||||
throw new IdGeneratorException("error:WorkerIdBitLength + SeqBitLength <= 22"); | throw new IdGeneratorException("error:WorkerIdBitLength + SeqBitLength <= 22"); | ||||
} | } | ||||
double maxWorkerIdNumber = Math.pow(2, options.WorkerIdBitLength) - 1; | double maxWorkerIdNumber = Math.pow(2, options.WorkerIdBitLength) - 1; | ||||
if (options.WorkerId < 1 || options.WorkerId > maxWorkerIdNumber) | |||||
{ | |||||
if (options.WorkerId < 1 || options.WorkerId > maxWorkerIdNumber) { | |||||
throw new IdGeneratorException("WorkerId error. (range:[1, " + maxWorkerIdNumber + "]"); | throw new IdGeneratorException("WorkerId error. (range:[1, " + maxWorkerIdNumber + "]"); | ||||
} | } | ||||
if (options.SeqBitLength < 2 || options.SeqBitLength > 21) | |||||
{ | |||||
if (options.SeqBitLength < 2 || options.SeqBitLength > 21) { | |||||
throw new IdGeneratorException("SeqBitLength error. (range:[2, 21])"); | throw new IdGeneratorException("SeqBitLength error. (range:[2, 21])"); | ||||
} | } | ||||
double maxSeqNumber = Math.pow(2, options.SeqBitLength) - 1; | double maxSeqNumber = Math.pow(2, options.SeqBitLength) - 1; | ||||
if (options.MaxSeqNumber < 0 || options.MaxSeqNumber > maxSeqNumber) | |||||
{ | |||||
if (options.MaxSeqNumber < 0 || options.MaxSeqNumber > maxSeqNumber) { | |||||
throw new IdGeneratorException("MaxSeqNumber error. (range:[1, " + maxSeqNumber + "]"); | throw new IdGeneratorException("MaxSeqNumber error. (range:[1, " + maxSeqNumber + "]"); | ||||
} | } | ||||
double maxValue = maxSeqNumber - 2; | double maxValue = maxSeqNumber - 2; | ||||
if (options.MinSeqNumber < 5 || options.MinSeqNumber > maxValue) | |||||
{ | |||||
if (options.MinSeqNumber < 5 || options.MinSeqNumber > maxValue) { | |||||
throw new IdGeneratorException("MinSeqNumber error. (range:[5, " + maxValue + "]"); | throw new IdGeneratorException("MinSeqNumber error. (range:[5, " + maxValue + "]"); | ||||
} | } | ||||
switch (options.Method) | |||||
{ | |||||
switch (options.Method) { | |||||
case 1: | case 1: | ||||
_SnowWorker = new SnowWorkerM1(options); | _SnowWorker = new SnowWorkerM1(options); | ||||
break; | break; | ||||
@@ -68,8 +60,7 @@ public class DefaultIdGenerator implements IIdGenerator { | |||||
break; | break; | ||||
} | } | ||||
if (options.Method == 1) | |||||
{ | |||||
if (options.Method == 1) { | |||||
try { | try { | ||||
Thread.sleep(500); | Thread.sleep(500); | ||||
} catch (InterruptedException e) { | } catch (InterruptedException e) { | ||||
@@ -79,7 +70,7 @@ public class DefaultIdGenerator implements IIdGenerator { | |||||
} | } | ||||
@Override | @Override | ||||
public long newLong() { | |||||
public long newLong() { | |||||
return _SnowWorker.nextId(); | return _SnowWorker.nextId(); | ||||
} | } | ||||
} | } |
@@ -1,12 +1,15 @@ | |||||
package com.yitter.test; | package com.yitter.test; | ||||
import com.yitter.contract.IIdGenerator; | import com.yitter.contract.IIdGenerator; | ||||
import java.util.HashSet; | |||||
import java.util.Set; | |||||
public class GenTest { | public class GenTest { | ||||
private IIdGenerator IdGen; | private IIdGenerator IdGen; | ||||
private int GenIdCount; | private int GenIdCount; | ||||
private int WorkerId; | private int WorkerId; | ||||
private Set IdSet = new HashSet(); | |||||
public GenTest(IIdGenerator idGen, int genIdCount, int workerId) { | public GenTest(IIdGenerator idGen, int genIdCount, int workerId) { | ||||
GenIdCount = genIdCount; | GenIdCount = genIdCount; | ||||
@@ -19,6 +22,7 @@ public class GenTest { | |||||
for (int i = 0; i < GenIdCount; i++) { | for (int i = 0; i < GenIdCount; i++) { | ||||
long id = IdGen.newLong(); | long id = IdGen.newLong(); | ||||
// IdSet.add(id); | |||||
} | } | ||||
long end = System.currentTimeMillis(); | long end = System.currentTimeMillis(); | ||||
@@ -31,7 +31,7 @@ public class StartUp { | |||||
// options.MaxSeqNumber = 200; | // options.MaxSeqNumber = 200; | ||||
options.Method = method; | options.Method = method; | ||||
options.StartTime = 1582206693000L; // (2020-2-20) | |||||
options.BaseTime = 1582206693000L; | |||||
options.WorkerId = 1; | options.WorkerId = 1; | ||||
IIdGenerator IdGen = new DefaultIdGenerator(options); | IIdGenerator IdGen = new DefaultIdGenerator(options); | ||||
@@ -1,8 +1,9 @@ | |||||
# IdGenerator | # IdGenerator | ||||
## 介绍 | ## 介绍 | ||||
用一种全新的雪花漂移算法,让ID更短、生成速度更快。 | |||||
核心在于缩短ID长度的同时,还能拥有极高瞬时并发处理量(50W/0.1s),及强大的配置能力。 | |||||
用一种全新的雪花漂移算法,让ID更短、生成速度更快。 | |||||
核心在于缩短ID长度的同时,还能拥有极高瞬时并发处理量(50W/0.1s)。 | |||||
顶尖优化,超强效能(位数更短,速度更快),全新 SnowFlake 算法,支持 C#/Java/Go/PHP 等语言。 | |||||
## 需求来源 | ## 需求来源 | ||||
@@ -138,7 +139,7 @@ | |||||
配置变更指是系统运行一段时间后,再变更运行参数(IdGeneratorOptions选项值),请注意: | 配置变更指是系统运行一段时间后,再变更运行参数(IdGeneratorOptions选项值),请注意: | ||||
1.最重要的一条原则是:StartTime **只能往前**(比老值更小、距离现在更远)赋值,原因是往后赋值极大可能产生相同的时间戳。[**不推荐**在系统运行之后调整 StartTime] | |||||
1.最重要的一条原则是:BaseTime **只能往前**(比老值更小、距离现在更远)赋值,原因是往后赋值极大可能产生相同的时间戳。[**不推荐**在系统运行之后调整 BaseTime] | |||||
2.任何时候增加 WorkerIdBitLength 或 SeqBitLength,都是可以的,但是慎用 “减小”的操作,因为这可能导致在未来某天生成的 ID 与过去老配置时相同。[允许在系统运行之后**增加**任何一个 BitLength 值] | 2.任何时候增加 WorkerIdBitLength 或 SeqBitLength,都是可以的,但是慎用 “减小”的操作,因为这可能导致在未来某天生成的 ID 与过去老配置时相同。[允许在系统运行之后**增加**任何一个 BitLength 值] | ||||