雪花算法(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.
演示效果: