在互聯網的業務系統中,涉及到各類各樣的ID,如在支付系統中就會有支付ID、退款ID等。那通常生成ID都有哪些解決方案呢?特別是在複雜的分佈式系統業務場景中,咱們應該採用哪一種適合本身的解決方案是十分重要的。下面咱們一一來列舉一下,不必定所有適合,這些解決方案僅供你參考,或許對你有用。html
一個ID通常來講有下面幾種要素:node
惟一性:確保生成的ID是全網惟一的。git
有序遞增性:確保生成的ID是對於某個用戶或者業務是按必定的數字有序遞增的。github
高可用性:確保任什麼時候候都能正確的生成ID。算法
帶時間:ID裏面包含時間,一眼掃過去就知道哪天的交易。數據庫
系統時間毫秒數數組
咱們可使用當前系統時間精確到毫秒數+業務屬性+用戶屬性+隨機數+...等參數組合形式來確保ID的惟一性,缺點是ID的有序性難以保證,要保證有序性就要依賴數據庫或者其餘中間存儲媒介。安全
UUID分佈式
Java自帶的生成UUID的方式就能生成一串惟一隨機32位長度數據,並且夠咱們用N億年,保證惟一性確定是不用說的了,但缺點是它不包含時間、業務數據可讀性太差了,並且也不能ID的有序遞增。性能
這是一種簡單的生成方式,簡單,高效,但在通常業務系統中我還沒見過有這種生成方式。
數據庫自增ID
咱們都知道爲數據庫主鍵設置自增序號,以必定的趨勢自增,以保證主鍵ID的惟一性。
這個方案很簡單,但最主要的問題在於依賴數據庫自己,這就無形增長了對數據庫的訪問壓力和依賴,一旦對單庫進行分庫分表或者數據遷移就尷尬了。
因此,這也不是合適的ID生成方法。
批量生成ID
一次按需批量生成多個ID,每次生成都須要訪問數據庫,將數據庫修改成最大的ID值,並在內存中記錄當前值及最大值。這樣就避免了每次生成ID都要訪問數據庫並帶來壓力。
這種方案服務就是單點了,若是服務重啓勢必會形成ID丟失不連續的狀況,並且這種方式也不利於水平擴展。
中間件
Redis的全部命令操做都是單線程的,自己提供像incr這樣的自增命令,因此能保證生成的ID確定是惟一有序的。
這種方式不依賴關係數據庫,並且速度快。但系統要引入Redis這一中間件,增長維護成本,並且編碼和配置工做量比較大。即便已經有了Redis組件,但生成ID的高頻率訪問對單線程的Redis性能勢必也會形成影響。
還能夠利用像Zookeeper中的znode數據版原本生成序列號,及MongoDB的ObjectId等,這種利用中間件的作法不是很推薦。
snowflake算法
image
如上圖的所示,Twitter的snowflake算法下面幾部分組成:
41位的時間序列,精確到毫秒,可使用69年
10位的機器標識,最多支持部署1024個節點
12位的序列號,支持每一個節點每毫秒產生4096個ID序號,最高位是符號位始終爲0。
這種方案性能好,在單機上是遞增的,可是因爲涉及到分佈式環境,每臺機器上的時鐘不可能徹底同步,也許有時候也會出現不是全局遞增的狀況。
並且這個項目在2010就中止維護了,但這個設計思路仍是應用於其餘各個ID生成器及變種。
UidGenerator
UidGenerator是百度開源的分佈式ID生成器,基於於snowflake算法的實現,看起來感受還行。不過,國內開源的項目維護性真是擔心。
你們能夠參考具體使用:
https://github.com/baidu/uid-generator/blob/master/README.zh_cn.md
Leaf
Leaf是美團開源的分佈式ID生成器,能保證全局惟一性、趨勢遞增、單調遞增、信息安全,裏面也提到了幾種分佈式方案的對比,但也須要依賴關係數據庫、Zookeeper等中間件。
具體能夠參考官網說明:
https://tech.meituan.com/MT_Leaf.html
好了,就這麼多了,不一樣的方案應用的場景和系統也是不一樣的。你們有更好的方案也能夠在下面留言,一塊兒討論下你們都是怎麼作的。