文章目錄
- 一、分表分庫
- 1. 數據分表的必要性與方式
- 2. 數據分庫原則與優勢
- 二、主從復制
- 1. 讀寫分離架構設計
- 2. 數據復制方式
- 3. MySQL實現主從復制
- 4. MySQL主從復制實踐與高可用方案
- 三、數據擴容
隨著業務的不斷發展和數據量的增長,傳統的單機關系型數據庫已經逐漸不能滿足高效存儲和快速訪問的需求。在這種背景下,分布式數據庫存儲成為了解決這些問題的重要策略。通過分表分庫、主從復制以及數據擴容等技術,分布式數據庫可以提高存儲的可擴展性、性能和可靠性。接下來,我們將詳細介紹這些關鍵策略及其應用。
一、分表分庫
1. 數據分表的必要性與方式
在傳統數據庫中,隨著單表數據量的增加,操作數據庫時會產生巨大的開銷,導致系統效率降低。例如,在MySQL中,當單表記錄數過多時,插入數據時可能會對表加鎖,這會導致后續的請求排隊等待,從而影響系統的整體性能。為了解決這一問題,通常建議MySQL單表的記錄數控制在500萬條以內,但實際情況要根據具體的業務需求和硬件配置來決定。
為了應對數據量過大的問題,分表技術應運而生。分表的方式主要有兩種:垂直分表和水平分表。
-
垂直分表:將表中的字段根據業務需求拆分到不同的表中。例如,將不常用的字段或長字段拆分出來,這樣可以避免查詢時產生“跨頁”問題。此方法通常在數據庫設計的初期就進行。
-
水平分表:根據某個關鍵字段(如ID)進行Hash計算,將數據拆分到多個表中。例如,可以通過對ID取模的方式,將數據分配到不同的表中。除了ID外,還可以按時間、地域等標準進行分表。
然而,分表雖然帶來了性能提升,但也引入了跨表數據查詢、ID生成和事務處理等新問題。針對這些問題,有以下解決思路:
- 跨表數據的Join:可以在應用層進行多次查詢,并合并結果。
- 跨表數據生成ID:可以使用UUID或Sequence表來生成ID,但這些方式的效率和空間利用有時不盡如人意。大廠常用的snowflake算法(由Twitter開源)就是一種高效生成ID的方式。
- 跨表數據的排序和分頁:可以先對分表數據進行排序、分頁、聚合等操作,再合并數據進行進一步處理,或者先合并數據后再進行這些操作。
- 跨表事務處理:可以通過補償事務或采用TCC(Try-Confirm-Cancel)模式來保證跨表事務的一致性。
?
2. 數據分庫原則與優勢
在分表的基礎上,隨著數據量和請求量的不斷增長,單一數據庫的存儲能力和訪問能力已無法滿足需求,這時就需要采用分庫技術。分庫技術可以將數據庫按照一定的規則拆分到多個數據庫中,減輕單個數據庫的負擔。
分庫的常見原則有:
- 按業務分庫:根據不同的業務模塊將數據分到不同的數據庫中。例如,訂單數據、核算數據和評價數據可以分別存儲在不同的數據庫中。
- 按冷熱數據分庫:根據數據訪問頻率的不同,將高頻、中頻和低頻的數據分庫存儲。頻繁訪問的數據存儲在高性能數據庫中,減少訪問延遲。
- 按訪問地域或時間范圍分庫:根據地域或者時間來劃分數據存儲的數據庫。例如,可以將不同地區或不同時間段產生的數據分配到不同的數據庫中。
通過分庫,將多個數據庫組成集群,應用程序通過負載均衡代理來訪問這些數據庫,實現讀寫分離,極大地提高了數據庫的可用性。同時,分庫也便于進行健康監控、熔斷、選舉等機制的實施,從而保障數據庫系統的高可用性。
?
二、主從復制
1. 讀寫分離架構設計
在分布式數據庫中,為了提高數據庫的并發處理能力,通常會采用讀寫分離的架構。具體來說,數據庫的寫操作由主庫處理,讀操作由從庫來承擔。這樣,主庫和從庫之間就形成了一個分離的架構,從庫可以分擔主庫的讀請求壓力。當讀請求較多時,可以通過增加從庫來進一步擴展系統的讀性能。
?
2. 數據復制方式
為了保證主庫和從庫數據的一致性,需要對主庫的數據進行復制。數據復制可以分為同步和異步兩種方式:
-
同步數據復制:主庫在進行寫操作時,必須先將數據同步到從庫,確認從庫同步成功后,才會返回給用戶。這樣做能夠確保主從數據的一致性,但也會犧牲部分系統的可用性,因為寫操作需要等待同步完成。
-
異步數據復制:主庫在進行寫操作后,直接返回結果給用戶,數據復制則在后臺進行。雖然這樣可以提高系統的可用性,但也可能導致主從數據不一致的問題,尤其是在從庫還未同步完成時,應用讀取到的數據可能存在問題。
?
3. MySQL實現主從復制
以MySQL為例,MySQL的主從復制過程如下:
- 從庫的IO線程連接到主庫,獲取Binary Log的指定位置和偏移量。
- 主庫在數據更新時,將更新信息通知從庫。
- 從庫IO線程將這些更新信息存入relay Log,并記錄日志文件名和位置。
- 從庫的SQL線程解析relay Log內容,執行SQL語句,從而完成數據的同步。
MySQL支持兩種數據復制方式:Row Level和Statement Level。Row Level復制記錄每條數據的修改操作,能夠更精確地同步數據,但會增加日志的存儲和網絡傳輸負擔;而Statement Level復制記錄執行的SQL語句,相對節省空間和IO成本,但對主從數據庫版本的要求較高,建議主庫的版本低于從庫版本。
?
4. MySQL主從復制實踐與高可用方案
在實際應用中,為了實現高可用性,除了傳統的主從復制,還有主主復制(雙主模式)等方案。在主主模式下,兩個主服務器之間互為備份,通常會暴露一個虛擬IP(VIP),并根據服務器的健康狀態進行切換。也可以通過中間件如MyCat和ZooKeeper實現更高級的高可用性,ZooKeeper提供了選舉機制來選擇新的主服務器,從而確保系統的高可用性。
?
如下圖:MyCat 通過 ZooKeeper 對主節點 writeHost(負責寫入)和從節點 readHost(負責讀取)進行心跳檢測。接收到請求時,MyCat 依據 SQL 解析結果,將 DML SQL 發往 writeHost,Select SQL 發往 readHost。writeHost 完成寫入后與 readHost 進行主從復制。若 writeHost 掛掉,n 次心跳檢測未恢復,MyCat 發起選舉新 writeHost,原 writeHost 恢復后變為 readHost 接收數據同步。
?
?
三、數據擴容
隨著數據量和并發量的不斷增長,數據庫需要不斷擴容以滿足需求。以主從數據庫擴容為例,假設原本有2個數據庫集群,在擴容時可以將數據庫數量增加到4個。擴容時,需要將原先基于ID取模的分表方式改為新的模4運算,重新分配數據并進行代理配置的調整。擴容后的系統,主庫和從庫之間可以繼續進行復制,進一步提高系統的可用性和性能。
具體操作如下:
- 初始數據分布:在2個數據庫集群中,每個集群含主備(M0、S0 和 M1、S1),通過對記錄ID進行模2運算,結果為0的數據存于M0和S0所在集群,結果為1的數據存于M1和S1所在集群。主庫寫入數據后,從庫主動同步以保證數據一致。
-
集群擴展操作:當將2個集群擴展為4個時,將模2運算切換為模4運算,原從庫S0和S1變為主庫,負載均衡器按ID%4算法將部分數據路由到它們上面,同時S0和S1停止與原主庫同步。只需修改代理配置,無需重啟服務。之后可通過后臺服務刪除冗余數據。
-
保障數據庫可用性:擴展到4個主庫后進行主從復制,為每個主庫建立從庫,主庫負責寫操作,從庫負責讀操作,后續擴容可參照此方法。
?
《分布式架構原理與實踐-崔皓》