本文到這里就結(jié)束了关面,喜歡的朋友可以幫忙轉(zhuǎn)發(fā)和關(guān)注一下,感謝支持十厢!
為了感謝支持我的朋友等太!整理了一份Java高級(jí)架構(gòu)資料、Spring源碼分析蛮放、Dubbo缩抡、Redis、Netty包颁、zookeeper瞻想、Spring cloud挎塌、分布式等資。
本號(hào)專注Java源碼分析内边。喜歡底層源碼的朋友可以來交流探討。交流群:818491202 驗(yàn)證:33
的需求待锈,它用于唯一標(biāo)識(shí)一個(gè)業(yè)務(wù)對(duì)象漠其、一個(gè)資源、或者一個(gè)消息等等竿音。在數(shù)據(jù)庫中和屎,唯一ID一般是用來做為一個(gè)數(shù)據(jù)的主鍵〈核玻看過前面介紹MySQL索引原理的文章的朋友應(yīng)該知道柴信,主鍵對(duì)于數(shù)據(jù)庫的重要性不言而喻。
在單機(jī)場(chǎng)景下宽气,要得到一個(gè)全局唯一的ID是非常容易的随常,你可以使用數(shù)據(jù)庫的自增功能。
但是如果在分布式的場(chǎng)景下萄涯,想要構(gòu)建構(gòu)建一個(gè)全局唯一的ID就有些不一樣绪氛。因?yàn)榉植际较到y(tǒng)一般是高并發(fā)場(chǎng)景,那自然不適合使用單機(jī)數(shù)據(jù)庫的自增功能了涝影。如果你的技術(shù)選型恰好是MySQL這樣的“非分布式數(shù)據(jù)庫”枣察,那就得參考一下業(yè)界常見的分布式全局唯一ID生成策略了。
UUID
UUID全稱是Universally Unique Identifier燃逻,翻譯過來叫通用唯一識(shí)別碼序目。標(biāo)準(zhǔn)型式包含32個(gè)16進(jìn)制數(shù)字,以連字號(hào)分為五段伯襟,形式為8-4-4-4-12的36個(gè)字符猿涨,示例:9628f6e9-70ca-45aa-9f7c-77afe0d26e05,到目前為止業(yè)界一共有5種方式生成UUID姆怪,詳情見IETF發(fā)布的UUID規(guī)范《A Universally Unique IDentifier (UUID) URN Namespace》嘿辟,分別稱為UUID的5個(gè)版本。
在JDK自帶的UUID類可以產(chǎn)生版本3和版本4的UUID片效。所以這里簡(jiǎn)單介紹一下版本3和版本4的UUID的生成方式红伦。
UUID版本3:通過計(jì)算name和namespace的MD5散列值得到。
UUID版本4:根據(jù)隨機(jī)數(shù)淀衣,或者偽隨機(jī)數(shù)生成UUID昙读。這種UUID產(chǎn)生重復(fù)的概率是可以計(jì)算出來的,但是重復(fù)的可能性可以忽略不計(jì)膨桥,因此該版本也是被經(jīng)常使用的版本蛮浑。
也有在線生成UUID的網(wǎng)站唠叛,如果你的項(xiàng)目上用到了UUID,可以用來生成臨時(shí)的測(cè)試數(shù)據(jù)沮稚。www.uuidgenerator.net/
UUID的優(yōu)勢(shì)是實(shí)現(xiàn)起來很簡(jiǎn)單艺沼,用JDK原生的API即可得到。劣勢(shì)是與基于b-Tree引擎的數(shù)據(jù)庫的主鍵索引策略不太符合蕴掏,不適合作為高性能需求的場(chǎng)景下的數(shù)據(jù)庫主鍵障般。
基于Redis實(shí)現(xiàn)
都用分布式了,多半要上個(gè)緩存盛杰。用緩存的話挽荡,可能會(huì)使用Redis。Redis的INCR函數(shù)在單機(jī)上是原子操作即供,可以保證唯一且遞增定拟。
單機(jī)Redis可能無法支撐高并發(fā)。而如果使用Redis集群逗嫡,如何保證ID的唯一性呢青自?可以使用步長(zhǎng)的方式。比如有5個(gè)Redis節(jié)點(diǎn)組成的集群驱证,它們生成的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
類snowflake方案
Twitter利用Zookeeper實(shí)現(xiàn)了一個(gè)全局ID生成的服務(wù)snowflake性穿。其生成ID的數(shù)據(jù)結(jié)構(gòu)如下圖所示:
共64位,正好對(duì)應(yīng)Java中的long型雷滚,第一個(gè)符號(hào)位不用需曾,然后41位用于表示時(shí)間戳。后續(xù)10位用來表示節(jié)點(diǎn)的id祈远,如果是多機(jī)房節(jié)點(diǎn)呆万,可以劃分前5位用來表示機(jī)房id,后5位用來表示每個(gè)機(jī)房下的機(jī)器的id车份。最后12位用來表示序列號(hào)谋减,這樣可以做到同一毫秒,同一機(jī)器生成多個(gè)id扫沼,12位算下來最多支持4096個(gè)出爹。
這里的時(shí)間戳并不是當(dāng)前時(shí)間的Time Stamp,而是當(dāng)前時(shí)間相對(duì)于起始時(shí)間的差值缎除。如果基于毫秒來計(jì)算的話严就,41位大約可以用69年。
snowflake算法有許多變種器罐∩椅可以根據(jù)自己的實(shí)際情況調(diào)整位數(shù)的分配,比如時(shí)間戳占42位,機(jī)器id占9位铸董。42位時(shí)間戳就可以用138年等祟印。
百度的UidGenerator和美團(tuán)的Leaf都是基于snowflake的變種。
snowflake是一種比較好的生成ID方式粟害,保證全局唯一蕴忆,且支持高并發(fā)。而且是long類型的悲幅,趨勢(shì)遞增套鹅,可以用于數(shù)據(jù)庫主鍵。還可以根據(jù)時(shí)間來排序夺艰。
但也有其缺點(diǎn),就是強(qiáng)依賴服務(wù)器的時(shí)鐘沉衣,如果服務(wù)器的時(shí)鐘出現(xiàn)回?fù)埽ū热玳c秒或者NTP同步)郁副,就會(huì)導(dǎo)致ID重復(fù)。
美團(tuán)的Leaf解決了時(shí)鐘回?fù)艿膯栴}豌习,具體流程如下圖存谎,可以了解一下:
其他方式
當(dāng)然,還有一些其他的ID生成方案肥隆,比如:
滴滴:時(shí)間+起點(diǎn)編號(hào)+車牌號(hào)
淘寶訂單:時(shí)間戳+用戶ID
其他電商:時(shí)間戳+下單渠道+用戶ID既荚,有的會(huì)加上訂單第一個(gè)商品的ID。
MongoDB的ID:也算是類snowflake的一種栋艳。通過“時(shí)間+機(jī)器碼+pid+inc”共12個(gè)字節(jié)恰聘,4+3+2+3的方式最終標(biāo)識(shí)成一個(gè)24長(zhǎng)度的十六進(jìn)制字符。
總結(jié)
如果不用于數(shù)據(jù)庫主鍵吸占,建議直接用UUID晴叨。
如果想要用來做數(shù)據(jù)庫主鍵,又沒有使用分布式數(shù)據(jù)庫(比如TiDB矾屯、MongoDB等)兼蕊,可以考慮使用snowflake算法,建議使用美團(tuán)的Leaf件蚕。
數(shù)據(jù)庫中間件sharding-jdbc的分布式ID采用twitter開源的snowflake算法孙技,不需要依賴任何第三方組件,這樣其擴(kuò)展性和維護(hù)性得到最大的簡(jiǎn)化排作;但是snowflake算法的缺陷(強(qiáng)依賴時(shí)間牵啦,如果時(shí)鐘回?fù)埽蜁?huì)生成重復(fù)的ID)妄痪,sharding-jdbc沒有給出解決方案蕾久,如果用戶想要強(qiáng)化,需要自行擴(kuò)展。
關(guān)注公眾號(hào)領(lǐng)資料
搜索公眾號(hào)【Java耕耘者】,回復(fù)【Java】僧著,即可獲取大量?jī)?yōu)質(zhì)電子書和一份Java高級(jí)架構(gòu)資料履因、Spring源碼分析、Dubbo盹愚、Redis栅迄、Netty、zookeeper皆怕、Spring cloud毅舆、分布式等視頻資料