'用單庫自增鍵來生成id了,後期怎麼分庫?'

算法 數據庫 技術 設計 物理 Java從算法到架構 2019-08-17
"
"
用單庫自增鍵來生成id了,後期怎麼分庫?

應該有不少公司都會利用數據庫“插入數據自動自增id”來作為業務id,這種方法會使得業務與id生成強耦合,導致id生成算法難以升級。

今天和大家一起簡單探討下,id生成要考慮哪些要素。

畫外音:別誤會,不是說“自增id”不好,是說它與業務耦合了,難以升級。

一、id生成要考慮的技術點

幾乎所有業務,都會有一個業務唯一標識:

  • 用戶標識:uid(user-id)
  • 消息標識:mid(msg-id)
  • 訂單標識:oid(order-id)

這個標識,在存儲系統裡通常是主鍵,主鍵使用聚集索引(clustered-index),即在物理存儲上以這個id排序。於是,對這個id有:唯一性趨勢遞增性的要求。

這個標識,也經常被用來做流量負載均衡,數據負載均衡的依據,即這個id必須在統計上必須是完全隨機的。於是,對這個id有:隨機性的要求。

同時,id生成算法升級,理論上對業務系統是透明的。於是,對這個id的生成有:獨立性需求。

為了保證id生成的上述特性,要有一個:

uint64_t GenID()

的獨立方法(或者獨立接口)來生成id,生成id具體做什麼用,該方法不關心,可以是用來做uid,也可以是用來做oid,甚至log-id。

當然,id生成的具體細節,業務也不用關心。即,GenID()的內部實現,可以是利用數據庫的自增id,也可以使用時間遞增,目前行業內最流行的,是仿照snowflake生成分佈式id。

這個封裝,屏蔽了id生成的細節,保留方案升級的可能性,是系統設計中,解耦的體現。

如果使用了此類方法生成業務id,數據庫由單庫擴展多庫就很容易了:

(1)確定一個路由算法,例如hash取模;

(2)將單庫中的數據,通過這個路由算法遷移到多庫中去,以實現單庫數據量的減少;

(3)通過這個路由算法尋找數據(讀);

(4)通過這個路由算法插入數據(寫);

假如架構設計前期沒有提前考慮獨立的id生成,後期又要實施單庫拆多庫,該怎麼辦呢?

歷史的坑已經鑄成,沒有解耦id生成方法,而且也沒法批量修改id,該怎麼辦呢?

假設由單庫拆分為3庫,可以這麼玩:

(1)做一個1主2從數據庫集群,相當於每條數據複製成了3份;

(2)將路由算法,設為取模hash算法,%3;

(3)第一個庫,%3=0,把餘1和餘2的uid刪掉;

(4)第二個庫,%3=1,把餘0和餘2的uid刪掉;

(5)第三個庫,%3=2,把餘0和餘1的uid刪掉;

(6)將每個庫的自增步長設置為3,這樣每個庫的id生成就不會重複了;

(7)升級用戶中心,按照路由算法查詢uid數據;

搞定,拆庫擴容達成:

(1)單庫數據量下降為了原來的1/3;

(2)讀寫實例個數擴充為了原來的3倍;

(3)並且id生成與查詢都不會衝突;

希望這個取巧的方法對你有幫助。

但更希望,大夥提前考慮id生成的唯一性、隨機性、趨勢遞增性、獨立性。

"

相關推薦

推薦中...