日本人做爰過程網(wǎng)站南寧網(wǎng)站seo排名優(yōu)化
文章目錄
- 1. 概述
- 2. 結(jié)構(gòu)
- 3. 代碼
- 3.1 IdWorker.cs
- 3.2 IdWorkerTest.cs (測試)
1. 概述
分布式系統(tǒng)中,有一些需要使用全局唯一ID
的場景,這種時候為了防止ID
沖突可以使用36位的UUID
,但是UUID
有一些缺點,首先他相對比較長,另外UUID
一般是無序的。有些時候我們希望能使用一種簡單一些的ID
,并且希望ID
能夠按照時間有序生成。而Twitter
的snowflake
解決了這種需求,最初Twitter
把存儲系統(tǒng)從MySQL
遷移到Cassandra
,因為Cassandra
沒有順序ID
生成機制,所以開發(fā)了這樣一套全局唯一ID
生成服務(wù)。
該項目地址為:https://github.com/twitter/snowflake
是用 Scala
實現(xiàn)的
參考:
-
C# 分布式自增ID算法snowflake(雪花算法) - 五維思考 - 博客園 (cnblogs.com)
-
C#雪花Id_c# 雪花id-CSDN博客
2. 結(jié)構(gòu)
第1位 | 第2位 | 第3位 | 第4位 | 第5位 |
---|---|---|---|---|
位數(shù) | 時間戳(ms) | 數(shù)據(jù)中心ID(DatacenterId ) | 工作節(jié)點ID (MachineId ) | 自增序列號 |
0 | 0000000000 | 0000000000 | 0000000000 | 000000000000 |
- 第1位:未使用
- 第2位:接下來的41位為毫秒級時間(41位的長度可以使用69年),用毫秒級的時間戳來表示自1970年1月1日 00:00:00 GMT以來的時間。
- 第3-4位:用來區(qū)分不同的數(shù)據(jù)中心
datacenterId
和machineId
,可根據(jù)實際情況分配,最多可容納1024個數(shù)據(jù)中心(2^10=10位的長度最多支持部署1024個節(jié)點),也可以設(shè)置成5位,最大節(jié)點是32個。 - 最后12位是毫秒內(nèi)的計數(shù)(12位的計數(shù)順序號支持每個節(jié)點每毫秒產(chǎn)生4096個
ID
序號)
一共加起來剛好64位,為一個Long
型。(轉(zhuǎn)換成字符串長度為18)
snowflake
生成的ID
整體上按照時間自增排序,并且 整個分布式
系統(tǒng)內(nèi)不會產(chǎn)生ID
碰撞(由datacenter
和machineId
作區(qū)分),并且效率較高。據(jù)說:snowflake
每秒能夠產(chǎn)生26萬個ID
。
注意:
- 在實際使用中,需要根據(jù)不同的分布式環(huán)境配置合適的數(shù)據(jù)中心ID和工作節(jié)點ID,以保證生成的雪花Id的唯一性和順序性。
- 其中
dataCenterId
和workerId
分別是數(shù)據(jù)中心和工作節(jié)點的標識,該生成器依賴于數(shù)據(jù)中心ID和工作節(jié)點ID兩個參數(shù)進行初始化。具體的生成過程是根據(jù)當前時間戳、數(shù)據(jù)中心ID、工作節(jié)點ID和自增序列號,通過位運算組合生成一個64位的唯一標識。
3. 代碼
3.1 IdWorker.cs
using System;
/// <summary>
/// Twitter的分布式自增ID雪花算法
/// </summary>
public class IdWorker
{//起始的時間戳private static long START_STMP = 1480166465631L;//每一部分占用的位數(shù)private static int SEQUENCE_BIT = 12; //序列號占用的位數(shù)private static int MACHINE_BIT = 5; //機器標識占用的位數(shù)private static int DATACENTER_BIT = 5;//數(shù)據(jù)中心占用的位數(shù)//每一部分的最大值private static long MAX_DATACENTER_NUM = -1L ^ (-1L << DATACENTER_BIT);private static long MAX_MACHINE_NUM = -1L ^ (-1L << MACHINE_BIT);private static long MAX_SEQUENCE = -1L ^ (-1L << SEQUENCE_BIT);//每一部分向左的位移private static int MACHINE_LEFT = SEQUENCE_BIT;private static int DATACENTER_LEFT = SEQUENCE_BIT + MACHINE_BIT;private static int TIMESTMP_LEFT = DATACENTER_LEFT + DATACENTER_BIT;private long datacenterId = 1; //數(shù)據(jù)中心private long machineId = 1; //機器標識private long sequence = 0L; //序列號private long lastStmp = -1L;//上一次時間戳#region 單例:完全懶漢private static readonly Lazy<IdWorker> lazy = new Lazy<IdWorker>(() => new IdWorker());public static IdWorker Singleton { get { return lazy.Value; } }private IdWorker() { }#endregionpublic IdWorker(long cid, long mid){if (cid > MAX_DATACENTER_NUM || cid < 0) throw new Exception($"中心Id應在(0,{MAX_DATACENTER_NUM})之間");if (mid > MAX_MACHINE_NUM || mid < 0) throw new Exception($"機器Id應在(0,{MAX_MACHINE_NUM})之間");datacenterId = cid;machineId = mid;}/// <summary>/// 產(chǎn)生下一個ID/// </summary>/// <returns></returns>public long nextId(){long currStmp = getNewstmp();if (currStmp < lastStmp) throw new Exception("時鐘倒退,Id生成失敗!");if (currStmp == lastStmp){//相同毫秒內(nèi),序列號自增sequence = (sequence + 1) & MAX_SEQUENCE;//同一毫秒的序列數(shù)已經(jīng)達到最大if (sequence == 0L) currStmp = getNextMill();}else{//不同毫秒內(nèi),序列號置為0sequence = 0L;}lastStmp = currStmp;return (currStmp - START_STMP) << TIMESTMP_LEFT //時間戳部分| datacenterId << DATACENTER_LEFT //數(shù)據(jù)中心部分| machineId << MACHINE_LEFT //機器標識部分| sequence; //序列號部分}private long getNextMill(){long mill = getNewstmp();while (mill <= lastStmp){mill = getNewstmp();}return mill;}private long getNewstmp(){return (long)(DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds;}
}
3.2 IdWorkerTest.cs (測試)
使用
IdWorker idworker = IdWorker.Singleton;
Console.WriteLine(idworker.nextId());
測試
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;namespace Test.Simple
{public static class IdWorkerTest{public static void Test(){/**** * 兩種測試方法,均為500并發(fā),生成5000個Id:* Machine1() 模擬1臺主機,單例模式獲取實例* Machine5() 模擬5臺主機,創(chuàng)建5個實例*/Machine1();Machine2();Machine5();}public static void Machine1(){int cid = 1;int mid = 15;Console.WriteLine("雪花ID -- IdWorkerTest -- 模擬1臺主機( 數(shù)據(jù)中心{0} - 機器節(jié)點{1}): ", cid, mid);IdWorker idworker = new IdWorker(cid, mid);Console.WriteLine(idworker.nextId());cid = 2;mid = 10;Console.WriteLine("雪花ID -- IdWorkerTest -- 模擬1臺主機( 數(shù)據(jù)中心{0} - 機器節(jié)點{1}): ", cid, mid);idworker = new IdWorker(cid, mid);Console.WriteLine(idworker.nextId());}public static void Machine2(){Console.WriteLine("雪花ID -- IdWorkerTest -- 模擬1臺主機 : ");for (int j = 0; j < 500; j++){Task.Run(() =>{IdWorker idworker = IdWorker.Singleton;for (int i = 0; i < 10; i++){Console.WriteLine(idworker.nextId());}});}}public static void Machine5(){Console.WriteLine("雪花ID -- IdWorkerTest -- 模擬5臺主機 : ");List<IdWorker> workers = new List<IdWorker>();Random random = new Random();for (int i = 0; i < 5; i++){workers.Add(new IdWorker(1, i + 1));}for (int j = 0; j < 500; j++){Task.Run(() =>{for (int i = 0; i < 10; i++){int mid = random.Next(0, 5);Console.WriteLine(workers[mid].nextId());}});}}}
}
在這里插入圖片描述
結(jié)束