分佈式ID系列(3)——數據庫自增ID機制適合做分佈式ID嗎

分佈式ID系列(3)——數據庫自增ID機制適合做分佈式ID嗎

數據庫自增ID機制原理介紹

在分佈式裡面,數據庫的自增ID機制的主要原理是:數據庫自增ID和mysql數據庫的replaceinto()函數實現的。這裡的replace數據庫自增ID和mysql數據庫的replaceinto()函數實現的。這裡的replace into跟insert功能類似,不同點在於:replace into首先嚐試插入數據列表中,如果發現表中已經有此行數據(根據主鍵或唯一索引判斷)則先刪除,再插入。否則直接插入新數據。

單機mysql數據庫的自增id實現如下所示 :

首先表結構如下所示

create table t_test(
 id bigint(20)unsignednotnull auto_increment PRIMARY KEY,
 stub char(1)notnulldefault'',
 unique key stub (stub)
)

然後我們插入的sql語句和查詢的語句如下所示

replace into t_test (stub) values('b');
select last_insert_id();

此時可以看到看到我們剛剛插入的id值是1

分佈式ID系列(3)——數據庫自增ID機制適合做分佈式ID嗎

以上就是單機版mysql的自增id的實現過程,但是這裡講的是分佈式id,所以我們要分析一下數據庫的自增ID機制在分佈式裡面是怎麼實現的。

分佈式id在數據庫裡面的實現過程:

既然是分佈式id,那麼最少要使用兩個數據庫,這裡我們使用3臺來講解,為了保證每一臺數據庫裡面的id自增的時候不會重複,那麼我們就要給每一臺數據庫設置auto-increment-increment和auto-increment-offset這兩個屬性值(auto-increment-increment表示每一臺數據庫的起始id值,然後auto-increment-offset表示每一臺數據庫每一次的增加數字),設置值如下所示

Server1:
auto-increment-increment =1
auto-increment-offset =3
Server2:
auto-increment-increment =2
auto-increment-offset =3
Server2:
auto-increment-increment =3
auto-increment-offset =3

那麼如果我們有n臺數據庫的話,那麼上面的auto-increment-increment和auto-increment-offset這兩個屬性值應該怎麼設計呢,我們給每一臺數據庫設置初始值分別為1,2,3...N,然後每一臺數據庫自增步長為機器的臺數N,如下圖所示

分佈式ID系列(3)——數據庫自增ID機制適合做分佈式ID嗎

數據庫自增ID是否適合做分佈式ID:

那數據庫自增ID機制適合作分佈式ID嗎?答案是不太適合,為什麼呢,我總結了下面兩個原因:

1:系統水平擴展比較困難,比如定義好了步長和機器臺數之後,如果要添加機器該怎麼做?假設現在只有一臺機器發號是1,2,3,4,5(步長是1),這個時候需要擴容機器一臺。可以這樣做:把第二臺機器的初始值設置得比第一臺超過很多,比如14(注意這裡設置14的前提是:在擴容期間第一臺機器的ID不可能增加到14),同時設置步長為2,那麼這臺機器下發的號碼都是14以後的偶數。然後把第一臺機器的ID值保留為奇數,比如7,然後修改第一臺的步長為2。讓它符合我們定義的號段標準。擴容方案看起來複雜嗎?貌似還好,現在想象一下如果我們線上有100臺機器,這個時候要擴容該怎麼做?簡直是噩夢。所以系統水平擴展方案複雜難以實現。

2:數據庫壓力還是很大,每次獲取ID都得讀寫一次數據庫,非常影響性能,不符合分佈式ID裡面的延遲低和要高QPS的規則(在高併發下,如果都去數據庫裡面獲取id,那是非常影響性能的)


分享到:


相關文章: