日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

分布式全局唯一ID的实现

發布時間:2025/3/12 编程问答 46 豆豆
生活随笔 收集整理的這篇文章主要介紹了 分布式全局唯一ID的实现 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

分布式全局唯一ID的實現

前言

上周末考完試,這周正好把工作整理整理,然后也把之前的一些素材,整理一番,也當自己再學習一番。
一方面正好最近看到幾篇這方面的文章,另一方面也是正好工作上有所涉及,所以決定寫一篇這樣的文章。
先是簡單介紹概念和現有解決方案,然后是我對這些方案的總結,最后是我自己項目的解決思路。

概念

在復雜分布式系統中,往往需要對大量的數據和消息進行唯一標識。

如在金融、電商、支付、等產品的系統中,數據日漸增長,對數據分庫分表后需要有一個唯一ID來標識一條數據或消息,數據庫的自增ID顯然不能滿足需求,此時一個能夠生成全局唯一ID的系統是非常必要的。

特點:

  • 全局唯一性(核心):作為唯一標識,不可以出現重復ID
  • 趨勢遞增:在MySQL InnoDB引擎中使用的是聚集索引,由于多數RDBMS使用B-tree的數據結構來存儲索引數據,在主鍵的選擇上面我們應該盡量使用有序的主鍵保證寫入性能。
  • 單調遞增:保證下一個ID一定大于上一個ID,例如事務版本號、IM增量消息、排序等特殊需求。
  • 信息安全:如果ID是連續的,惡意用戶的扒取工作就非常容易做了,直接按照順序下載指定URL即可;如果是訂單號就更危險了,競對可以直接知道我們一天的單量。所以在一些應用場景下,會需要ID無規則、不規則。
    同時除了對ID號碼自身的要求,業務還對ID號生成系統的可用性要求極高,想象一下,如果ID生成系統癱瘓,這就會帶來一場災難。

運用場景:

分布式全局唯一ID(數據庫的分庫分表后需要有一個唯一ID來標識一條數據或消息;特別一點的如訂單、騎手、優惠券也都需要有唯一ID做標識;MQ中消息的高可用性(確認消息是否發送成功,是否已發送等)等)
其實分布式全局ID是一個比較復雜,重要的分布式問題(什么問題涉及真正的分布式,高并發后都會比較復雜)。常見解決方案有UUID,Snowflake,Flicker,Redis,Zookeeper,Leaf等。

實現方案:

UUID(此處用的Version1:共五個版本,Version1是基于時間的)

生成一個32位16進制字符串(16字節的128位數據,通常以32位長度的字符串表示)(結合機器識別碼(全局唯一的IEEE機器識別號,如果有網卡,從網卡MAC地址獲得,沒有網卡以其他方式獲得),當前時間,一個隨機數)。

優點:

  • 性能好;
  • 擴展性高;
  • 本地生成;
  • 無網絡消耗;
  • 不需要考慮性能瓶頸;
  • 不需要提前商定,各自為政,但絕對不會沖突

缺點:

  • 無法保證趨勢遞增(由于數據庫MySQL的InnoDB采用聚簇索引,有序的ID可以保證寫入速度);
  • UUID過長(消耗內存,帶寬等。更重要的是如果存儲在數據庫中,作為主鍵建立索引效率低)

適用場景:

不需要考慮空間占用,不需要生成有遞增趨勢的ID,且不在MySQL中存儲。

Snowflake

Twitter開源,生成一個64bit(0和1)字符串(1bit不用,41bit表示存儲時間戳,10bit表示工作機器id(5位數據標示位,5位機器標識位),12bit序列號)

結構:

  • 首位符號位:因為ID一般為正數,該值為0.
  • 41位時間戳(毫秒級):時間戳并不是當前時間戳,而是存儲時間戳的差值(當前時間戳-起始時間戳(起始時間戳需要程序指定),理論可以適用(1<<41)/(1000x60x60x24x365),69年。
  • 10位數據機器位(說白了就是邏輯分片ID,具體實現和機器本身無關系):包括5位數據標識位和5位機器標識位(比如5位機房ID,5位機器ID),理論最多可以部署節點位:1<<10=1024。
  • 12位毫秒內的序列:同一節點,同一時刻(同一毫秒內)最多生成ID數1<<12=4096。

最后生成64位Long型數值(這里指,一般Long數據就是64位bit的)。

優點:

  • 趨勢遞增,且按照時間有序;
  • 性能高,穩定性高,不依賴數據庫等第三方系統;
  • 可以按照自身業務特性靈活分配bit位(比如機器位改為15bit,序列位改為7bit)。

缺點:

  • 依賴機器時鐘(雖然UUID也根據當前時間,但其非時間部分波動太大了(重新組織措辭)),時鐘回撥會造成暫不可用或重復發號(分布式系統中,每臺機器上的時鐘不可能完全同步。在同步各個服務器的時間時,有一定幾率發生時鐘回撥(時間超了,往回撥))

適用場景:

要求高性能,可以不連續,數據類型為long型。

Flicker

主要思路是涉及單獨的庫表,利用數據庫的自增ID+replace_into,來生成全局ID。

前置補充:

replace into跟insert功能類似,不同點在于:replace into首先嘗試插入數據列表中,如果發現表中已經有此行數據(根據主鍵或唯一索引判斷)則先刪除,再插入。否則直接插入新數據。

建表:create table t_global_id(id bigint(20) unsigned not null auto_increment,stub char(1) not null default '',primary key (id),unique key stub (stub)) engine=MyISAM; (stub:票根,對應需要生成ID的業務方編碼,可以是項目名,表名,甚至是服務器IP地址。MyISAM(MYSQL5.5.8前默認數據庫存儲引擎,5.5.8及之后默認存儲引擎為InnoDB):(此處應當有MyISAM與InnoDB引擎的區別,乃至其他引擎)基于ISAM類型。不是事務安全(沒有事務隔離??),不支持外鍵,沒有行級鎖。如果執行大量的select,建議MyISAM。獲取數據:# 每次業務可以使用以下SQL讀寫MySQL得到ID號replace into t_golbal_id(stub) values('a');select last_insert_id();

擴展:為解決單點問題,啟用多臺服務器,如MySQL,利用給字段設置auto_increment_increment和auto_increment_offset來保證ID自增(如通過設置起始值與步長,生成奇偶數ID)

優點:

  • 非常簡單,充分利用了數據庫系統的功能實現,成本小,有DBA專業維護;
  • ID號單調自增,可以實現一些對ID有特殊要求的業務。

缺點:

  • 強依賴DB,當DB異常時,整個系統不可用,屬于致命問題(配置主從復制可以盡可能地增加可用性,但是數據一致性在特殊情況下難以保證。主從切換時的不一致可能導致重復發號);
  • 水平擴展困難(定義好了起始值,步長和機器臺數之后,如果要添加機器就比較麻煩(為什么我想到了REDIS的哈希一致原理));
  • ID發號性能瓶頸限制在單臺MySQL的讀寫性能。

適用場景:

數據量不大,并發量不大。

Redis

由于Redis的所有命令是單線程的,所以可以利用Redis的原子操作INCR和INCRBY,來生成全局唯一的ID。

擴展:

可以通過集群來提升吞吐量(可以通過為不同Redis節點設置不同的初始值并同意步長,從而利用Redis生成唯一且趨勢遞增的ID)(其實這個方法和Flicker一致,只是利用到了Redis的一些特性,如原子操作,內存數據庫讀寫快等)(Incrby:將key中儲存的數字加上指定的增量值。這是一個“INCR AND GET”的原子操作,業務方可以定義一個自己的key值,通過INCR命令來獲取對應的ID)

優點:

不依賴數據庫,靈活方便,且性能優于基于數據庫的Flicker方案。

缺點:

  • 擴展性低,Redis集群需要設置號初始值與步長(與Flicker方案一樣);
  • Redis宕機可能生成重復的ID;如果系統中沒有Redis,還需要引入新的組件,增加系統復雜度;
  • 需要編碼和配置的工作量比較大。

適用場景:

Redis集群高可用,并發量高。

舉例:

利用Redis來生成每天從0開始的流水號。如訂單號=日期+當日自增長號。可以每天在Redis中生成一個Key,適用INCR進行累加。

zookeeper

通過其znode數據版本來生成序列號,可以生成32位和64位的數據版本號,客戶端可以使用這個版本號來作為唯一的序列號。

小結:很少會使用zookeeper來生成唯一ID。主要是由于需要依賴zookeeper,并且是多步調用API,如果在競爭較大的情況下,需要考慮使用分布式鎖。因此,性能在高并發的分布式環境下,也不甚理想。

Leaf

美團的Leaf分布式ID生成系統,在Flicker策略與Snowflake算法的基礎上做了兩套優化的方案:Leaf-segment數據庫方案(相比Flicker方案每次都要讀取數據庫,該方案改用proxy server批量獲取,且做了雙buffer的優化)與Leaf-snowflake方案(主要針對時鐘回撥問題做了特殊處理。若發生時鐘回撥則拒絕發號,并進行告警)。

MongDB objectID

ObjectID可以算作和snowflake類似方法,通過”時間+機器碼+pid+inc”共12個字節,通過4+3+2+3的方式,最終標識一個24長度的十六進制字符。

理論總結

其實除了上述方案外,還有ins等的方案,但總的來看,方案主要分為兩種:第一有中心(如數據庫,包括MYSQL,REDIS等),其中可以會利用事先的預約來實現集群(起始步長)。第二種就是無中心,通過生成足夠散落的數據,來確保無沖突(如UUID等)。站在這兩個方向上,來看上述方案的利弊就方便多了。

中心化方案:

優點:

  • 數據長度相對小一些;
  • 數據可以實現自增趨勢等。

缺點:

  • 并發瓶頸處理;
  • 集群需要實現約定;橫向擴展困難(當然有的方案看起來后兩者沒有那么問題,是因為,這些方案利用其技術特性,早就一定程度上解決了這些問題,如Redis的橫向擴展等)。

非中心化方案:

優點:

  • 實現簡單(因為不需要與其他節點存在這方面的約定,耦合);
  • 不會出現中心節點帶來的性能瓶頸;
  • 擴展性較高(擴展的局限往往集中于數據的離散問題)。

缺點:

  • 數據長度較長(畢竟就是通過這一特性來實現無沖突的);
  • 無法實現數據的自增長(畢竟是隨機的);
  • 依賴數據生成方案的優劣(數據生成方案的優劣會全盤接收,但可以推成出新)。

體悟:

技術是無窮無盡的,我們不僅需要看到其中體現的思想與原則,在學習新技術或方案時,需要明確其中一些特性,優缺點的來源,從而進行有效的總結歸納。

應用角度來說:(一方面想要標示符短,便于處理與存儲,另一方面想要足夠大,而不會產生沖突。呵呵)。最理想就是追求從0開始,每個標示符都被使用,且不重復,而且不用擔心并發。呵呵。完全應該根據當前業務場景來選擇,畢竟業務場景在當前是確定的。如果業務變動較大(比如發展初期,業務增長很快),那就需要考慮擴展性,便于日后進行該模塊的更新與技術方案的替換實現(避免一個系統開發一年,用不到一年,那就尷尬了))。

個人經驗

我曾經做過一個“工業物聯網”系統,該系統系統是分為三個子系統:終端服務器(用于收集終端傳感器數據);企業中控服務器(接收來自多個終端服務器的數據,進行綜合查看與控制);云平臺服務器(提供上云)。其中就涉及多個終端服務器的傳感器數據辨識問題,這里以傾斜傳感器數據為例。簡述不同終端服務器的傾斜數據的如何實現全局唯一標識。

以企業中控服務器的數據庫作為統一的數據標識來源

簡單說,就是終端服務器發送一個數據到企業中控室,企業中控服務器就將該數據保存到數據庫中,那么每個數據在企業中控服務器數據庫中都有唯一的ID,并且保持了自增。

優點是實現簡單,只需要做好數據收發,與數據的插入工作即可。唯一需要注意的是數據庫插入時注意資源互斥,防止出現數據插入異常問題(Springframework生成的Bean默認時單例的)。

缺點是需要實時收發數據,防止數據丟失,數據積壓,數據的create_time異常等問題。

以UUID等方式生成數據的全局唯一標識

簡單說,就是終端服務器要發送的數據賦予UUID這樣的ID,來確保全局唯一。這樣終端服務器就可以和中控服務器保持同樣且不沖突的ID了。數據的生成是實現在終端服務器的,而中控服務器只是作為數據的保存與調用(通過統一ID調用)。

優點是不需要數據的實時收發,避免系統在弱網絡情況下出現各類異常。

缺點是數據的ID過長,并且無法保持自增。并且在某種程度上帶來了數據復雜度,從而提高了系統復雜度。

落地方案

由于實際業務的需求,如弱網絡,數據交互頻率跨度大等情況。最終我的實現是先由終端服務器在啟動之初,在企業中控服務器注冊TerminalId,作為不同終端服務器的標識。不同終端服務器接收與保存數據時,都會在每條數據中插入TerminalId,便于企業中控服務器的識別。當然,具體實現當中還有一些細節。如終端服務器在注冊時由于網絡等情況注冊失敗,會先建立一個類似UUID的TerminalId來先保存監測數據。當注冊成功時(系統會根據TerminalId的長度等特性來判斷是否注冊失敗,是否需要重新注冊),會重新修改所有數據的TerminalId,再允許數據上傳。

優點是確保了數據在弱網絡情況下的正確性,并且實現了自動注冊等通用模塊的實現。

缺點是最終數據插入企業中控服務器數據庫時,并沒有嚴格實現數據符合實際時間的增長(如某終端服務器由于網絡等情況沒法發送數據,等待一段時間后發送了這段時間堆積的數據),但保持了總體增長的趨勢。

總結

IT沒有銀彈,我們要做的是多去了解現有的技術方案,再產生符合自己需求的技術方案。因為不同的技術方案都因為其使用場景有著各自的特點,而我們需要了解各種特點的技術來源(是什么技術造就了這一特點,或者說是什么架構造就了這一特點等),從而構建出最符合自己需求的技術方案。

沒有最好,只有最適合。

附錄

參考

阿里P8架構師談:分布式系統全局唯一ID簡介、特點、5種生成方式

分布式ID生成策略

分布式全局唯一ID生成策略

轉載:https://www.cnblogs.com/Tiancheng-Duan/p/10962704.html

總結

以上是生活随笔為你收集整理的分布式全局唯一ID的实现的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。