1. 程式人生 > >資料庫分散式架構——分庫分表

資料庫分散式架構——分庫分表

資料庫分散式,其核心內容無非就是資料切分(Sharding),以及切分後對資料的定位、整合工作,解決單一資料庫或資料表因資料量過大而導致的效能瓶頸問題。這裡有必要再做一個澄清,本文談的資料庫分散式並非分散式資料庫,前者不關注資料細節的儲存組織問題,而是仍然在已有的MySQL、ORACLE等成熟資料庫系統基礎上進行的一系列資料操作排程。後者分散式資料庫則是集資料儲存、管理以及分散式協調與計算為一體的資料庫系統,目前尚無特別成熟的商用產品。

資料切分就是把資料分散存放到多個數據庫或多個表中,使得單臺主機中的資料量變小,使得通過擴充主機數量即可提升資料庫操作效能的目的。

資料切分可分為縱向和橫向兩種切分方法。縱向切分就是根據業務耦合性,將關聯度低的不同表獨立建成不同的資料庫。如下圖所示:

縱向切分相對簡單,做法與我們將一個大的系統拆分成幾個小系統的做法相似,就是根據業務分類進行獨立劃分應用或資料庫。

然而當一個應用已經難以再進一步拆分時,或者拆分後資料行數巨大時,我們就還需要進行橫向切分(即:將單個表的記錄數變小)。橫向切分是根據表內資料的邏輯關係,將同一個表按不同的條件拆分到多個數據庫或多個表中。

preview

如上圖所示,橫向切分後同一張表同時出現在多個數據庫中,每個庫的資料內容不同,如何設定資料記錄的切分規則是最重要考量。一旦確定切分規則,應用對該表的操作原則基本就已確定。假設我們將Customer表根據cus_no欄位來切分到4個庫,如果我們所有查詢條件都帶有cus_no欄位則可明確定位到相應庫去查詢,但如果我們頻繁用到的查詢條件中不帶cus_no時,將會導致無法定位資料庫,從而需要同時向4個庫發起查詢,最後再合併資料、取最小集返回給應用,導致分庫優勢反而可能成為你的拖累。下圖我們示意一個分表過程:

行文至此,分庫分表的基本思路應該明瞭,緊接著有一籮筐的棘手問題還需要處理:

一、關聯查詢問題

資料切分後一大難題就是關聯查詢,跨庫關聯查詢的想法最好打消掉,目前沒有好的解決方案。簡單一些的辦法就是根據E-R圖來切分,將同一族的資料都存放在本地庫內,這樣將跨庫資料關聯變成跨庫資料拼接。

preview

基於上述表間關係,同一客戶的賬戶及賬戶的餘額都在同一庫,當查詢條件未使用切分欄位時,則將向4個庫分別發起查詢,以得到全部結果。

若希望查詢某一客戶的所有賬戶及餘額時,將根據切分欄位CUS_ID值直接定位到DB1庫查詢。

二、分頁查詢問題

正如前面提到的分庫並行查詢時,若需要分頁查詢則將出現悲劇,每個庫返回的結果集本身是無序的,無法確定應該如何返回資料給使用者。目前像MyCat這類中介軟體要求分頁查詢時必須帶上ORDER BY欄位,好使得多庫查詢結果全部出來後,再在記憶體中根據排序欄位單獨進行排序,最後返回最小結果集。可以想像,當查詢的總結果集過大時,這一排序過程對資源和時間的消耗相當可觀。

三、事務一致性問題

當我們需要更新的內容同時分佈在不同庫時,不可避免會帶來跨庫事務問題,在JavaEE體系下使用XA事務進行協調解決,但XA事務目前也並非完全安全,在最後確認提交這一步若某個庫失敗時,並不能確保所有庫都能成功roolback。目前針對此種情況尚無簡單的方案,需要採用日誌分析、事後補償的方式來解決,以達到網際網路類系統宣稱的“最終一致性”。

四、主鍵避重問題

由於表同時存在於多個數據庫內,主鍵值我們平時常用的自增序列將無用武之地,因此需要單獨設計全域性主鍵,以避免跨庫主鍵重複問題。

五、公共表問題

前方主要談分表相關的內容,實際應用中大量的引數表、產品表等都資料量較小,而且屬於高頻聯合查詢的依賴表,這類表的所有資料都需要同時出現在各個庫中。

一種辦法就是我們對公共表的所有更新操作都同時傳送到所有分庫執行,然後指定一個主庫,若主庫成功我們就認為操作成功,然後再定期對其它庫的資料進行同步操作。

 

上面所列的五大問題只是我們從巨集觀層面所看到的,還有許多實操環節的細節問題、分散式資料庫中介軟體自身侷限問題,例如SQL阻塞、死鎖等導致全庫無法工作等都會存在,特別是在主從模式下帶來的資料不一致等問題。一旦你選擇了資料切分,這些問題便接踵而來,如何構建相應的資料修復機制、避免全域性故障等問題將伴隨整個應用生命週期。

最後來點個人意見,作為我等傳統銀行,在非關鍵業務應用中可以嘗試,原則上能不分表就不分表。我願意相信,在資料膨脹的時代驅動下,成熟的商業化分散式資料庫問世的時間將不會太久,像傳統銀行核心這類系統不妨等等看。

轉自知乎連結:https://zhuanlan.zhihu.com/p/27871998