| @@ -11,7 +11,7 @@ namespace Yitter.OrgSystem.TestA | |||||
| class Program | class Program | ||||
| { | { | ||||
| // 测试参数(默认配置下,最佳性能是10W/s) | // 测试参数(默认配置下,最佳性能是10W/s) | ||||
| static int genIdCount = 50000; // 计算ID数量(如果要验证50W效率,请将TopOverCostCount设置为20000或适当增加SeqBitLength) | |||||
| static int genIdCount = 2;//50000; // 计算ID数量(如果要验证50W效率,请将TopOverCostCount设置为20000或适当增加SeqBitLength) | |||||
| static short method = 1; // 1-漂移算法,2-传统算法 | static short method = 1; // 1-漂移算法,2-传统算法 | ||||
| @@ -35,9 +35,12 @@ namespace Yitter.OrgSystem.TestA | |||||
| WorkerIdBitLength = 6, | WorkerIdBitLength = 6, | ||||
| SeqBitLength = 6, | SeqBitLength = 6, | ||||
| DataCenterIdBitLength = 10, | |||||
| TopOverCostCount = 2000, | TopOverCostCount = 2000, | ||||
| //MinSeqNumber = 1, | |||||
| //TimestampType = 1, | |||||
| // MinSeqNumber = 1, | |||||
| // MaxSeqNumber = 200, | // MaxSeqNumber = 200, | ||||
| // BaseTime = DateTime.Now.AddYears(-10), | // BaseTime = DateTime.Now.AddYears(-10), | ||||
| @@ -128,6 +131,7 @@ namespace Yitter.OrgSystem.TestA | |||||
| MinSeqNumber = options.MinSeqNumber, | MinSeqNumber = options.MinSeqNumber, | ||||
| MaxSeqNumber = options.MaxSeqNumber, | MaxSeqNumber = options.MaxSeqNumber, | ||||
| Method = options.Method, | Method = options.Method, | ||||
| //TimestampType = 1, | |||||
| }; | }; | ||||
| Console.WriteLine("Gen:" + i); | Console.WriteLine("Gen:" + i); | ||||
| @@ -64,6 +64,22 @@ namespace Yitter.IdGenerator | |||||
| public virtual int TopOverCostCount { get; set; } = 2000; | public virtual int TopOverCostCount { get; set; } = 2000; | ||||
| /// <summary> | |||||
| /// 数据中心ID(默认0) | |||||
| /// </summary> | |||||
| public virtual uint DataCenterId { get; set; } = 0; | |||||
| /// <summary> | |||||
| /// 数据中心ID长度(默认0) | |||||
| /// </summary> | |||||
| public virtual byte DataCenterIdBitLength { get; set; } = 0; | |||||
| /// <summary> | |||||
| /// 时间戳类型(0-毫秒,1-秒),默认0 | |||||
| /// </summary> | |||||
| public virtual byte TimestampType { get; set; } = 0; | |||||
| public IdGeneratorOptions() | public IdGeneratorOptions() | ||||
| { | { | ||||
| @@ -51,9 +51,9 @@ namespace Yitter.IdGenerator | |||||
| /// <summary> | /// <summary> | ||||
| /// 最大漂移次数(含) | /// 最大漂移次数(含) | ||||
| /// </summary> | /// </summary> | ||||
| protected readonly int TopOverCostCount = 0; | |||||
| protected int TopOverCostCount = 0; | |||||
| protected readonly byte _TimestampShift = 0; | |||||
| protected byte _TimestampShift = 0; | |||||
| protected static object _SyncLock = new object(); | protected static object _SyncLock = new object(); | ||||
| protected ushort _CurrentSeqNumber; | protected ushort _CurrentSeqNumber; | ||||
| @@ -215,7 +215,7 @@ namespace Yitter.IdGenerator | |||||
| _TurnBackIndex)); | _TurnBackIndex)); | ||||
| } | } | ||||
| private long NextOverCostId() | |||||
| protected virtual long NextOverCostId() | |||||
| { | { | ||||
| long currentTimeTick = GetCurrentTimeTick(); | long currentTimeTick = GetCurrentTimeTick(); | ||||
| @@ -262,7 +262,7 @@ namespace Yitter.IdGenerator | |||||
| return CalcId(_LastTimeTick); | return CalcId(_LastTimeTick); | ||||
| } | } | ||||
| private long NextNormalId() | |||||
| protected virtual long NextNormalId() | |||||
| { | { | ||||
| long currentTimeTick = GetCurrentTimeTick(); | long currentTimeTick = GetCurrentTimeTick(); | ||||
| @@ -319,7 +319,7 @@ namespace Yitter.IdGenerator | |||||
| return CalcId(_LastTimeTick); | return CalcId(_LastTimeTick); | ||||
| } | } | ||||
| private long CalcId(in long useTimeTick) | |||||
| protected virtual long CalcId(in long useTimeTick) | |||||
| { | { | ||||
| var result = ((useTimeTick << _TimestampShift) + | var result = ((useTimeTick << _TimestampShift) + | ||||
| ((long)WorkerId << SeqBitLength) + | ((long)WorkerId << SeqBitLength) + | ||||
| @@ -329,7 +329,7 @@ namespace Yitter.IdGenerator | |||||
| return result; | return result; | ||||
| } | } | ||||
| private long CalcTurnBackId(in long useTimeTick) | |||||
| protected virtual long CalcTurnBackId(in long useTimeTick) | |||||
| { | { | ||||
| var result = ((useTimeTick << _TimestampShift) + | var result = ((useTimeTick << _TimestampShift) + | ||||
| ((long)WorkerId << SeqBitLength) + _TurnBackIndex); | ((long)WorkerId << SeqBitLength) + _TurnBackIndex); | ||||
| @@ -0,0 +1,83 @@ | |||||
| /* | |||||
| * 版权属于:yitter(yitter@126.com) | |||||
| * 开源地址:https://github.com/yitter/idgenerator | |||||
| * 版权协议:MIT | |||||
| * 版权说明:只要保留本版权,你可以免费使用、修改、分发本代码。 | |||||
| * 免责条款:任何因为本代码产生的系统、法律、政治、宗教问题,均与版权所有者无关。 | |||||
| * | |||||
| */ | |||||
| using System; | |||||
| using System.Threading; | |||||
| using System.Threading.Tasks; | |||||
| namespace Yitter.IdGenerator | |||||
| { | |||||
| /// <summary> | |||||
| /// 雪花漂移算法(支持数据中心ID和秒级时间戳) | |||||
| /// </summary> | |||||
| internal class SnowWorkerM3 : SnowWorkerM1 | |||||
| { | |||||
| /// <summary> | |||||
| /// 数据中心ID(默认0) | |||||
| /// </summary> | |||||
| protected readonly uint DataCenterId = 0; | |||||
| /// <summary> | |||||
| /// 数据中心ID长度(默认0) | |||||
| /// </summary> | |||||
| protected readonly byte DataCenterIdBitLength = 0; | |||||
| /// <summary> | |||||
| /// 时间戳类型(0-毫秒,1-秒),默认0 | |||||
| /// </summary> | |||||
| protected readonly byte TimestampType = 0; | |||||
| public SnowWorkerM3(IdGeneratorOptions options) : base(options) | |||||
| { | |||||
| // 秒级时间戳类型 | |||||
| TimestampType = options.TimestampType; | |||||
| // DataCenter相关 | |||||
| DataCenterId = options.DataCenterId; | |||||
| DataCenterIdBitLength = options.DataCenterIdBitLength; | |||||
| if (TimestampType == 1) | |||||
| { | |||||
| TopOverCostCount = 0; | |||||
| } | |||||
| _TimestampShift = (byte)(DataCenterIdBitLength + WorkerIdBitLength + SeqBitLength); | |||||
| } | |||||
| protected override long CalcId(in long useTimeTick) | |||||
| { | |||||
| var result = ((useTimeTick << _TimestampShift) + | |||||
| ((long)DataCenterId << DataCenterIdBitLength) + | |||||
| ((long)WorkerId << SeqBitLength) + | |||||
| (long)_CurrentSeqNumber); | |||||
| _CurrentSeqNumber++; | |||||
| return result; | |||||
| } | |||||
| protected override long CalcTurnBackId(in long useTimeTick) | |||||
| { | |||||
| var result = ((useTimeTick << _TimestampShift) + | |||||
| ((long)DataCenterId << DataCenterIdBitLength) + | |||||
| ((long)WorkerId << SeqBitLength) + | |||||
| _TurnBackIndex); | |||||
| _TurnBackTimeTick--; | |||||
| return result; | |||||
| } | |||||
| protected override long GetCurrentTimeTick() | |||||
| { | |||||
| return TimestampType == 0 ? | |||||
| (long)(DateTime.UtcNow - BaseTime).TotalMilliseconds : | |||||
| (long)(DateTime.UtcNow - BaseTime).TotalSeconds; | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -46,12 +46,12 @@ namespace Yitter.IdGenerator | |||||
| { | { | ||||
| throw new ApplicationException("WorkerIdBitLength error.(range:[1, 21])"); | throw new ApplicationException("WorkerIdBitLength error.(range:[1, 21])"); | ||||
| } | } | ||||
| if (options.SeqBitLength + options.WorkerIdBitLength > 22) | |||||
| if (options.DataCenterIdBitLength + options.WorkerIdBitLength + options.SeqBitLength > 22) | |||||
| { | { | ||||
| throw new ApplicationException("error:WorkerIdBitLength + SeqBitLength <= 22"); | |||||
| throw new ApplicationException("error:DataCenterIdBitLength + WorkerIdBitLength + SeqBitLength <= 22"); | |||||
| } | } | ||||
| // 3.WorkerId | |||||
| // 3.WorkerId & DataCenterId | |||||
| var maxWorkerIdNumber = (1 << options.WorkerIdBitLength) - 1; | var maxWorkerIdNumber = (1 << options.WorkerIdBitLength) - 1; | ||||
| if (maxWorkerIdNumber == 0) | if (maxWorkerIdNumber == 0) | ||||
| { | { | ||||
| @@ -62,6 +62,12 @@ namespace Yitter.IdGenerator | |||||
| throw new ApplicationException("WorkerId error. (range:[0, " + maxWorkerIdNumber + "]"); | throw new ApplicationException("WorkerId error. (range:[0, " + maxWorkerIdNumber + "]"); | ||||
| } | } | ||||
| var maxDataCenterIdNumber = (1 << options.DataCenterIdBitLength) - 1; | |||||
| if (options.DataCenterId < 0 || options.DataCenterId > maxDataCenterIdNumber) | |||||
| { | |||||
| throw new ApplicationException("DataCenterId error. (range:[0, " + maxDataCenterIdNumber + "]"); | |||||
| } | |||||
| // 4.SeqBitLength | // 4.SeqBitLength | ||||
| if (options.SeqBitLength < 2 || options.SeqBitLength > 21) | if (options.SeqBitLength < 2 || options.SeqBitLength > 21) | ||||
| { | { | ||||
| @@ -87,18 +93,22 @@ namespace Yitter.IdGenerator | |||||
| switch (options.Method) | switch (options.Method) | ||||
| { | { | ||||
| case 1: | |||||
| _SnowWorker = new SnowWorkerM1(options); | |||||
| break; | |||||
| case 2: | case 2: | ||||
| _SnowWorker = new SnowWorkerM2(options); | _SnowWorker = new SnowWorkerM2(options); | ||||
| break; | break; | ||||
| default: | default: | ||||
| _SnowWorker = new SnowWorkerM1(options); | |||||
| if (options.DataCenterIdBitLength == 0 && options.TimestampType == 0) | |||||
| { | |||||
| _SnowWorker = new SnowWorkerM1(options); | |||||
| } | |||||
| else | |||||
| { | |||||
| _SnowWorker = new SnowWorkerM3(options); | |||||
| } | |||||
| break; | break; | ||||
| } | } | ||||
| if (options.Method == 1) | |||||
| if (options.Method != 2) | |||||
| { | { | ||||
| Thread.Sleep(500); | Thread.Sleep(500); | ||||
| } | } | ||||
| @@ -146,7 +146,7 @@ QQ群:646049993 | |||||
| ❄ ***WorkerIdBitLength***,机器码位长,决定 WorkerId 的最大值,**默认值6**,取值范围 [1, 19],实际上有些语言采用 无符号 ushort (uint16) 类型接收该参数,所以最大值是16,如果是采用 有符号 short (int16),则最大值为15。 | ❄ ***WorkerIdBitLength***,机器码位长,决定 WorkerId 的最大值,**默认值6**,取值范围 [1, 19],实际上有些语言采用 无符号 ushort (uint16) 类型接收该参数,所以最大值是16,如果是采用 有符号 short (int16),则最大值为15。 | ||||
| ❄ **WorkerId**,机器码,**最重要参数**,无默认值,必须 **全局唯一**,必须 **程序设定**,缺省条件(WorkerIdBitLength取默认值)时最大值63,理论最大值 2^WorkerIdBitLength-1(不同实现语言可能会限定在 65535 或 32767,原理同 WorkerIdBitLength 规则)。不同机器或不同应用实例 **不能相同**,你可通过应用程序配置该值,也可通过调用外部服务获取值。针对自动注册WorkerId需求,本算法提供默认实现:通过 redis 自动注册 WorkerId 的动态库,详见“Tools\AutoRegisterWorkerId”。 | |||||
| ❄ **WorkerId**,机器码,**最重要参数**,无默认值,必须 **全局唯一**(或相同 DataCenterId 内唯一),必须 **程序设定**,缺省条件(WorkerIdBitLength取默认值)时最大值63,理论最大值 2^WorkerIdBitLength-1(不同实现语言可能会限定在 65535 或 32767,原理同 WorkerIdBitLength 规则)。不同机器或不同应用实例 **不能相同**,你可通过应用程序配置该值,也可通过调用外部服务获取值。针对自动注册WorkerId需求,本算法提供默认实现:通过 redis 自动注册 WorkerId 的动态库,详见“Tools\AutoRegisterWorkerId”。 | |||||
| **特别提示**:如果一台服务器部署多个独立服务,需要为每个服务指定不同的 WorkerId。 | **特别提示**:如果一台服务器部署多个独立服务,需要为每个服务指定不同的 WorkerId。 | ||||
| @@ -158,6 +158,14 @@ QQ群:646049993 | |||||
| ❄ ***BaseTime***,基础时间(也称:基点时间、原点时间、纪元时间),有默认值(2020年),是毫秒时间戳(是整数,.NET是DatetTime类型),作用是:用生成ID时的系统时间与基础时间的差值(毫秒数)作为生成ID的时间戳。基础时间一般无需设置,如果觉得默认值太老,你可以重新设置,不过要注意,这个值以后最好不变。 | ❄ ***BaseTime***,基础时间(也称:基点时间、原点时间、纪元时间),有默认值(2020年),是毫秒时间戳(是整数,.NET是DatetTime类型),作用是:用生成ID时的系统时间与基础时间的差值(毫秒数)作为生成ID的时间戳。基础时间一般无需设置,如果觉得默认值太老,你可以重新设置,不过要注意,这个值以后最好不变。 | ||||
| 第二版增加参数(非必须): | |||||
| ❄ ***DataCenterId***,数据中心ID(默认0),请确保全局唯一。 | |||||
| ❄ ***DataCenterIdBitLength***,数据中心ID长度(默认0)。 | |||||
| ❄ ***TimestampType***,时间戳类型(0-毫秒,1-秒),默认0。 | |||||
| #### 常规集成 | #### 常规集成 | ||||