「分庫分表" ?選型和流程要慎重,不然會失控

更多文章關注微信公衆號《小姐姐味道》 mp.weixin.qq.com/s?__biz=MzA…java

數據庫中間件之分庫分表

恭喜你,貴公司終於成長到必定規模,須要考慮高可用,甚至分庫分表了。但你是否知道分庫分表須要哪些要素?拆分過程是複雜的,提早計劃,不要等真正開工,各類意外的工做接踵而至,以致失控。mysql

本文意圖打開數據庫中間件的廣度,而不考慮實現深度,至於庫表垂直和水平分的概念和原因,不作過多解釋。因此此文面向的是有必定研發經驗,正在尋找選型和拆分流程的專業人士。sql

切入層次

如下,範圍界定在JAVAMySQL中。咱們首先來看一下分庫分表切入的層次。 數據庫

① 編碼層

在同一個項目中建立多個數據源,採用if else的方式,直接根據條件在代碼中路由。Spring中有動態切換數據源的抽象類,具體參見 AbstractRoutingDataSource編程

若是項目不是很龐大,使用這種方式可以快速的進行分庫。但缺點也是顯而易見的,須要編寫大量的代碼,照顧到每一個分支。當涉及跨庫查詢、聚合,須要循環計算結果併合並的場景,工做量巨大。後端

若是項目裂變,此類代碼大多不能共用,大多經過拷貝共享。久而久之,碼將不碼。安全

② 框架層

這種狀況適合公司ORM框架統一的狀況,但在不少狀況下不太現實。主要是修改或加強現有ORM框架的功能,在SQL中增長一些自定義原語或者hint來實現。微信

經過實現一些攔截器(好比MybatisInterceptor接口),增長一些自定義解析來控制數據的流向,效果雖然較好,但會改變一些現有的編程經驗。架構

不少狀況要修改框架源碼,不推薦。框架

③ 驅動層

基於在編碼層和框架層切入的各類缺點,真正的數據庫中間件起碼要從驅動層開始。什麼意思呢?其實就是從新編寫了一個JDBC的驅動,在內存中維護一個路由列表,而後將請求轉發到真正的數據庫鏈接中。

TDDLShardingJDBC等,都是在此層切入。

包括Mysql Connector/J的Failover協議 (具體指「load balancing」、「replication」、「farbic」等), 也是直接在驅動上進行修改。

請求流向通常是這樣的:

④ 代理層

代理層的數據庫中間件,將本身假裝成一個數據庫,接受業務端的連接。而後負載業務端的請求,解析或者轉發到真正的數據庫中。

MySQL RouterMyCat等,都是在此層切入。

請求流向通常是這樣的:

⑤ 實現層

SQL特殊版本支持,如Mysql cluster自己就支持各類特性,mariadb galera cluster支持對等雙主,Greenplum支持分片等。

須要換存儲,通常是解決方案,就不在討論之列了。

技術最終都會趨於一致,選擇任何一種、都是可行的。但最終選型,受開發人員熟悉度、社區活躍度、公司切合度、官方維護度、擴展性,以及公司現有的數據庫產品等多方位因素影響。選擇或開發一款合適的,小夥伴們會幸福不少。

驅動層和代理層對比

經過以上層次描述,很明顯,咱們選擇或開發中間件,就集中在驅動層和代理層。在這兩層,可以對數據庫鏈接和路由進行更強的控制和更細緻的管理。但它們的區別也是明顯的。

驅動層特色

僅支持JAVA,支持豐富的DB

驅動層中間件僅支持Java一種開發語言,但支持全部後端關係型數據庫。若是你的開發語言固定,後端數據源類型豐富,推薦使用此方案。

佔用較多的數據庫鏈接

驅動層中間件要維護不少數據庫鏈接。好比一個分了10個 的表,每一個java中的Connection要維護10個數據庫鏈接。若是項目過多,則會出現鏈接爆炸(咱們算一下,若是每一個項目6個實例,鏈接池中minIdle等於5,3個項目的鏈接總數是 10*6*5*3 = 900 個)。像Postgres這種每一個鏈接對應一個進程的數據庫,壓力會很大。

數據聚合在業務實例執行

數據聚合,好比count sum等,是經過屢次查詢,而後在業務實例的內存中進行聚合。

路由表存在於業務方實例內存中,經過輪詢或者被動通知的途徑更新路由表便可。

集中式管理

全部集羣的配置管理都集中在一個地方,運維負擔小,DBA便可完成相關操做。

典型實現

代理層特色

異構支持,DB支持有限

代理層中間件正好相反。僅支持一種後端關係型數據庫,但支持多種開發語言。若是你的系統是異構的,而且都有一樣的SLA要求,則推薦使用此方案。

運維負擔大

代理層須要維護數據庫鏈接數量有限(MySQL Router那種粘性鏈接除外)。但做爲一個獨立的服務,既要考慮單獨部署,又要考慮高可用,會增長不少額外節點,更別提用了影子節點的公司了。 另外,代理層是請求惟一的入口,穩定性要求極高,一旦有高耗內存的聚合查詢把節點搞崩潰了,都是災難性的事故。

典型實現

共同點

篇幅有限,不作過多討論。訪問各中間件宣傳頁面,可以看到長長的Feature列表,也就是白名單;也能看到長長的限制列表,也就是黑名單。限定了你怎麼玩,在加強了分佈式能力後,分庫分表自己就是一個閹割的數據庫。

使用限制

確保數據均衡 拆分數據庫的數據儘可能均勻,好比按省份分user庫不均勻,按userid取模會比較均勻 不用深分頁 不帶切分鍵的深分頁,會取出全部庫所取頁數以前的全部數據在內存排序計算。容易形成內存溢出。 減小子查詢 子查詢會形成SQL解析紊亂,解析錯誤的狀況,儘可能減小SQL的子查詢。 事務最小原則 儘可能縮小單機事務涉及的庫範圍,即儘量減小誇庫操做,將同類操做的庫/表分在一塊兒 數據均衡原則 拆分數據庫的數據儘可能均勻,好比按省份分user庫不均勻,按userid取模會比較均勻 特殊函數 distinct、having、union、in、or等,通常不被支持。或者被支持,使用以後會增長風險,須要改造。

產品

建議聚焦在MyCatShardingJDBC上。另外,還有大量其餘的中間件,不熟悉建議不要妄動。 數據庫中間件很差維護,你會發現大量半死不活的項目。

如下列表,排名不分前後,有幾個是隻有HA功能,沒有拆分功能的:

Atlas、Kingshard、DBProxy、mysql router、MaxScale、58 Oceanus、ArkProxy、Ctrip DAL、Tsharding、Youtube vitess、網易DDB、Heisenberg、proxysql、Mango、DDAL、Datahekr、MTAtlas、MTDDL、Zebra、Cobar、Cobar

汗、幾乎每一個大廠都有本身的數據庫中間件(還發現了幾個喜歡拿開源組件加公司前綴做爲產品的),只不過不給咱用罷了。

流程解決方案

不管是採用哪一個層面切入進行分庫分表,都面臨如下工做過程。

信息收集

統計影響的業務和項目

項目範圍越大,分庫難度越高。有時候,一句複雜的SQL可以涉及四五個業務方,這種SQL都是須要重點關注的。

肯定分庫分表的規模,是隻分其中的幾張表,仍是所有涉及。分的越多,工做量越大,幾乎是線性的。

還有一些項目是牽一髮動全身的。舉個例子,下面這個過程,影響的鏈路就不只是分庫這麼簡單了。

肯定參與人員

除了分庫分表組件的技術支持人員,最應該參與的是對系統、對現有代碼最熟悉的幾我的。只有他們可以肯定哪些SQL該廢棄掉、SQL的影響面等。

肯定分庫分表策略

肯定分庫分表的維度和切分鍵。切分鍵(就是路由數據的column)一旦肯定,是不容許修改的,因此在前期架構設計上,應該首先將其確立下來,才能進行後續的工做;數據維度多意味着有不一樣的切分鍵,達到不一樣條件查詢的效果。這涉及到數據的冗餘(多寫、數據同步),會更加複雜。

前期準備

數據規整

庫表結構不知足需求,須要提早規整。好比,切分鍵的字段名稱不一樣或者類型各異。在實施分庫分表策略時,這些個性會形成策略過大很差維護。

掃描全部SQL

將項目中全部的SQL掃描出來,逐個判斷是否可以按照切分鍵正常運行。 在判斷過程當中確定會有大量不合規的SQL,則都須要給出改造方案,這是主要的工做量之一。

驗證工具支持

直接在原有項目上進行改動和驗證是可行的,但會遇到諸多問題,主要是效率過低。我傾向於首先設計一些驗證工具,輸入要驗證的SQL或者列表,而後打印路由信息和結果進行判斷。

技術準備

建議如下提到的各個點,都找一個例子體驗一下,而後根據本身的團隊預估難度。

如下: 中間件全部不支持的SQL類型 整理容易形成崩潰的注意事項 不支持的SQL給出處理方式 考慮一個通用的主鍵生成器 考慮沒有切分鍵的SQL如何處理 考慮定時任務等掃全庫的如何進行遍歷 考慮跨庫跨表查詢如何改造 準備一些工具集

實施階段

數據遷移

分庫分表會從新影響數據的分佈,不管是全量仍是增量,都會涉及到數據遷移,因此Databus是必要的。

一種理想的狀態是全部的增刪改都是消息,能夠經過訂閱MQ進行雙寫。

但通常狀況下,仍然須要去模擬這個狀態,好比使用Canal組件。

怎麼保證數據安全的切換,咱們分其餘章節進行討論。

充足的測試

分庫分表必須通過充足的測試,每一句SQL都要通過嚴格的驗證。若是有單元測試或者自動化測試工具,徹底的覆蓋是必要的。一旦有數據進行了錯誤的路由,尤爲是增刪改,將會創造大量的麻煩。

在測試階段,將驗證過程輸出到單獨的日誌文件,充足測試後review日誌文件是否有錯誤的數據流向。

SQL複驗

強烈建議統一進行一次SQL複驗。主要是根據功能描述,肯定SQL的正確性,也就是一般說的review。

演練

在非線上環境屢次對方案進行演練,確保萬無一失。

制定新的SQL規範

分庫分表之後,項目中的SQL就加了枷鎖,不可以隨意書寫了。不少日常支持的操做,在拆分環境下就可能運行不了了。因此在上線前,涉及的SQL都應該有一個確認過程,即便已經通過了充足的測試。

題外話

沒有支持的活別接,幹不成。

分庫分表是戰略性的技術方案,不少狀況沒法回退或者回退方案複雜。若是要拆分的庫表涉及多個業務方,公司技術人員複雜,CTO要親自掛帥進行協調,並有專業仔細的架構師進行監督。沒有受權的協調人員會陷入尷尬的境地,致使流程失控項目難產。

真正經歷過的人,會知道它的痛!

相關文章
相關標籤/搜索