在分佈式裏面,數據庫的自增ID機制的主要原理是:數據庫自增ID和mysql數據庫的replace_into()函數實現的。這裏的replace數據庫自增ID和mysql數據庫的replace_into()函數實現的。這裏的replace into跟insert功能相似,不一樣點在於:replace into首先嚐試插入數據列表中,若是發現表中已經有此行數據(根據主鍵或惟一索引判斷)則先刪除,再插入。不然直接插入新數據。html
首先表結構以下所示mysql
create table t_test(
id bigint(20) unsigned not null auto_increment PRIMARY KEY,
stub char(1) not null default '',
unique key stub (stub)
)
複製代碼
而後咱們插入的sql語句和查詢的語句以下所示算法
replace into t_test (stub) values('b');
select last_insert_id();
複製代碼
此時能夠看到看到咱們剛剛插入的id值是1 sql
既然是分佈式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,以下圖所示 segmentfault
那數據庫自增ID機制適合做分佈式ID嗎?答案是不太適合,爲何呢,我總結了下面兩個緣由:併發
1:系統水平擴展比較困難,好比定義好了步長和機器臺數以後,若是要添加機器該怎麼作?假設如今只有一臺機器發號是1,2,3,4,5(步長是1),這個時候須要擴容機器一臺。能夠這樣作:把第二臺機器的初始值設置得比第一臺超過不少,好比14(注意這裏設置14的前提是:在擴容期間第一臺機器的ID不可能增長到14),同時設置步長爲2,那麼這臺機器下發的號碼都是14之後的偶數。而後把第一臺機器的ID值保留爲奇數,好比7,而後修改第一臺的步長爲2。讓它符合咱們定義的號段標準。擴容方案看起來複雜嗎?貌似還好,如今想象一下若是咱們線上有100臺機器,這個時候要擴容該怎麼作?簡直是噩夢。因此係統水平擴展方案複雜難以實現。 2:數據庫壓力仍是很大,每次獲取ID都得讀寫一次數據庫,很是影響性能,不符合分佈式ID裏面的延遲低和要高QPS的規則(在高併發下,若是都去數據庫裏面獲取id,那是很是影響性能的)分佈式
原文連接函數
其餘分佈式ID系列快捷鍵:高併發
分佈式ID系列(1)——爲何須要分佈式ID以及分佈式ID的業務需求
分佈式ID系列(3)——數據庫自增ID機制適合作分佈式ID嗎
分佈式ID系列(4)——Redis集羣實現的分佈式ID適合作分佈式ID嗎
分佈式ID系列(5)——Twitter的雪法算法Snowflake適合作分佈式ID嗎
大佬網址