有點牛逼,滴滴開源的分布式id生成系統(tǒng)
閱讀本文大概需要 7 分鐘。
來自:網(wǎng)絡(luò)
簡介
tinyid系統(tǒng)架構(gòu)圖

nextId和getNextSegmentId是tinyid-server對外提供的兩個http接口
nextId是獲取下一個id,當(dāng)調(diào)用nextId時,會傳入bizType,每個bizType的id數(shù)據(jù)是隔離的,生成id會使用該bizType類型生成的IdGenerator。
getNextSegmentId是獲取下一個可用號段,tinyid-client會通過此接口來獲取可用號段
IdGenerator是id生成的接口
IdGeneratorFactory是生產(chǎn)具體IdGenerator的工廠,每個biz_type生成一個IdGenerator實例。通過工廠,我們可以隨時在db中新增biz_type,而不用重啟服務(wù)
IdGeneratorFactory實際上有兩個子類IdGeneratorFactoryServer和IdGeneratorFactoryClient,區(qū)別在于,getNextSegmentId的不同,一個是DbGet,一個是HttpGet
CachedIdGenerator則是具體的id生成器對象,持有currentSegmentId和nextSegmentId對象,負(fù)責(zé)nextId的核心流程。
nextId最終通過AtomicLong.andAndGet(delta)方法產(chǎn)生。
性能與可用性
性能
http方式訪問,性能取決于http server的能力,網(wǎng)絡(luò)傳輸速度 java-client方式,id為本地生成,號段長度(step)越長,qps越大,如果將號段設(shè)置足夠大,則qps可達(dá)1000w+
可用性
依賴db,當(dāng)db不可用時,因為server有緩存,所以還可以使用一段時間,如果配置了多個db,則只要有1個db存活,則服務(wù)可用 使用tiny-client,只要server有一臺存活,則理論上可用,server全掛,因為client有緩存,也可以繼續(xù)使用一段時間
Tinyid的特性
全局唯一的long型id 趨勢遞增的id,即不保證下一個id一定比上一個大 非連續(xù)性 提供http和java client方式接入 支持批量獲取id 支持生成1,3,5,7,9…序列的id 支持多個db的配置,無單點
推薦使用方式
tinyid-server推薦部署到多個機(jī)房的多臺機(jī)器 多機(jī)房部署可用性更高,http方式訪問需使用方考慮延遲問題 推薦使用tinyid-client來獲取id,好處如下: id為本地生成(調(diào)用AtomicLong.addAndGet方法),性能大大增加
client對server訪問變的低頻,減輕了server的壓力
因為低頻,即便client使用方和server不在一個機(jī)房,也無須擔(dān)心延遲
即便所有server掛掉,因為client預(yù)加載了號段,依然可以繼續(xù)使用一段時間 注:使用tinyid-client方式,如果client機(jī)器較多頻繁重啟,可能會浪費較多的id,這時可以考慮使用http方式
推薦db配置兩個或更多: db配置多個時,只要有1個db存活,則服務(wù)可用 多db配置,如配置了兩個db,則每次新增業(yè)務(wù)需在兩個db中都寫入相關(guān)數(shù)據(jù)
tinyid的原理
Id生成系統(tǒng)要點
全局唯一的id:無論怎樣都不能重復(fù),這是最基本的要求了 高性能:基礎(chǔ)服務(wù)盡可能耗時少,如果能夠本地生成最好 高可用:雖說很難實現(xiàn)100%的可用性,但是也要無限接近于100%的可用性 簡單易用: 能夠拿來即用,接入方便,同時在系統(tǒng)設(shè)計和實現(xiàn)上要盡可能的簡單
Tinyid的實現(xiàn)原理
DB號段算法描述

這里我們增加了biz_type,這個代表業(yè)務(wù)類型,不同的業(yè)務(wù)的id隔離
max_id則是上面的end_id了,代表當(dāng)前最大的可用id
step代表號段的長度,可以根據(jù)每個業(yè)務(wù)的qps來設(shè)置一個合理的長度
version是一個樂觀鎖,每次更新都加上version,能夠保證并發(fā)更新的正確性 ?那么我們可以通過如下幾個步驟來獲取一個可用的號段,
A.查詢當(dāng)前的max_id信息:select id, biz_type, max_id, step, version from tiny_id_info where biz_type='test';
B.計算新的max_id: new_max_id = max_id + step
C.更新DB中的max_id:update tiny_id_info set max_id=#{new_max_id} , verison=version+1 where id=#{id} and max_id=#{max_id} and version=#{version}
D.如果更新成功,則可用號段獲取成功,新的可用號段為(max_id, new_max_id]
E.如果更新失敗,則號段可能被其他線程獲取,回到步驟A,進(jìn)行重試
號段生成方案的簡單架構(gòu)

簡單架構(gòu)的問題
當(dāng)id用完時需要訪問db加載新的號段,db更新也可能存在version沖突,此時id生成耗時明顯增加
db是一個單點,雖然db可以建設(shè)主從等高可用架構(gòu),但始終是一個單點
使用http方式獲取一個id,存在網(wǎng)絡(luò)開銷,性能和可用性都不太好
優(yōu)化辦法如下:


tinyid提供http和tinyid-client兩種方式接入 tinyid-server內(nèi)部緩存兩個號段 號段基于db生成,具有原子性 db支持多個 tinyid-server內(nèi)置easy-router選擇db
項目地址
推薦閱讀:
成都又一程序員跳樓!一首IT版的《成都》,聽哭了所有IT人……
微信掃描二維碼,關(guān)注我的公眾號
朕已閱?


