Database Sharding 架構深度解析指南
精選本文翻自于 Apache ShardingSphere PMC 潘娟發表于 Stack Overflow 上技術文章 “How sharding a database can make it faster”。
原文鏈接:https://stackoverflow.blog/2022/03/14/how-sharding-a-database-can-make-it-faster/
數據分片往往是分布式數據庫用以提高性能的眾多首選方法之一,而近些年來的技術創新使其逐漸成為最佳選擇。
如今,數據庫受到廣泛關注,這是因為其管理著公司最重要的數據資產。30 年前,數據大多存儲在紙、磁帶或某種類型的磁盤上。當時人均生產和消費的數據量較少,所以這些方式可以有效支持存儲、管理和訪問數據。
然而,“數據為王”的時代,情況早已截然不同。隨著智能手機的出現與普及,日常生活越來越離不開手機,手機應用程序所消耗和產生的數據量之大,是十五年前人們無法想象的。海量數據意味著數據庫集群需要處理龐大的流量,一些頭部網站和服務器每周接收訪問甚至達到數十億次級,數據庫集群承受著巨大壓力。
我們又該如何處理這些到達數據庫集群的龐大數據流量呢?
答案可能是采用數據分片。也許,你從未聽說過數據分片,或者你早已將其視為無法應對當代挑戰的過時解決方案,而選擇忽略它。數據庫分片架構聽起來可能不像其他解決方案一樣搶眼或是花里胡哨,但它絕對兼具有效性和實用性。
近期,數據分片方式實現了重大技術創新,而不久前人們還是無法想象的(例如能夠使分片更易于實現和管理的分布式 SQL/DistSQL)。也許這就是在一些尋求實現數據可擴展性的區塊鏈公司中越來越受歡迎的原因。
數據庫碎片化
數據庫誕生距今已有 50 多年,在此期間你可能認為數據庫已無創新的空間。但事實上,數據庫碎片化已成為科技行業發展最快的垂直領域之一,因為現有數據基礎設施的復雜性似乎只會惡化。
許多現代應用程序都建立在多個并且通常是特定用途的數據庫之上。單個應用程序可能包括用于存儲和訪問內容的關系數據庫(例如 PostgreSQL)、用于內容緩存的內存數據庫(例如 Redis)、自定義數據庫(例如時間序列數據庫)和用于分析的數據倉庫。現在,試想一下,一家企業擁有多種應用程序,或者不同部門各自采用不同的應用,又或者更糟糕的,不同供應商同時應用不同數據庫時會發生什么?
如上所述,數據已成為所有企業最重要的資產之一,而數據庫技術近期迅猛發展,離不開高速發展的人工智能、機器學習、區塊鏈和云技術。
據 DB-Engines 統計,目前已有超過 350 個數據庫管理系統,當然還有更多數據庫系統甚至沒有被其列入名單。
根據卡內基梅隆大學設計并維護的 “Database of Databases” 網站統計,目前已有 792 個值得關注且具有差異的數據庫管理系統。
行業中存在這么多不同的數據庫管理系統(Database Management Systems,簡稱 DBMS)也反映出企業在數據庫管理系統選型時有著多種潛在需求。
例如,銀行或其他金融機構可能會選擇 SQL Server 或 PostgreSQL 等關系 DBMS 以確保其結構化數據具有ACID(Atomicity, Consistency, Isolation & durability)事務特性。對于有著大型在線多人游戲或在線會話的 Web 應用程序業務的企業而言,通常偏好 Redis 等鍵值 NoSQL 數據庫。從事社交媒體分析的企業通常會選擇圖形數據庫,而物聯網(IoT)企業會選擇時間序列數據庫來支持其傳感器或網絡數據。
如果你認為這些選擇不錯,隨著未來幾年更多的解決方案進入市場,你也會喜歡這種多樣化的選擇。這些解決方案可能是由具有創新性的初創公司實現,而更成熟的數據庫供應商也將繼續發布新產品或增強已有解決方案。
不久后,數據庫市場碎片化趨勢會更加明顯,而碎片化也帶來了重大挑戰,例如需考慮供應商技術是否具有兼容性、舊系統是否具有適應性和高昂的更換成本等。
為什么需要數據分片?
傳統數據庫難以處理海量數據和查詢流量,因此 NoSQL 和 NewSQL 概念日益流行,受此啟發,越來越多新型數據庫產品正在投放市場,但是,僅憑這些概念并不能實際解決數據增長問題。
分片技術可將數據拆分為單獨的行和列,并將其保存在單獨的數據庫服務器實例上,以分散流量負載。每個小表稱為一個分片。Apache HBase 或 MongoDB 等 NoSQL 產品具有分片功能,此外分片架構也內置于一些 NewSQL 系統中。
讓我們看一下一種特定類型的 NewSQL 架構,即與當今的 OLTP 問題息息相關的分片架構。
雖然許多解決方案都可以最大限度地減少數據庫負載,但數據分片解決方案具有以下優點:
? 在多臺機器上實現分布式數據存儲
? 輕松平衡不同分片上的流量負載
? 顯著提高查詢性能
? 無需額外操作即可擴展數據庫
? 高效實現重用和升級傳統 DBMS
? 使用代理支持多租戶,實現多個數據庫跨用戶使用單個服務器或云計算資源。
如何進行數據庫分片
接下來,我們將通過介紹數據分片的基本流程,展示如何為 DBMS 實現分片。此外,在介紹完配置和基本概念之后,也會更深入地解釋一些重點內容。
創建分片的最佳技術之一是將數據拆分為多個小表,也稱為分區。
原表可以分為垂直分片或水平分片,即將一列或多列存儲在單獨的表中,或者將一行或多行存儲在單獨的表中。這些表可以標記為垂直分片的 “VS1” 和水平分片的 “HS1”,其中數字代表第一個表或第一個 schema,以此類推。這些數據子集綜合構成了該表的原始 schema。
以下是分片相關的兩個關鍵概念:
? 分片鍵:特定的列值,用于表示該行存儲在哪個分片中。
? 分片算法:一種將數據分布到一個或多個分片的算法。
步驟 1:分析場景查詢和數據分布情況以確定適合的分片鍵和分片算法
確定存儲指定行的分片,需將分片算法應用于分片鍵。不同的分片策略適合不同的場景,常見分片策略包括:
- MOD:Modulo 的縮寫,取模分片算法,用于將每第 n 行或每列發送到特定的分片。例如,MOD 3 算法會將第一、四、七行發送到第一個分片,將第二、五、八行發送到第二個分片,將第三、六、九行發送到第三個分片,以此類推。
- HASH:哈希取模分片算法,將 Hash 分片在分片之間均勻隨機分布數據。根據對該行的分片列值計算的一致 Hash 將每行放置在一個分片中。
- RANGE:基于分片邊界的范圍分片算法,將特定范圍的行或列發送到各個分片。
- TAG:發送與特定值匹配的所有行或列。
例如,如果分片鍵是“ID”且分片算法是“ID modulo 2”(即拆分偶數行和奇數行),則行將按如下方式進行分配:
因此,要做的就是設計一個使用該分片鍵的合適算法,而分片策略將會極大程度影響查詢效率和未來的水平擴展。不正確或較差的分片算法總是會在不同的分片之間創建冗余數據進行計算,最終導致整體計算性能不佳。
在決定如何進行數據庫分片時,需考慮的關鍵點在于明確業務查詢和數據分布的特征。雖然每個數據庫都會有影響數據分片策略選擇的個性因素,但我們可以通過提供場景案例來解釋好的分片算法如何可以有效地實現數據分布。
RANGE
例如,當對包括時間戳日志詳細信息的表進行分片時,建議使用以創建日期作為分片鍵的 RANGE 分片算法,因為人們傳統上傾向于只在特定的時間范圍內查詢這些詳細記錄。
然而,使用日期-時間時,RANGE 算法可能會導致另外一個問題:由于歷史記錄的更新頻率通常較低,而最近的記錄更新和查詢頻繁,大多數查詢會針對有最新存儲記錄的分片,導致大多數查詢相互進行競爭以獲得更新該數據的專屬權利。
MOD
MOD 分片算法則可以有效避免上述的激烈競爭。它通過 shardingKey MOD shards number 分割行,最新的行將被拆分為不同的分片,以便將最新的查詢發送到不同的分片,避免最新的行之間的競爭。分片鍵是字符串值(并且可能對泄露敏感)時,可以使用 HASH 算法創建一個值,MOD 算法可以使用該值將數據分布到分表上。
TAG
需按單元格的值對數據進行分片時,建議使用 TAG 分片算法。假設,為遵守通用數據保護條例(GDPR),需將所有歐盟相關數據存儲在位于歐盟的服務器上,為此,我們該如何操作一個基于分片的分布式數據庫系統呢?假設,該數據庫管理員(Databse Administrator, DBA) 使用 TAG 分片算法,則可以將帶有標記國家/地區的數據的行發送到位于特定國家/地區的指定分片,如果想了解有多少記錄受到影響,該分片數據庫系統只需從與歐盟相關分片返回 COUNT(*) 即可回答此查詢 SELECT COUNT(*) FROM registrant_table WHERE region = "EU", 由此,必須從整個分布式系統計算最終結果的分布式查詢被簡化成來自一個分片的單個查詢。
沒有哪種方法是放之四海而皆準的。要獲得最佳數據庫性能,就得多花些時間對特定業務場景進行深入分析。當然,為實現用戶快速入門,基于分片的分布式數據庫系統開發者通常會選擇滿足大多數用戶案例的通用策略。
步驟 2: 遷移現有數據
如果決定執行分片,不需要將所有原始數據遷移至某一分片集群中。但這樣做是有風險的,你將面臨以下問題:
- 如何在分片的同時保證業務不間斷運轉
- 如何在新的分片集群中重放增量數據
- 如何比較原數據庫和新分片集群的數據
- 如何找到將流量切換到新分片集群的最佳時機
但是,如果你決定將歷史數據遷移至分片,傳統方法如下:
1. 首先,通過分片算法將歷史數據劃分至新的數據庫分片集群。建議使用一個自動數據遷移程序,它將運行所需的所有 SQL 查詢。
2. 其次,運行平臺或程序來拉取和解析數據庫日志,以了解數據劃分過程中發生了哪些變更,并將這些變更應用至新的分片集群(增量數據分片)。
3. 第三,選擇一種數據檢查策略來比較原始數據庫和新分片集群中的數據。這些數據檢查策略很靈活,既可以選擇高精度檢查也可以選擇快速檢查,亦或選擇折中的檢查策略。是比較每個單元格,還是只檢查總額,都由你來決定。為達到最精確的數據檢查策略,可以采取逐行比較,這也是最為費力的一種檢查方式。而只比較原始數據庫和新集群的行值是最為快速的檢查方式,但準確性也就大打折扣。其他策略,如 CRC32,正在實現準確性和速度之間的平衡。
步驟 3:將流量轉移至新集群
假設上述步驟已順利完成,那么下一步就是將在線流量切換到新的分片集群。該操作適用于無法寫入數據庫集群的時間段,以便兩個數據集保持一致并保留可選查詢——非高峰時間此步驟為常見選擇。
應禁止所有更新請求以保持分布式數據一致性。但可以允許查詢,因為查詢不會引起分布式系統中的任何變動。
這個過程很簡單,但每個部分處理起來可能會有難度。自動執行將最大限度縮短停機時間,但由于處理的數據十分重要,建議應保持謹慎。
不過,好消息是,你并非第一個面臨這些挑戰的人。開源項目幫助我們站在了巨人的肩膀上。
整個分片過程是 Apache ShardingSphere(我也是該項目的 Contributor 之一) 的主要功能之一。它提供各種分片策略、數據遷移、重新分片和管理現有分片等功能。
它還提供了許多更為高級的功能來幫助解決我們在下一節中將提到的問題。此外,有一個額外的好處是,ApacheShardingSphere 擁有一個活躍的社區,這意味著你的大多數問題已經得到了解決。
怎樣才是好的分片?
現在我們已經了解了分片工作流程以及在數據庫上執行分片的必要步驟。但是好的分片應該是什么樣的呢?
無須對邊緣理論或背景和場景特定要求進行太多擴展,好的分片通常具有六個特點。
如果負責運行操作的 DBA(數據庫管理員)發生了變動,分片應易于設置和理解。分片具有高可用性、彈性伸縮能力、高分布式系統性能、可觀察性和低遷移成本。
這六個要素代表了理想的分片,但它還取決于你所選擇的分片客戶端。
使用分片和副本
由于數據庫場景多種多樣,而需求會隨著應用程序的擴展而變化,因此除了上述核心流程之外,你還需要了解以下內容。
提升數據庫性能和擴展性的另一種方法是通過副本。副本會創建獨立的重復數據庫節點,寫入某一節點的數據將被復制到另一個重復節點上。
一般來說,無論是專業人士還是致力于 passion projects 的開發人員都在努力最大限度地利用數據庫,以實現高可用和高性能。然而,分片和副本的體系架構可能會讓數據庫管理和路由策略復雜化。
設想每個分片都有副本節點,結果將如下圖所示。如果一個主節點有多個副本,則訪問它們的應用程序情況會更為復雜。
那么,分片和副本有何不同呢?如上所述,分片意味著將一個大表拆分為幾個小表以創建許多分片;另一方面,副本將對原始表創建多個副本。每個副本將包含原始節點(主節點)的全部數據。
分片可以幫助用戶對存在于多個服務器上的數據進行負載均衡,以實現可擴展性;而副本將創建主庫備份,以提高系統可用性。這兩種不同的體系架構給分布式系統帶來了不同的優勢。基于這一論證,一些用戶希望同時擁有這兩種功能,因此同時利用分片和副本的體系架構并不少見。
如下圖所示,用戶可能會希望跨不同的服務器(如P1、P2、P3)對一個包含大量數據的數據庫進行分片。每次查詢也會被分成不同的分片,以提高該分布式數據庫系統的 TPS 或 QPS。但是,一旦其中一個分片崩潰下線,可用性將降至 2/3。不僅如此,重新調用離線副本非常耗時,這會造成嚴重損失。為提高該分片系統的可用性,對每個分片進行復制,即對前面提到的主節點 P1、P2、P3 進行復制,將是一種高效的方法。
R1、R2、R3 的存在能很好的解釋我上面說到的解決方案。當 P1 不可用時,其副本 R1 將成為主節點以服務于業務。這是一個安全的選擇,其理念是停機率越小,業務和服務的損失就越小。
這個想法乍聽上去不錯,但是這一分布式分片數據庫系統的拓撲結構讓應用程序訪問變得十分復雜。假設每個主節點有兩個副本,那么由 P1、P2、P3 和它們的六個副本組成的網絡就會讓開發人員感到困惑和負擔。他們可能會提出這樣的問題:哪個主節點適合該查詢?如何訪問他們的副本?如何在不同副本之間進行負載均衡?一旦主節點無法正常工作,誰來負責重新路由此查詢?
在這一假設場景中,開發人員負責代碼編寫以保證業務效率。這種架構的確有其優勢,但其復雜性也意味著難以對其加以利用和維護。
如何對應用程序隱藏這種復雜性?
一般來說,有兩種客戶端或訪問模式可供用戶選擇,外加一種新的“額外”類型客戶端。用戶可以通過專門的數據庫連接驅動程序或通過將應用程序連接到路由數據的代理應用程序來啟動分片。
Sidecar 是可用分片模式中相對較新的概念,它起源于 service meshes。簡單地說,它是一個與某種服務一起部署的代理實例,用于處理不同服務之間的通信、監控等。這種模式的操作方式類似于摩托車的跨斗。就是說跨斗被附加到母應用程序上,同時為該應用程序提供支持性功能。
如果我們使用專門的驅動程序或代理而非使用 Sidecar,它將僅僅是單個數據庫服務器,能夠幫助用戶管理數據庫集群。如此一來,應用程序就不會受到這些復雜的訪問拓撲的影響,也不必進行重構代碼以適應新的框架。
總結與趨勢
分片是解決網絡應用迅速發展所帶來新挑戰的方法之一。其他解決方案包括 DBaaS(或云上數據庫)、新的數據庫體系架構,或者僅僅是增加用于存儲的數據庫數量這一老辦法。
兜了一大圈,希望這篇文章至少能幫助你了解分片架構。如果你早已聽說過分片架構,但認為它已經過時了,那么希望這篇文章能改變你的想法。
實際上,我不喜歡時尚這個詞,因為它給我的感覺是轉瞬即逝的,因為今天的時尚明天就有可能過時。雖然生活中有許多事物的確如此,尤其是技術,但我更愿意以技術在特定場景下的實用性、效率和成本優勢來評判一項技術。
所有這些都表明,對新趨勢持開放態度固然很好,但也不要忘記,有時現有和成熟的技術可能才是最佳解決方案。
作者介紹
潘娟,SphereEx聯合創始人兼CTO,Apache member、 Apache ShardingSphere PMC、Apache brpc(Incubating) & Apache AGE(Incubating) mentor、中國木蘭開源社區導師。曾負責京東數科數據庫智能平臺的設計與研發,現專注于分布式數據庫 & 中間件生態及開源領域。被評為《2020 中國開源先鋒人物》,OSCAR尖峰開源人物。
*參考?文檔
[1] https://db.cs.cmu.edu/papers/2016/pavlo-newsql-sigmodrec2016.pdf
[2] https://github.com/apache/shardingsphere
[3] https://opensource.com/article/21/9/distsql