主從同步、讀寫分離、分庫分表及Sharding Sphere

1. 主從同步

Mysql 5.0之後,支持經過binary log(二進制日誌)以支持主從複製。複製容許未來自一個MySQL數據庫服務器(master)的數據複製到一個或多個其餘MySQL數據庫服務器(slave),以實現熱備份、讀寫分離、水平擴展、統計分析、遠程數據分發等功能。二進制日誌中存儲的內容稱之爲事件,每個數據庫更新操做(Insert、Update、Delete,不包括Select)等都對應一個事件html

                                  â€œMySQL基于binlog主从复制”的图片搜索结果

                                                  圖-MySQL基於binlog主從複製mysql

主要分爲3個步驟:
第一步:master在每次準備提交事務完成數據更新前,將改變記錄到二進制日誌(binary log)中(這些記錄叫作二進制日誌事件,binary log event,簡稱event)
第二步:slave啓動一個I/O線程來讀取主庫上binary log中的事件,並記錄到slave本身的中繼日誌(relay log)中;
第三步:slave還會起動一個SQL線程,該線程從relay log中讀取事件並在備庫執行,從而實現備庫數據的更新。spring

1.1 主從同步須要解決的問題

1.1.1 主從延遲問題

因爲網絡延遲、機器性能、大事務、鎖、MySQL參數設置等存在的問題,可能使得主從數據存在延遲,須要考慮好應該在什麼場景下來用MySQL主從同步,建議是通常在讀遠遠多於寫,並且讀的時候通常對數據時效性要求沒有那麼高,採用主從同步。解決的具體作法有:優化MySQL配置參數、分庫、並行複製、強一致性業務強制路由主庫。具體作法能夠參考:簡書-mysql讀寫分離和解決主從同步延時問題掘金-mysql同步(複製)延遲的緣由及解決方案CSDN-完全終結MySQL同步延遲問題sql

1.1.2 主庫數據丟失問題

MySQL複製默認是異步的,主庫寫入事務在生成Events並寫入到Binlog文件以後,寫入線程是不等待的,或者能夠說主庫並不知道從庫是否是已經收到或處理了這些Binlog。在這種狀況下,若是主庫掛了,有可能沒有任何一個從庫能夠收到已經在主庫提交的事務,而此時若是高可用架構將業務從主庫切換到了從庫,則可能會致使從庫丟失主庫上面發生的不少修改。數據庫

如何解決?能夠採用半同步複製策略,是介於全同步複製與全異步複製之間的一種,主庫只須要等待至少一個從庫節點收到Flush Binlog到Relay Log文件便可,主庫不須要等待全部從庫給主庫反饋,同時這裏只是一個收到的反饋,而不是已經徹底執行而且提交的反饋,這樣就節省了不少時間。具體過程能夠參考:高效開發運維-MySQL半同步複製apache

2. 讀寫分離

經過數據冗餘將數據庫讀寫操做分散到不一樣的節點上,數據庫主機經過主從同步將數據複製到從機,每臺數據庫服務器都存儲了全部的業務數據,其中主機負責寫操做,從機負責讀操做。適合併發量大,讀遠大於寫的場景,數據實時性不那麼嚴格的業務。通常經過上述binlog複製來實現,所以存在上述延遲問題。緩存

如何將讀寫操做區分開來,而後訪問不一樣的數據庫服務器?通常有客戶端代碼封裝實現,如Sharding-JDBC、TDDL和服務端中間件封裝如Cobar、MyCat兩種。具體分析能夠參考:芋道源碼-淺談高性能數據庫集羣——讀寫分離安全

3. 分庫分表

常見的作法有如下幾種:服務器

  • 垂直分表,即「大表拆小表」,拆分是基於關係型數據庫中的「列」(字段)進行的。一般狀況,某個表中的字段比較多,能夠新創建一張「擴展表」,將不常用或者長度較大的字段拆分出去放到「擴展表」中,能夠避免跨頁形成的額外性能開銷;
  • 垂直分庫,基本的思路就是按照業務模塊來劃分出不一樣的數據庫,而不是像早期同樣將全部的數據表都放到同一個數據庫中;
  • 水平分表,橫向分表,就是將表中不一樣的數據行按照必定規律分佈到不一樣的數據庫表中(這些表保存在同一個數據庫中),這樣來下降單表數據量,優化查詢性能,最多見的方式就是經過主鍵或者時間等字段進行Hash和取模後拆分。
  • 水平分庫分表,水平分庫分表與上面講到的水平分表的思想相同,惟一不一樣的就是將這些拆分出來的表保存在不一樣的數據中。「冷熱數據分離」(將一些使用較少的歷史數據遷移到其餘的數據庫中,而在業務功能上,一般默認只提供熱點數據的查詢)也是相似的實踐。分庫分表可以有效緩解單機和單庫的性能瓶頸和壓力,突破IO、鏈接數、硬件資源的瓶頸。

3.1 什麼時候分庫分表

數據庫記錄數達到多少許級須要考慮分庫分表?阿里巴巴《Java開發手冊》推薦「單錶行數超過500萬行或者單表容量超過2GB,才推薦進行分庫分表,若是預計三年後的數據量根本達不到這個級別,請不要在建立表時就分庫分表」。事實上該數值的評估與MySQL的配置以及機器的硬件有關。具體分析能夠參考:佔小狼的博客-MySQL單表數據不要超過500萬行:是經驗數值,仍是?網絡

3.2 分庫分表須要解決的問題

3.2.1 跨庫join的問題

拆分後,數據庫多是分佈式在不一樣實例和不一樣的主機上,join將變得很是麻煩。並且基於架構規範,性能,安全性等方面考慮,通常是禁止跨庫join的。那該怎麼解決?

  • 全局表

所謂全局表,就是有可能系統中全部模塊均可能會依賴到的一些表。比較相似咱們理解的「數據字典」。爲了不跨庫join查詢,咱們能夠將這類表在其餘每一個數據庫中均保存一份。同時,這類數據一般也不多發生修改(甚至幾乎不會),因此也不用太擔憂「一致性」問題。

  • 字段冗餘

這是一種典型的反範式設計,在互聯網行業中比較常見,一般是爲了性能來避免join查詢。字段冗餘能帶來便利,是一種「空間換時間」的體現。但其適用場景也比較有限,比較適合依賴字段較少的狀況。最複雜的仍是數據一致性問題,這點很難保證,能夠藉助數據庫中的觸發器或者在業務代碼層面去保證。

  • 數據同步

例如A庫中的tab_a表和B庫中tbl_b有關聯,能夠定時將指定的表作同步。固然同步原本會對數據庫帶來必定的影響,須要性能影響和數據時效性中取得一個平衡,這樣來避免複雜的跨庫查詢,能夠經過ETL工具來實施。

  • 系統層組裝

在系統層面,經過調用不一樣模塊的組件或者服務,獲取到數據並進行字段拼裝。簡單字段組裝的狀況下,咱們只須要先獲取「主表」數據,而後再根據關聯關係,調用其餘模塊的組件或服務來獲取依賴的其餘字段(如例中依賴的用戶信息),最後將數據進行組裝。一般,咱們都會經過批量查詢以及緩存來避免頻繁RPC通訊和數據庫查詢的開銷。

3.2.2 跨庫事務(分佈式事務)的問題

按業務拆分數據庫以後,不可避免的就是「分佈式事務」的問題。以往在代碼中經過spring註解簡單配置就能實現事務的,如今則須要花很大的成本去保證一致性。具體解決方案參考:分佈式事務

3.2.3 數據遷移的問題

能夠參考:美團技術團隊-大衆點評訂單系統分庫分表實踐閒魚技術-21世紀了還愚公移山?數據庫這麼遷移更穩定!程序猿DD-推薦一個不錯的分庫分表實踐!

3.3 分庫分表實踐總結

能夠參考:

InfoQ-分庫分表的幾種常見形式以及可能遇到的難題

程序猿DD-推薦一個不錯的分庫分表實踐!

4. Sharding Sphere分佈式數據庫中間件

田守枝的技術博客-數據庫中間件詳解

Hollis-SpringBoot 2.x ShardingSphere分庫分表實戰

ShardingSphere官網

參考資料

匠心零度-MySQL binlog原來能夠這樣用?各類場景和原理剖析!

田守枝的技術博客-異地多活場景下的數據同步之道

開源中國-sharding-jdbc 事務支持部分觀後感

相關文章
相關標籤/搜索