雪花算法(DELPHI实现)
生成ID能够按照时间有序生成。
分布式系统内不会产生重复id(用workerId来做区分)。
自增ID:对于数据敏感场景不宜使用,且不适合于分布式场景。
GUID:采用无意义字符串,数据量增大时造成访问过慢,且不宜排序。
算法描述:
- 最高位是符号位,始终为0,不可用。
- 41位的时间序列,精确到毫秒级,41位的长度可以使用69年。时间位还有一个很重要的作用是可以根据时间进行排序。
- 10位的机器标识,10位的长度最多支持部署1024个节点。
- 12位的计数序列号,序列号即一系列的自增id,可以支持同一节点同一毫秒生成多个ID序号,12位的计数序列号支持每个节点每毫秒产生4096个ID序号。
在delphi7下面,测试通过。
下面的算法,适用于单机构生成不重复ID。
unit Snowflake; interface uses SysUtils, SyncObjs, DateUtils; type TSnowflake = class private FMachineID: integer; //机器号 FLocker: TCriticalSection; fTime: Int64; //时间戳 fsn: int64; //序列 public constructor Create; destructor Destroy; override; property MachineID: Integer read FMachineID write FMachineID; function Generate: Int64; end; implementation const Epoch: int64 = 1539615188000; //北京时间2018-10-15号 MachineBits: Byte = 10; //机器号10位 0..1023 snBits: Byte = 12; //序列号12位 timeShift: Byte = 22; //时间戳左移位数=序列号12位+机器号10位 machineShift: Byte = 12; //工作站左移位数 snMask: Word = 4095; //12位的计数序列号支持每个节点每毫秒产生4096个ID序号 { TSnowflake } constructor TSnowflake.Create; begin FLocker := TCriticalSection.Create; end; destructor TSnowflake.Destroy; begin FLocker.Free; inherited; end; function TSnowflake.Generate: Int64; var curtime: Int64; begin FLocker.Acquire; try curtime := DateTimeToUnix(Now) * 1000; if curtime = fTime then begin fsn := (fsn + 1) and snMask; if fsn = 0 then begin while curtime <= fTime do curtime := DateTimeToUnix(Now) * 1000; end; end else fsn := 0; fTime := curtime; Result := (curtime - Epoch) shl timeShift or FMachineID shl machineShift or fsn; finally FLocker.Release; end; end; initialization end.
下面的算法,适用于连锁机构生成分布式ID:
unit Snowflake; { 调用演示 procedure TForm1.Button1Click(Sender: TObject); var s: TSnowflake; i: Integer; begin s := TSnowflake.Create; s.OrgID := 8; s.MachineID :=10; for i:=1 to 30 do begin Memo1.Lines.Add(IntToStr(s.Generate)); end; s.Free; end; } interface uses SysUtils, SyncObjs, DateUtils; type TSnowflake = class private FOrgID: Integer; //机构号 FMachineID: integer; //机器号 FLocker: TCriticalSection; fTime: Int64; //时间戳 fsn: int64; //序列 public constructor Create; destructor Destroy; override; property MachineID: Integer read FMachineID write FMachineID; property OrgID: Integer read FOrgID write FOrgID; function Generate: Int64; end; implementation const Epoch: int64 = 1539615188000; //北京时间2018-10-15号 curtime := DateTimeToUnix(Now) * 1000; OrgBits: Byte = 5; //机构号 0..31 MachineBits: Byte = 5; //机器号 0..31 snBits: Byte = 12; //序列号12位 timeShift: Byte = 22; //时间戳左移位数=序列号位数+机器号位数+机构号位数 orgShift: Byte = 17; //机构号左移位数=序列号位数+机器号位数 machineShift: Byte = 12; //工作站左移位数=序列号位数 snMask: Word = 4095; //12位的计数序列号支持每个节点每毫秒产生4096个ID序号 { TSnowflake } constructor TSnowflake.Create; begin FLocker := TCriticalSection.Create; end; destructor TSnowflake.Destroy; begin FLocker.Free; inherited; end; function TSnowflake.Generate: Int64; var curtime: Int64; begin FLocker.Acquire; try curtime := DateTimeToUnix(Now) * 1000; if curtime = fTime then begin fsn := (fsn + 1) and snMask; if fsn = 0 then begin while curtime <= fTime do curtime := DateTimeToUnix(Now) * 1000; end; end else fsn := 0; fTime := curtime; Result := (curtime - Epoch) shl timeShift or FOrgID shl orgShift or FMachineID shl machineShift or fsn; finally FLocker.Release; end; end; initialization end.
演示效果: