分布式ID-号段模式
我們可以使用號段的方式來獲取自增ID,號段可以理解成批量獲取,比如DistributIdService從數據庫獲取ID時,如果能批量獲取多個ID并緩存在本地的話,那樣將大大提供業務應用獲取ID的效率。
比如DistributIdService每次從數據庫獲取ID時,就獲取一個號段,比如(1,1000],這個范圍表示了1000個ID,業務應用在請求DistributIdService提供ID時,DistributIdService只需要在本地從1開始自增并返回即可,而不需要每次都請求數據庫,一直到本地自增到1000時,也就是當前號段已經被用完時,才去數據庫重新獲取下一號段。
所以,我們需要對數據庫表進行改動,如下:
CREATE TABLE id_generator (id int(10) NOT NULL,current_max_id bigint(20) NOT NULL COMMENT '當前最大id',increment_step int(10) NOT NULL COMMENT '號段的長度',PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;這個數據庫表用來記錄自增步長以及當前自增ID的最大值(也就是當前已經被申請的號段的最后一個值),因為自增邏輯被移到DistributIdService中去了,所以數據庫不需要這部分邏輯了。
這種方案不再強依賴數據庫,就算數據庫不可用,那么DistributIdService也能繼續支撐一段時間。但是如果DistributIdService重啟,會丟失一段ID,導致ID空洞。
為了提高DistributIdService的高可用,需要做一個集群,業務在請求DistributIdService集群獲取ID時,會隨機的選擇某一個DistributIdService節點進行獲取,對每一個DistributIdService節點來說,數據庫連接的是同一個數據庫,那么可能會產生多個DistributIdService節點同時請求數據庫獲取號段,那么這個時候需要利用樂觀鎖來進行控制,比如在數據庫表中增加一個version字段,在獲取號段時使用如下SQL:
update id_generator set current_max_id=#{newMaxId}, version=version+1 where version = #{version}因為newMaxId是DistributIdService中根據oldMaxId+步長算出來的,只要上面的update更新成功了就表示號段獲取成功了。
為了提供數據庫層的高可用,需要對數據庫使用多主模式進行部署,對于每個數據庫來說要保證生成的號段不重復,這就需要利用最開始的思路,再在剛剛的數據庫表中增加起始值和步長,比如如果現在是兩臺Mysql,那么
mysql1將生成號段(1,1001],自增的時候序列為1,3,4,5,7…
mysql1將生成號段(2,1002],自增的時候序列為2,4,6,8,10…
更詳細的可以參考滴滴開源的TinyId:鏈接
在TinyId中還增加了一步來提高效率,在上面的實現中,ID自增的邏輯是在DistributIdService中實現的,而實際上可以把自增的邏輯轉移到業務應用本地,這樣對于業務應用來說只需要獲取號段,每次自增時不再需要請求調用DistributIdService了。
總結
以上是生活随笔為你收集整理的分布式ID-号段模式的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 分布式ID-数据库多主模式
- 下一篇: 分布式ID-雪花算法