Mysql 擴展性設計之數據切分、那麼數據切分後會帶來哪些問題呢?比如分佈式事務、數據的一致性、垂直切分和水平切分應用場景

前言、什麼是數據切分

數據的切分(Sharding)根據切分的類型,可以分爲兩種切分模式

  • 第一種是按照不同的表(或者schema)來切分到不同的數據庫上,稱之爲數據的垂直(縱向)切分
  • 另一種是根據表中的數據邏輯的關係、將同一個表中的數據按照某種條件拆分到多臺數據庫上,稱之爲水平(橫向)切分

垂直(縱向)切分、水平(橫向)切分、他們各自的特點

垂直切分

最大的特點就是規則簡單、實施也方便、尤其適合業務之間的耦合度低、相互影響小、業務邏輯清晰的系統。在這種系統中,可以很容易做到將不同業務模塊所使用的表拆分到不同數據庫中,根據不同的表來拆分,對應用程序的影響也會更小,拆分規則也會相對來說比較簡單

水平切分

水平切分相比垂直切分,顯得稍微複雜一些,因爲需要將同一個表中的不同數據拆分到不同數據庫中,對於應用程序來說,拆分的規則本身就根據表名來拆分更爲複雜、後期的數據維護也會更爲複雜一些

聯合使用解決方案

當我們某個表的數據量和訪問量特別大的,通過垂直拆分將其放在獨立的設備上之後仍無法滿足性能要求時,這時我們就必須將垂直切分和水平切分相結合,先垂直切分,在水平切分,才能解決這種超大型表的性能問題。

垂直切分的具體分析、詳解、結合案例

將數據庫想象成爲由很多個一大塊一大塊的“數據塊(表)組成,我們垂直的將這些“數據塊”切開,然後將他們分散到多臺數據庫主機上面。
通俗來講就是講一張大表拆分成多個小表、減少單表的數據量過大、通過拆分Schema、減少不必要的字段查詢。

具體分析

一個架構設計比較完善的應用,總體功能模塊是有很多模塊組成的,而每一個功能模塊所需要的數據對應到數據庫就是一個個表。而在架構設計中,各個功能模塊相互之間的交互點越少越好,系統的耦合度就越低,系統各個模塊的維護,這樣各個模塊的維護性及擴展性就越好,這樣呢,實現數據的垂直切分就更容易。
當我們的功能模塊越清晰,耦合度越低,數據垂直切分的規則定義也就越容易。完全可以根據功能模塊來進行數據的切分,不同功能模塊的數據存放於不同的數據庫主機中,可以很容易就避免掉跨數據庫的 Join 存在,同時系統架構也非常的清晰。

當然有時,很難有系統能夠做到所有功能模塊所使用的表完全獨立,完全不需要訪問對方的表或者需要兩個模塊的表進行 Join 操作。這種情況下,我們就必須根據實際的應用場景進行評估權衡。決定是遷就應用程序將需要 Join 的表的相關某快都存放在同一個數據庫中,還是讓應用程序做更多的事情,也就是程序完全通過模塊接口取得不同數據庫中的數據,然後在程序中完成 merger操作。

經驗之談

根據筆者的經驗、一般來說,如果是一個負載相對不是很大的系統,而且表關聯又非常的頻繁,那可能數據庫讓步,將幾個相關模塊合併在一起減少應用程序的工作的方案,可以減少較多的工作量,是一個可行的方案。

當然,通過數據庫的讓步,讓多個模塊集中共用數據源,實際上也是簡介的默許了各模塊架構耦合度增大的發展,可能會讓以後的架構越來越惡化。尤其是當發展到一定階段之後 ,發現數據庫實在無法承擔這些表所帶來的壓力,不得不面臨再次切分的時候,所帶來的架構改造成本可能會遠遠大於最初的時候。

所以,在數據庫進行垂直切分的時候,如何切分,切分到什麼樣的程度,是一個比較考驗人的難題。只能在實際的應用場景中通過平衡各方面的成本和收益,才能分析出一個真正適合自己的拆分方案。

結合案例解剖

案例背景

某個系統功能可以基本分爲四個功能模塊:用戶,羣組消息,相冊以及事件,分別對應爲如下這些表:

  1. 用戶模塊表:user,user_profile,user_group,user_photo_album
  2. 羣組討論表:groups,group_message,group_message_content,top_message
  3. 相冊相關表:photo,photo_album,photo_album_relation,photo_comment
  4. 事件信息表:event

分析

  • 羣組討論模塊和用戶模塊之間主要存在通過用戶或者是羣組關係來進行關聯。一般關聯的時候都會是通過用戶的 id 或者 nick_name 以及 group 的 id 來進行關聯,通過模塊之間的接口實現不會帶來太多麻煩;
  • 相冊模塊僅僅與用戶模塊存在通過用戶的關聯。這兩個模塊之間的關聯基本就有通過用戶 id關聯的內容,簡單清晰,接口明確;
  • 事件模塊與各個模塊可能都有關聯,但是都只關注其各個模塊中對象的 ID 信 息 ,同樣可以做到很容易分拆。

剖析

可以將數據庫按照功能模塊相關的表進行一次垂直拆分,每個模塊所涉及的表單獨到一個數據庫中,模塊與模塊之間的表關聯都在應用系統端通過藉口來處理,如下圖
圖片替換文本
通過這樣的垂直切分之後,之前只能通過一個數據庫來提供的服務,就被分拆成四個數據庫來提供服務,服務能力自然是增加幾倍了。

垂直切分的優點

  • 數據庫的拆分簡單明瞭,拆分規則明確
  • 應用程序模塊清晰明確,整合容易
  • 數據維護方便易行,容易定位

垂直切分的缺點

  • 部分表關聯無法在數據庫級別完成,需要在程序中完成
  • 對於訪問極其頻繁且數據量超大的表仍然存在性能平靜,不一定能滿足要求
  • 事務處理相對更爲複雜
  • 切分達到一定程度之後,擴展性會遇到限制
  • 過讀切分可能會帶來系統過渡複雜而難以維護

不足之處

針對於垂直切分可能遇到數據切分及事務問題,在數據庫層面實在是很難找到一個較好的處理方案。

水平切分

一般來說,簡單的水平切分主要是將某個訪問極其平凡的表再按照某個字段的某種規則來分散到多個表之中,每個表中包含一部分數據。
簡單來說,我們可以將數據的水平切分理解爲是按照數據行的切分,就是將表中的某些行切分到一個數據庫,而另外的某些行又切分到其他的數據庫中。當然,爲了能夠比較容易的判定各行數據被切分到哪個數據庫中了,切分總是都需要按照某種特定的規則來進行的。
如根據某個數字類型字段基於特定數目取模,某個時間類型字段的範圍,或者是某個字符類型字段的 hash 值。如果整個系統中大部分核心表都可以通過某個字段來進行關聯,那這個字段自然是一個進行水平分區的上上之選了,當然,非常特殊無法使用就只能另選其他了。

水平切分的優點

  • 表關聯基本能夠在數據庫端全部完成
  • 不會存在某些超大型數據量和高負載的表遇到瓶頸的問題
  • 應用程序端整體架構改動相對較少
  • 事務處理相對簡單
  • 只要切分規則能夠定義好,基本上較難遇到擴展性限制

水平切分的缺點

  • 切分規則相對更爲複雜,很難抽象出一個能夠滿足整個數據庫的切分規則
  • 後期數據的維護難度有所增加,人爲手工定位數據更困難
  • 應用系統各模塊耦合度較高,可能會對後面數據的遷移拆分造成一定的困難

垂直與水平 相結合(聯合使用)

上面我們對垂直切分和水平切分有了一定的瞭解。同時也說了他們各自的優缺點、及應用場景,但是我們在實際的場景中、沒有辦法使用一種切分的方法來提供性能、和擴展性、在不同的業務場景下使用不同的切分方法。
一般來說隨着業務的發展、在遇到瓶頸時、首先會進行數據的垂直切分、因爲這樣成本最小、服務當前的業務發展狀況、通俗講投入產出比吧,然而隨着業務的不斷擴張、負載和數據量也是持續增長、在穩定一段時期之後,再對數據水平切分。

實際上,在很多大型的系統中,垂直切分和水平切分基本上都是並行存在的,而且是經常在不斷交替進行、以不斷增加系統的擴展力,當然聯合使用也存在一定程度上的優劣使。

聯合切分的優點
  • 可以充分利用垂直切分和水平切分各自的優勢而避免各自的缺陷
  • 讓系統擴展性得到最大化提升
聯合切分的缺點
  • 數據庫系統架構比較複雜,維護難度更大
  • 應用程序架構也相對更復雜

數據切分及切分之後的數據整合方案

總的來說,存在兩種解決思路:

  • 在每個應用程序模塊中配置管理自己需要的一個(或者多個)數據源,直接訪問各個數據庫,在模塊內完成數據的整合
  • 通過中間代理層來統一管理所有的數據源,後端數據庫集羣對前端應用程序透明
    可能90%人的都會採用第二種(中間代理層)解決方案。也是一個正確的解決方案。

簡單介紹中間代理層都有哪些,

  • 利用 MySQL Proxy 實現數據切分及整合
  • 利用 Amoeba 實現數據切分及整合
  • 利用 HiveDB 實現數據切分及整合
  • 阿里雲的DRDS 產品
  • Mycat 中間件 零侵入
  • 噹噹的sharding jdbc 中間件

數據切分與整合的遺留問題

  • 引入分佈式事務的問題
    • 對應的解決方案:Seata https://github.com/seata/seata
  • 跨節點 Join 的問題
    • sharding jdbc 、drds 都支持的
  • 跨節點合併排序分頁問題
    • sharding jdbc 、drds 都支持的

總結、敲黑板、劃重點

  • 對垂直切分、一般情況下大表拆分小表
  • 對水平切分
    • 分表的策略、常用:hash取模,日期
    • 一旦水平切分之後、後期的擴展就比較麻煩、大部分情況下都是按照Hash取模。所以,前期一定要規劃好,未來一到兩年數據量、比如,單表的月增長量、保證業務在未來一到兩年數據量能滿足。
    • 規劃時,儘可能保證單表500萬左右的數據量、非核心業務可以稍微大點
    • 分庫一般情況下也是hash 形式來進行
  • 架構設計、儘可能保證to c 業務單表查詢、便於管理和維護、後期有利於加緩存、或者join 不超過三個、可以前期結合緩存使用
  • 目前大部分雲產品DRDS、sharding jdbc 分庫分表都是支持不按照分庫或分表條件查詢、比如分頁或者做排序,這些都是支持,但是性能比較慢,原因是:會在中間代理層把所有的表進行挨個查詢、在內存做Merger,性能比較差。對於業務後臺或者內部系統,可以使用OLAP型數據庫進行統計查詢、比如:阿里雲的ADB、可以通過DTS進行遷移
  • 目前大部分設計都是微服務、所以建議單個服務對應單個庫、減低耦合、避免多個服務共享數據源、一旦業務起量、需要拆分時,不利於擴展性、另外單庫的連接數也不夠用、微服務肯定每個服務都有對應的連接池、當然還可以通過數據中間件,例如:mycat
  • 分庫分表之後帶來分佈式事務問題
    • 如果保證數據的一致性,一般分爲弱一致性、強一致性、最終一致性,
      • CAP原理中,有三個要素:
        • 一致性(Consistency)
        • 可用性(Availability)
        • 分區容忍性(Partition tolerance)
    • 一般來說使用分佈式事務框架對性能必定產生一定的影響,建議根據業務情況對數據一致性做不同的處理,做到最終一致性即可、比如:通過MQ、或者Seata

常見問題答疑

一張表多少數據量合適?
  • 單表500萬吧,非核心業務可以更多、另外還看成本
一般分幾張表合適?
  • 根據單表的數據、估算未來一到兩年的數據量、來算分多少張表合適
分庫分表之後事務如果保證?
  • 比如:通過MQ來最終一致性、或者Seata框架來做,對性能有一定的影響、根據業務情況對數據一致性做不同的處理,做到最終一致性即可
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章