交互分布式系統(tǒng)下如何生成唯一序列
1 介紹
在常見的業(yè)務(wù)場景中,比如全局訂單Id,唯一標識的支付編號等,都需要這個來保證。
那生成ID都有哪些解決方案呢?特別是在復雜的分布式系統(tǒng)業(yè)務(wù)場景中,我們應(yīng)該采用哪種解決方案來實現(xiàn)這個唯一序列呢?
一般來說,這個唯一序號有如下幾種特征:
全局唯一性:確保生成的序列是全局唯一的,不可重復。
有序性:確保生成的ID值對于某個用戶或者業(yè)務(wù)是按一定的數(shù)字有序遞增的。
高可用性:確保生成ID功能的高可用,能夠承接較大峰值,能夠保證序列生成的有效性(不重復且有序)。
帶時間標記:ID中有時間片段組成,可是清晰識別出操作的時間。
下面是業(yè)內(nèi)幾種常見的分布式唯一序列生成方案,我們一一來介紹下。
2 數(shù)據(jù)庫自增
數(shù)據(jù)庫主鍵設(shè)置自增序號auto_increment,可以按照一定的趨勢自增,保證主鍵ID的唯一性。
這個方案簡單易操作,優(yōu)點是明顯、可控。
但由于它是在數(shù)據(jù)庫的單表上進行操作,對數(shù)據(jù)庫性能依賴比較明顯,高并發(fā)下的壓力也很大。所以不是唯一ID生成的最佳方法。
1 create table `t_generator_id` 2 ( 3 `id` bigint(20) not null auto_increment, -- 表示自增列 4 -- 其他字段信息 5 )
3 系統(tǒng)時間毫秒數(shù)
我們可以使用當前系統(tǒng)時間精確到毫秒數(shù)(或者時間戳)+業(yè)務(wù)屬性+用戶屬性+隨機數(shù)+...等參數(shù)組合形式來確保ID的唯一性,缺點是ID的有序性難以保證,如果對有序性由強需求的業(yè)務(wù)不建議使用。
類似京東淘寶等電商的訂單號生成。因為訂單號和用戶id在業(yè)務(wù)上的區(qū)別,訂單號盡可能要多些冗余的業(yè)務(wù)信息,比如
滴滴:時間+起點編號+車牌號 ; 淘寶訂單:時間戳+用戶ID,類似滴滴訂單的唯一序號如下:
4 UUID(GUID)
Java自帶的生成UUID的方式(.Net體系下也有GUID可以對應(yīng)),生成的是Length=32的16進制格式的字符串,如果回退為byte數(shù)組共16個byte元素,即UUID是一個128bit長的數(shù)字,一般用16進制表示。
可以保證唯一性,但缺點是它不包含時間標識、業(yè)務(wù)數(shù)據(jù)可讀性太差了,而且也不能ID的有序遞增。優(yōu)點生成方式,簡單,高效,一般業(yè)務(wù)系統(tǒng)中比較少用。
5 批量預生成ID
1、在內(nèi)存(緩存)中,按需批量生成N個ID,并將最大ID值記錄到數(shù)據(jù)庫中。比如生成 1~10000,把max=10000持久化到數(shù)據(jù)庫中,內(nèi)存中記錄的是current=1和max=10000。
2、所有的使用都在內(nèi)存中進行,每消耗一次序號,current + 1。
3、當current==max的時候,重復第一個步驟,再次批量生成 10001~20000的值,并將數(shù)據(jù)庫中的max改成20000。
優(yōu)點是避免了每次生成ID都要訪問數(shù)據(jù)庫并帶來壓力。
缺點是只能是單點服務(wù),如果服務(wù)重啟勢必會造成ID丟失不連續(xù)的情況,而且這種方式也不利于水平擴展。
6 Redis生成唯一序列
Redis可以使用簡易的String類型,它的incr/decr key 語法,支持高效快速的增減值,能夠保證生成的ID肯定是唯一有序的。
這種方式不依賴數(shù)據(jù)庫持久化,速度快,算是比較好的辦法了。但系統(tǒng)中引入Redis這一中間件,無形中增加維護成本。在超大流量、超高并發(fā)的情況下,單實例Redis還是無法滿足的,需要橫向擴展Redis集群來進行支撐。
1 <strong>incr</strong>/<strong>decr key</strong> // 自增減 1 2 <strong>incrby</strong>/<strong>decrby key</strong> increment // 自增減指定數(shù)值 3 <strong>incrbyfloat</strong>/<strong>decrbyfloat key</strong> increment // 自增減浮點數(shù)
還可以利用像Zookeeper中的znode數(shù)據(jù)版本來生成序列號,及MongoDB的ObjectId等,但是性能不如Redis,不是很推薦。
7 snowflake算法
Twitter在把存儲系統(tǒng)從MySQL遷移到Cassandra的過程中由于Cassandra沒有順序ID生成機制,于是自己開發(fā)了一套全局唯一ID生成服務(wù):Snowflake。
如上圖的所示,Twitter的snowflake算法下面幾部分組成:
41位的時間序列,精確到毫秒,可以使用69年
10位的機器標識,最多支持部署1024個節(jié)點
12位的序列號,支持每個節(jié)點每毫秒產(chǎn)生4096個ID序號,最高位是符號位始終為0。
這種方案性能好,在單機上是遞增的,但是由于涉及到分布式環(huán)境,每臺機器上的時鐘不可能完全同步,也許有時候也會出現(xiàn)不是全局遞增的情況。
而且這個項目在2010就停止維護了,但這個設(shè)計思路被很多廠家參考,應(yīng)用于各個業(yè)務(wù)的ID生成器及變種。
8 UidGenerator
UidGenerator是百度開源的一款分布式高性能的唯一ID生成器,使用Java實現(xiàn)的, 基于Snowflake算法的唯一ID生成器。
在實現(xiàn)上, UidGenerator通過借用未來時間來解決sequence天然存在的并發(fā)限制; 采用RingBuffer來緩存已生成的UID, 并行化UID的生產(chǎn)和消費, 同時對CacheLine補齊,避免了由RingBuffer帶來的硬件級「偽共享」問題. 最終單機QPS可達600萬。
具體的GitHub地址如下:
https://github.com/baidu/uid-generator/blob/master/README.zh_cn.md
9 Leaf
Leaf是美團開源的分布式ID生成器,能保證全局唯一性、趨勢遞增、單調(diào)遞增、信息安全,同時也需要依賴關(guān)系數(shù)據(jù)庫、Zookeeper等中間件。
美團技術(shù)社區(qū)有詳細的說明,同時也對分布式ID生成有一些比較好的分析和建議:https://www.jb51.net/article/235968.htm
10 總結(jié)
個人覺得最好的是Redis方案和snowflake算法,無論是性能還是可用性程度上。另外各大廠也有自己的一些做法,比如百度的UidGenerator 和 美團的Leaf,
主要也是根據(jù)現(xiàn)有的方案進行優(yōu)化和改造,達到比較契合他們自己業(yè)務(wù)的目標。
以上就是交互分布式系統(tǒng)下如何生成唯一序列的詳細內(nèi)容,更多關(guān)于交互分布式系統(tǒng)下的唯一序列的資料請關(guān)注本站其它相關(guān)文章!
版權(quán)聲明:本站文章來源標注為YINGSOO的內(nèi)容版權(quán)均為本站所有,歡迎引用、轉(zhuǎn)載,請保持原文完整并注明來源及原文鏈接。禁止復制或仿造本網(wǎng)站,禁止在非www.sddonglingsh.com所屬的服務(wù)器上建立鏡像,否則將依法追究法律責任。本站部分內(nèi)容來源于網(wǎng)友推薦、互聯(lián)網(wǎng)收集整理而來,僅供學習參考,不代表本站立場,如有內(nèi)容涉嫌侵權(quán),請聯(lián)系alex-e#qq.com處理。