每秒生成超過數百萬個【可視有序】分散式ID的簡單方案

来源:https://www.cnblogs.com/bluedoctor/archive/2018/05/30/9112269.html
-Advertisement-
Play Games

生成順序良好肉眼方便查看的分散式ID的方案,比雪花ID演算法實現更簡單,理論上每秒可以生成接近1000萬個不重覆的ID。 ...


去年做了一個產品,會經常導入導出大量的外部數據,這些數據的ID有的是GUID類型,有的是字元串,也有的是自增。GUID類型沒有順序,結果要排序得藉助其它業務欄位,整體查詢效率比較低;字元串ID本來是用來轉換GUID的或者數字ID的,結果有些字元串ID不符合規範,常常有特殊數據需要處理;自增主鍵ID的數據導入合併經常有衝突。

為了避免GUID主鍵的“索引頁分裂”問題,提高查詢效率,同時為瞭解決分散式環境下的數據導入合併問題,強烈需要一種分散式的,有序的ID生成方案。我參考了雪花ID(Twitter-Snowflake,64位自增ID演算法)實現方案,設計一個更容易肉眼觀察數值連續有序的分散式ID方案。

跟雪花ID方案一樣,都是使用時間數據做為生成ID的基礎,不同的在於對數據的具體處理方式。另外,為了確保每台機器ID的不同,可以配置指定此ID,在應用程式配置文件中如下配置:

<!--分散式ID標識,3位整數,範圍101-999 大小--> 
<add key="SOD_MachineID" value="101"/>

如果不配置分散式ID,預設將根據當前機器IP隨機生成3位分散式機器ID。

該演算法的實現比雪花演算法簡單不少,詳細的不多說,直接看代碼:

       /// <summary>
        /// 獲取一個新的有序GUID整數
        /// </summary>
        /// <param name="dt">當前時間</param>
        /// <param name="haveMs">是否包含毫秒,生成更加有序的數字,但這會增加重覆率</param>
        /// <returns></returns>
        protected internal static long InnerNewSequenceGUID(DateTime dt, bool haveMs)
        {
            //日期以 2017.3.1日為基準,計算當前日期距離基準日期相差的天數,可以使用20年。
            //日期部分使用4位數字表示
            int days = (int)dt.Subtract(baseDate).TotalDays;
            //時間部分表示一天中所有的秒數,最大為 86400秒,共5位
            //日期時間總位數= 4(日期)+5(時間)+3(毫秒)=12
            int times = dt.Second + dt.Minute * 60 + dt.Hour * 3600;
            //long 類型最大值 9223 3720 3685 4775 807
            //可用隨機位數= 19-12=7
            long datePart = ((long)days + 1000) * 1000 * 1000 * 1000 * 100;
            long timePart = (long)times * 1000 * 1000;
            long msPart = (long)dt.Millisecond * 1000;
            long dateTiePart = (datePart + timePart + msPart) * 10000;

            int mid = MachineID * 10000;
            //得到總數= 4(日期)+5(時間)+3(毫秒)+7(GUID)
            long seq = dateTiePart + mid;

            //線程安全的自增並且不超過最大值10000
            int startValue = System.Threading.Interlocked.Increment(ref SeqNum);
            while (startValue >= 10000)
            {
                SeqNum = 0;
                startValue = 0;
                //可能此時別的線程再次更改了 SeqNum
                while (startValue != SeqNum)
                {
                    startValue = System.Threading.Interlocked.Increment(ref SeqNum);
                }
            }

            seq = seq + startValue;
            return seq;
        }

每秒不重覆ID生成數:

從上面的程式代碼中,得知 ID總數= 4位(日期)+5位(時間)+3位(毫秒)+7位(GUID)。
其中,7位(GUID)中,除去前3位的分散式機器ID,剩餘4位有序數字,可以表示1萬個數字。
所以,該方面每毫秒最大可以生成1萬個不重覆的ID數,每秒最大可以生成1千萬個不重覆ID
當然這是理論大小,實際上受到當前機器的計算能力限制。

該方法進行了再次封裝,用於在不同情況下分別使用:

   /// <summary>
       /// 生成一個新的有序的長整形“GUID”,在一秒內,重覆概率低於 萬分之一,速度較快,線程安全,
       /// 但不如NewUniqueSequenceGUID 方法結果更有序(不包含毫秒部分)
       /// </summary>
       /// <returns></returns>
       public static long NewSequenceGUID()
       {
           return UniqueSequenceGUID.InnerNewSequenceGUID(DateTime.Now,false);
       }

       /// <summary>
       /// 生成一個唯一的有序的GUID形式的長整數,速度較NewSequenceGUID 稍慢,但線程不安全
       /// </summary>
       /// <returns></returns>
       public static long NewUniqueSequenceGUID()
       {
           return UniqueId.NewID();
       }

        /// <summary>
        /// 當前機器ID,可以作為分散式ID,如果需要指定此ID,請在應用程式配置文件配置 SOD_MachineID 的值,範圍大於100,小於1000.
        /// </summary>
        /// <returns></returns>
        public static int CurrentMachineID()
        {
            return UniqueSequenceGUID.GetCurrentMachineID();
        }

最後,像下麵這樣使用即可:

        Console.WriteLine("當前機器的分散式ID:{0}",CommonUtil.CurrentMachineID());
            Console.WriteLine("測試分散式ID:快速(萬分之一重覆率)模式");
            for (int i= 0; i < 50; i++)
            {
                Console.Write(CommonUtil.NewSequenceGUID());
                Console.Write(",");
            }
            Console.WriteLine();
            Console.WriteLine("測試分散式ID:唯一模式");
            for (int i = 0; i < 50; i++)
            {
                Console.Write(CommonUtil.NewUniqueSequenceGUID());
                Console.Write(",");
            }
            Console.WriteLine();

下麵是生成的ID數字示例:

當前機器的分散式ID:832
測試分散式ID:快速(每毫秒一萬個不重覆ID)模式
1455630735488320001,1455630735498320002,1455630735498320003,1455630735498320004,1455630735498320005,1455630735498320006,1455630735498320007,1455630735498320008,1455630735498320009,1455630735498320010,1455630735508320011,1455630735508320012,1455630735508320013,1455630735508320014,1455630735508320015,1455630735508320016,1455630735508320017,1455630735508320018,1455630735508320019,1455630735508320020,1455630735508320021,1455630735508320022,1455630735508320023,1455630735508320024,1455630735508320025,1455630735508320026,1455630735508320027,1455630735508320028,1455630735508320029,1455630735508320030,1455630735508320031,1455630735508320032,1455630735508320033,1455630735518320034,1455630735518320035,1455630735518320036,1455630735518320037,1455630735518320038,1455630735518320039,1455630735518320040,1455630735528320041,1455630735528320042,1455630735528320043,1455630735528320044,1455630735528320045,1455630735528320046,1455630735528320047,1455630735528320048,1455630735528320049,1455630735558320050,
測試分散式ID:唯一模式
1455630735578320051,1455630735598320052,1455630735598320053,1455630735598320054,1455630735598320055,1455630735608320056,1455630735608320057,1455630735608320058,1455630735608320059,1455630735608320060,1455630735608320061,1455630735608320062,1455630735608320063,1455630735618320064,1455630735618320065,1455630735618320066,1455630735618320067,1455630735618320068,1455630735618320069,1455630735618320070,1455630735618320071,1455630735628320072,1455630735628320073,1455630735628320074,1455630735628320075,1455630735628320076,1455630735628320077,1455630735628320078,

 

註:本文生成ID的方法已經在產品中大量使用,運行情況良好。

要使用本程式,你可以Nuget 下載SOD的程式包(支持.NET 2.0項目),然後像本文示例這樣使用即可:

Install-Package PDF.NET.SOD.Core

獲取SOD的源碼,請Fork我們的Github:

https://github.com/znlgis/sod

源碼位置在 https://github.com/znlgis/sod/tree/master/src/SOD 目錄下。

有疑問,請加QQ群154224970 咨詢,感謝大家支持SOD框架!

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 今天,我們很高興可以發佈 ASP.NET Core 2.1.0!這是我們 .NET平臺下開源的、跨平臺的 Web 框架的最新版本,現在已準備好供生產使用。今天就[開始使用](https://www.microsoft.com/net/learn/apps/web/get-started) ASP.N... ...
  • 我們很高興可以發佈 .NET Core 2.1。這次更新包括對性能的改進,對運行時和工具的改進。還包含一種以 NuGet 包的形式部署工具的新方法。我們添加了一個名為 [`Span ...
  • 前言: 最近正好寫一個程式,需要操作剪切板 功能很簡單,只需要從剪切板內讀取字元串,然後清空剪切板,然後再把字元串導入剪切板 我想當然的使用我最拿手的C#來完成這項工作,原因無他,因為.Net框架封裝了能實現這種功能的方法 然後就有瞭如下代碼 1 string Temp = ""; 2 while ...
  • 記得之前使用VS2015打開老的MVC4項目,不能右鍵創建控制器和添加視圖,讓我非常不習慣!找遍了網路無果,最後只能回到VS2013,但我就是不喜歡用舊的VS,這是不是病。。。 1、將VS2017離線安裝包下載完整(離線下載方法參考:https://www.cnblogs.com/VAllen/p/ ...
  • C#有以下幾種數據類型:數據類型案例以及取值範圍:界面:選擇int時:選中long時:選中float時:選中double時:選中decimal時:選中string時:選中char時:選中Bool時:源代碼如下:using System;using System.Collections.Generic... ...
  • (記錄下方便自己複習) 概念 簡單地理解為用來連接資料庫的類。 工作流程 ①Connection對象用來連接資料庫。 兩種連接方式:Windows身份驗證 / sqlserver驗證 ②command對象用來操作資料庫。(三個重要的方法:ExecuteNonQuery(),ExecuteReader ...
  • 這幾天在知乎看到一個問題“為什麼很多IT公司不喜歡進過培訓機構的人呢?” 身為老男孩的教學負責人,這樣的問題必然會引起我的關註, 花時間看了各路人士的回答, 我了個去,儘是對培訓機構排山倒海的謾罵聲, 負面評價不勝枚舉, 看完久久不能釋懷,心裡堵的慌, 又委屈又氣憤又無奈, 委屈的是自己辛苦為之奮鬥 ...
  • 1 //文件的讀取方式一 2 //直接讀取文件 3 4 string textContent=File.ReadAllText("路徑","讀取的文件內容類型"); 5 6 //文件讀取 方式二 7 8 string FileName="";//表示路徑 9 using(FlieStream fs= ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...