<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          分布式系統(tǒng)唯一 ID 生成方案

          共 4654字,需瀏覽 10分鐘

           ·

          2021-05-24 21:48

          0x01:簡(jiǎn)介

          系統(tǒng)唯一ID是我們?cè)陂_(kāi)發(fā)過(guò)程中遇到的一個(gè)常見(jiàn)問(wèn)題,簡(jiǎn)單的來(lái)說(shuō),生成ID的方式有很多種,它們適應(yīng)不同性能。


          0x02:常見(jiàn)方案

          一、數(shù)據(jù)庫(kù)自增長(zhǎng)序列或者字段

          這是最常見(jiàn)的方式,利用數(shù)據(jù)庫(kù)的AUTO_INCREMENT

          優(yōu)點(diǎn)

          • 簡(jiǎn)單,代碼方便,性能可接受

          • 數(shù)字ID具有天然排序,對(duì)需要分頁(yè)或者排序的結(jié)果很有幫組

          缺點(diǎn)

          • 不同數(shù)據(jù)庫(kù)的語(yǔ)法和實(shí)現(xiàn)不同,數(shù)據(jù)庫(kù)遷移或者數(shù)據(jù)庫(kù)版本支持的時(shí)候需要處理

          • 在單個(gè)數(shù)據(jù)庫(kù)或讀寫(xiě)分離或者一主多從的情況下,只有一個(gè)主庫(kù)可以生成,可能會(huì)造成單點(diǎn)故障。

          • 在性能達(dá)不到要求的情況下,比較難擴(kuò)展。

          • 分表分庫(kù)的時(shí)候會(huì)比較麻煩

          優(yōu)化點(diǎn)

          • 針對(duì)主庫(kù)單點(diǎn),如果是有多個(gè)master庫(kù),則每個(gè)master庫(kù)設(shè)置的起始數(shù)字不一樣,但是他們的步長(zhǎng)一樣,可以是master的個(gè)數(shù),比如是1、4、7、10,master2生成的是2、5、8、11,master3生成的是3、6、9、12~這樣就可以有效生成集群中的唯一ID,也可以大大降低ID生成數(shù)據(jù)庫(kù)操作的負(fù)載。


          二、UUID

          這是最常見(jiàn)的方式,可以利用數(shù)據(jù)庫(kù)也可以利用程序生成。

          優(yōu)點(diǎn)

          • 簡(jiǎn)單,代碼生成方便

          • 生成ID的性能非常好,基本不會(huì)有性能問(wèn)題。

          • 全球唯一,在遇見(jiàn)數(shù)據(jù)遷移,系統(tǒng)數(shù)據(jù)合并,或者數(shù)據(jù)庫(kù)變更時(shí),很難產(chǎn)生沖突,較易解決。

          缺點(diǎn)

          • 沒(méi)有排序,無(wú)法保證趨勢(shì)遞增

          • UUID往往使用的是字符串存儲(chǔ),查詢(xún)效率比較低

          • 存儲(chǔ)空間比較大,一般是16位或者32位

          • 傳輸數(shù)據(jù)量大

          • 不可讀


          三、UUID 變種

          為了解決UUID不可讀,可以使用UUID to Int64的方法。及

          /// <summary>
          /// 根據(jù)GUID獲取唯一數(shù)字序列
          /// </summary>
          public static long GuidToInt64() {
              byte[] bytes = Guid.NewGuid().ToByteArray();
              return BitConverter.ToInt64(bytes, 0);

          }

          為了解決UUID無(wú)序的問(wèn)題,NHibernate在其主鍵生成方式中提供了Comb算法(combined guid/timestamp)。保留GUID的10個(gè)字節(jié),用另6個(gè)字節(jié)表示GUID生成的時(shí)間(DateTime)。

          /// <summary> 
          /// Generate a new <see cref="Guid"/> using the comb algorithm. 
          /// </summary> 
          private Guid GenerateComb()
          {
              byte[] guidArray = Guid.NewGuid().ToByteArray();
              DateTime baseDate = new DateTime(190011);
              DateTime now = DateTime.Now;
              // Get the days and milliseconds which will be used to build    
              //the byte string    
              TimeSpan days = new TimeSpan(now.Ticks - baseDate.Ticks);
              TimeSpan msecs = now.TimeOfDay;
              // Convert to a byte array        
              // Note that SQL Server is accurate to 1/300th of a    
              // millisecond so we divide by 3.333333    
              byte[] daysArray = BitConverter.GetBytes(days.Days);
              byte[] msecsArray = BitConverter.GetBytes((long)
                (msecs.TotalMilliseconds / 3.333333));
              // Reverse the bytes to match SQL Servers ordering    
              Array.Reverse(daysArray);
              Array.Reverse(msecsArray);

              // Copy the bytes into the guid    
              Array.Copy(daysArray, daysArray.Length - 2, guidArray,
                guidArray.Length - 62);
              Array.Copy(msecsArray, msecsArray.Length - 4, guidArray,
                guidArray.Length - 44);
              return new Guid(guidArray);
          }

          用上面的算法測(cè)試一下,得到如下的結(jié)果:作為比較,前面3個(gè)是使用COMB算法得出的結(jié)果,最后12個(gè)字符串是時(shí)間序(統(tǒng)一毫秒生成的3個(gè)UUID),過(guò)段時(shí)間如果再次生成,則12個(gè)字符串會(huì)比圖示的要大。后面3個(gè)是直接生成的GUID。


          四、Redis 生成 ID

          當(dāng)使用數(shù)據(jù)庫(kù)來(lái)生成ID性能不能夠達(dá)到要求時(shí),可以使用Redis來(lái)生成ID,這主要依賴(lài)于Redis是單線程的,所有也可以利用生成全局唯一ID,可以使用Redis的INCR或INCRBY來(lái)實(shí)現(xiàn)

          可以使用Redis集群來(lái)獲取更高的吞吐量。假如一個(gè)集群中有5臺(tái)Redis。可以初始化每臺(tái)Redis的值分別是1,2,3,4,5,然后步長(zhǎng)都是5。各個(gè)Redis生成的ID為:

          A:1,6,11,16,21
          B:2,7,12,17,22
          C:3,8,13,18,23
          D:4,9,14,19,24
          E:5,10,15,20,25

          這個(gè),隨便負(fù)載到哪個(gè)機(jī)確定好,未來(lái)很難做修改。但是3-5臺(tái)服務(wù)器基本能夠滿足上,都可以獲得不同的ID。但是步長(zhǎng)和初始值一定需要事先需要了。使用Redis集群也可以方式單點(diǎn)故障的問(wèn)題。

          另外,比較適合使用Redis來(lái)生成每天從0開(kāi)始的流水號(hào)。比如訂單號(hào) = 日期 + 當(dāng)日自增長(zhǎng)號(hào)。可以每天在Redis中生成一個(gè)Key,使用INCR進(jìn)行累加。

          優(yōu)點(diǎn)

          • 不依賴(lài)數(shù)據(jù)庫(kù),靈活方便,且性能優(yōu)于數(shù)據(jù)庫(kù)

          • 數(shù)字ID天然排序,對(duì)分頁(yè)或者需要有排序的結(jié)果良好

          缺點(diǎn)

          • 如果系統(tǒng)中沒(méi)有Redis,還需要引入Redis,增加了系統(tǒng)組件的復(fù)雜度

          • 如需要編碼和配置的工作量比較大


          四、利用 zookeeper 生成唯一 ID

          zookeeper主要通過(guò)其znode數(shù)據(jù)版本來(lái)生成序列號(hào),可以生成32位和64位的數(shù)據(jù)版本號(hào),客戶(hù)端可以使用這個(gè)版本號(hào)來(lái)作為唯一的序列號(hào)。

          很少會(huì)使用zookeeper來(lái)生成唯一ID。主要是由于需要依賴(lài)zookeeper,并且是多步調(diào)用API,如果在競(jìng)爭(zhēng)較大的情況下,需要考慮使用分布式鎖。因此,性能在高并發(fā)的分布式環(huán)境下,也不甚理想。


          五、MongoDB 的 ObjectId

          MongoDB的ObjectId和snowflake算法類(lèi)似。它設(shè)計(jì)成輕量型的,不同的機(jī)器都能用全局唯一的同種方法方便地生成它。MongoDB 從一開(kāi)始就設(shè)計(jì)用來(lái)作為分布式數(shù)據(jù)庫(kù),處理多個(gè)節(jié)點(diǎn)是一個(gè)核心要求。使其在分片環(huán)境中要容易生成得多。

          六、Twitter的snowflake算法

          snowflake是Twitter開(kāi)源的分布式ID生成算法,結(jié)果是一個(gè)long型的ID。其核心思想是:使用41bit作為毫秒數(shù),10bit作為機(jī)器的ID(5個(gè)bit是數(shù)據(jù)中心,5個(gè)bit的機(jī)器ID),12bit作為毫秒內(nèi)的流水號(hào)(意味著每個(gè)節(jié)點(diǎn)在每毫秒可以產(chǎn)生 4096 個(gè) ID),最后還有一個(gè)符號(hào)位,永遠(yuǎn)是0。具體實(shí)現(xiàn)的代碼可以參看:

          https://github.com/twitter/snowflake

          喜歡,在看


          瀏覽 44
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国产无码中文字幕在线 | 人人摸人人色 | 偷拍视频图片综合网 | 做爱 高清无码 | www.淫香淫色 |