數(shù)據(jù)庫(kù)分片技術(shù):深入解析與實(shí)踐指南
前言
任何應(yīng)用程序或網(wǎng)站,如果經(jīng)歷了顯著增長(zhǎng),最終都需要進(jìn)行擴(kuò)展以適應(yīng)流量的增加。對(duì)于數(shù)據(jù)驅(qū)動(dòng)的應(yīng)用程序和網(wǎng)站來說,擴(kuò)展的方式必須確保數(shù)據(jù)的安全性和完整性。很難預(yù)測(cè)一個(gè)網(wǎng)站或應(yīng)用程序會(huì)變得多受歡迎,或者這種受歡迎程度能維持多久,這就是為什么一些組織選擇能夠動(dòng)態(tài)擴(kuò)展數(shù)據(jù)庫(kù)的數(shù)據(jù)庫(kù)架構(gòu)。在這篇概念性文章中,我們將討論這樣一種數(shù)據(jù)庫(kù)架構(gòu):分片數(shù)據(jù)庫(kù)。分片在近年來受到了大量關(guān)注,但許多人對(duì)它是什么或者在什么情況下對(duì)數(shù)據(jù)庫(kù)進(jìn)行分片是有意義的并沒有清晰的理解。我們將討論分片是什么,它的一些主要優(yōu)點(diǎn)和缺點(diǎn),以及一些常見的分片方法。
什么是分片
分片是一種數(shù)據(jù)庫(kù)架構(gòu)模式,與水平分區(qū)有關(guān)——即將一個(gè)表的行分離到多個(gè)不同的表中,這些表被稱為分區(qū)。每個(gè)分區(qū)都有相同的模式和列,但行完全不同。同樣,每個(gè)分區(qū)中保存的數(shù)據(jù)是獨(dú)特的,并且與其它分區(qū)中保存的數(shù)據(jù)互不影響。
我們可以從水平分區(qū)與垂直分區(qū)的關(guān)系來幫助理解水平分區(qū)。在垂直分區(qū)的表中,整個(gè)列被分離出來并放入新的、不同的表中。一個(gè)垂直分區(qū)中保存的數(shù)據(jù)與所有其他分區(qū)中的數(shù)據(jù)是獨(dú)立的,并且每個(gè)分區(qū)都保存著不同的行和列。下面的圖示展示了一個(gè)表如何同時(shí)進(jìn)行水平和垂直分區(qū):
圖片
分片涉及將數(shù)據(jù)分成兩個(gè)或更多的小塊,稱為邏輯分片。這些邏輯分片隨后被分布到不同的數(shù)據(jù)庫(kù)節(jié)點(diǎn)上,這些節(jié)點(diǎn)被稱為物理分片,可以保存多個(gè)邏輯分片。盡管如此,所有分片中保存的數(shù)據(jù)集體代表了整個(gè)邏輯數(shù)據(jù)集。
數(shù)據(jù)庫(kù)分片體現(xiàn)了一種無共享架構(gòu)。這意味著分片是自治的;它們不共享任何相同的數(shù)據(jù)或計(jì)算資源。然而,在某些情況下,將某些表復(fù)制到每個(gè)分片中作為引用表可能是有意義的。例如,假設(shè)有一個(gè)應(yīng)用程序的數(shù)據(jù)庫(kù)依賴于固定的重量測(cè)量轉(zhuǎn)換率。通過將包含必要轉(zhuǎn)換率數(shù)據(jù)的表復(fù)制到每個(gè)分片中,它將有助于確保所有分片都保存了查詢所需的所有數(shù)據(jù)。
通常,分片是在應(yīng)用程序級(jí)別實(shí)現(xiàn)的,這意味著應(yīng)用程序包含定義傳輸讀取和寫入到哪個(gè)分片的代碼。然而,一些數(shù)據(jù)庫(kù)管理系統(tǒng)內(nèi)置了分片功能,允許你直接在數(shù)據(jù)庫(kù)級(jí)別實(shí)現(xiàn)分片。
鑒于我們對(duì)分片的一般概述,讓我們來看看與這種數(shù)據(jù)庫(kù)架構(gòu)相關(guān)的一些優(yōu)點(diǎn)和缺點(diǎn)。
分片的優(yōu)點(diǎn)
分片數(shù)據(jù)庫(kù)的主要吸引力在于它可以幫助實(shí)現(xiàn)水平擴(kuò)展,也稱為擴(kuò)展外部。水平擴(kuò)展是在現(xiàn)有堆棧中添加更多機(jī)器以分散負(fù)載并允許更多流量和更快處理的做法。這通常與垂直擴(kuò)展相對(duì)比,后者稱為擴(kuò)展上行,涉及升級(jí)現(xiàn)有服務(wù)器的硬件,通常是通過增加更多RAM或CPU。
在單臺(tái)機(jī)器上運(yùn)行關(guān)系數(shù)據(jù)庫(kù)并根據(jù)需要通過升級(jí)其計(jì)算資源來擴(kuò)展它是相對(duì)簡(jiǎn)單的。然而,任何非分布式數(shù)據(jù)庫(kù)在存儲(chǔ)和計(jì)算能力方面都將受到限制,因此具有水平擴(kuò)展的自由使你的設(shè)置更加靈活。
選擇分片數(shù)據(jù)庫(kù)架構(gòu)的另一個(gè)原因是加快查詢響應(yīng)時(shí)間。當(dāng)你在未分片的數(shù)據(jù)庫(kù)上提交查詢時(shí),它可能必須搜索你查詢的表中的所有行,才能找到你正在尋找的結(jié)果集。對(duì)于具有大型、單一數(shù)據(jù)庫(kù)的應(yīng)用程序,查詢可能會(huì)變得非常慢。通過將一個(gè)表分片成多個(gè),查詢必須覆蓋的行數(shù)減少,結(jié)果集返回得更快。
分片還可以通過減輕停機(jī)的影響來使應(yīng)用程序更可靠。如果你的應(yīng)用程序或網(wǎng)站依賴于未分片的數(shù)據(jù)庫(kù),停機(jī)可能會(huì)使整個(gè)應(yīng)用程序不可用。通過分片數(shù)據(jù)庫(kù),停機(jī)可能只會(huì)影響單個(gè)分片。盡管這可能會(huì)使應(yīng)用程序或網(wǎng)站的某些部分對(duì)某些用戶不可用,但總體影響仍然會(huì)比整個(gè)數(shù)據(jù)庫(kù)崩潰時(shí)要小。
分片的缺點(diǎn)
雖然分片數(shù)據(jù)庫(kù)可以使擴(kuò)展更容易并提高性能,但它也可能帶來一定的限制。在這里,我們將討論其中的一些,并解釋為什么它們可能是完全避免分片的原因。
人們遇到分片的第一個(gè)困難是正確實(shí)現(xiàn)分片數(shù)據(jù)庫(kù)架構(gòu)的復(fù)雜性。如果做得不正確,分片過程可能導(dǎo)致數(shù)據(jù)丟失或表?yè)p壞的風(fēng)險(xiǎn)很大。即使做得正確,分片也可能對(duì)你的團(tuán)隊(duì)工作流程產(chǎn)生重大影響。用戶必須管理跨越多個(gè)分片位置的數(shù)據(jù),而不是從一個(gè)單一的入口點(diǎn)訪問和管理數(shù)據(jù),這可能會(huì)對(duì)某些團(tuán)隊(duì)造成干擾。
用戶在分片數(shù)據(jù)庫(kù)后有時(shí)會(huì)遇到的一個(gè)問題是分片最終變得不平衡。舉個(gè)例子,假設(shè)你有一個(gè)數(shù)據(jù)庫(kù)有兩個(gè)獨(dú)立的分片,一個(gè)用于姓氏以字母A到M開頭的客戶,另一個(gè)用于姓氏以字母N到Z開頭的客戶。然而,你的應(yīng)用程序?yàn)樾帐弦宰帜窯開頭的人提供了過多服務(wù)。因此,A-M分片逐漸積累了比N-Z分片更多的數(shù)據(jù),導(dǎo)致應(yīng)用程序減速并為大量用戶停滯不前。A-M分片已經(jīng)成為了所謂的數(shù)據(jù)庫(kù)熱點(diǎn)。在這種情況下,分片數(shù)據(jù)庫(kù)的任何好處都被減速和崩潰所抵消。數(shù)據(jù)庫(kù)可能需要修復(fù)和重新分片,以實(shí)現(xiàn)更均勻的數(shù)據(jù)分布。
另一個(gè)主要缺點(diǎn)是一旦數(shù)據(jù)庫(kù)被分片,就很難將其恢復(fù)到未分片的架構(gòu)。在分片之前制作的數(shù)據(jù)庫(kù)備份不會(huì)包括自分區(qū)以來寫入的數(shù)據(jù)。因此,重建原始未分片架構(gòu)需要將新分區(qū)數(shù)據(jù)與舊備份合并,或者將分區(qū)數(shù)據(jù)庫(kù)轉(zhuǎn)換回單個(gè)數(shù)據(jù)庫(kù),這兩者都是昂貴且耗時(shí)的努力。
最后一個(gè)需要考慮的缺點(diǎn)是分片不是每個(gè)數(shù)據(jù)庫(kù)引擎都原生支持的。例如,PostgreSQL不包括自動(dòng)分片作為功能,盡管可以手動(dòng)分片PostgreSQL數(shù)據(jù)庫(kù)。有一些Postgres分支確實(shí)包括自動(dòng)分片,但這些通常落后于最新的PostgreSQL發(fā)布,并且缺少某些其他功能。一些專門的數(shù)據(jù)庫(kù)技術(shù)——如MySQL Cluster或某些數(shù)據(jù)庫(kù)即服務(wù)產(chǎn)品,如MongoDB Atlas——確實(shí)包括自動(dòng)分片作為功能,但這些數(shù)據(jù)庫(kù)管理系統(tǒng)的普通版本則不支持。因此,分片通常需要“自己搞定”的方法。這意味著分片的文檔或故障排除提示通常很難找到。
當(dāng)然,這些只是分片前的一些問題。根據(jù)其用例,分片數(shù)據(jù)庫(kù)可能還有許多其他潛在的缺點(diǎn)。
分片架構(gòu)
一旦你決定分片你的數(shù)據(jù)庫(kù),接下來你需要弄清楚你將如何進(jìn)行。在運(yùn)行查詢或?qū)魅霐?shù)據(jù)分布到分片表或數(shù)據(jù)庫(kù)時(shí),確保它去到正確的分片是至關(guān)重要的。否則,可能會(huì)導(dǎo)致數(shù)據(jù)丟失或查詢緩慢。在這一部分,我們將討論一些常見的分片架構(gòu),每種架構(gòu)都使用稍微不同的過程來在分片之間分布數(shù)據(jù)。
基于鍵的分片
基于鍵的分片,也稱為基于哈希的分片,涉及使用從新寫入數(shù)據(jù)中取出的值——例如客戶的ID號(hào)、客戶端應(yīng)用程序的IP地址、郵政編碼等——并將其插入哈希函數(shù)以確定數(shù)據(jù)應(yīng)該去哪個(gè)分片。哈希函數(shù)是一種函數(shù),它將數(shù)據(jù)(例如客戶電子郵件)作為輸入,并輸出一個(gè)離散值,稱為哈希值。在分片的情況下,哈希值是一個(gè)分片ID,用于確定傳入數(shù)據(jù)將存儲(chǔ)在哪個(gè)分片上??偟膩碚f,過程是這樣的:
圖片
為了確保條目以正確的分片和一致的方式放置,輸入哈希函數(shù)的值應(yīng)該都來自同一列。這個(gè)列被稱為分片鍵。簡(jiǎn)單來說,分片鍵類似于主鍵,因?yàn)閮烧叨加糜跒閱蝹€(gè)行建立唯一標(biāo)識(shí)符。廣義上講,分片鍵應(yīng)該是靜態(tài)的,這意味著它不應(yīng)該包含隨時(shí)間變化的值。否則,它將增加更新操作的工作量,并可能減慢性能。
雖然基于鍵的分片是一種相當(dāng)常見的分片架構(gòu),但在嘗試動(dòng)態(tài)添加或刪除數(shù)據(jù)庫(kù)服務(wù)器時(shí),它可能會(huì)使事情變得棘手。當(dāng)你添加服務(wù)器時(shí),每個(gè)服務(wù)器都需要一個(gè)相應(yīng)的哈希值,如果你不添加它們,許多現(xiàn)有條目,如果不是全部的話,都需要重新映射到它們新的、正確的哈希值,然后遷移到適當(dāng)?shù)姆?wù)器。當(dāng)你開始重新平衡數(shù)據(jù)時(shí),新的和舊的哈希函數(shù)都將無效。因此,你的服務(wù)器在遷移期間將無法寫入任何新數(shù)據(jù),你的應(yīng)用程序可能會(huì)受到停機(jī)的影響。
這種策略的主要吸引力在于它可以用來均勻地分布數(shù)據(jù),以防止熱點(diǎn)。此外,因?yàn)樗惴ㄐ缘胤植紨?shù)據(jù),所以不需要像范圍或目錄基于分片的其他策略那樣維護(hù)所有數(shù)據(jù)位置的映射。
基于范圍的分片
基于范圍的分片涉及根據(jù)給定值的范圍進(jìn)行分片數(shù)據(jù)。為了說明,假設(shè)你有一個(gè)數(shù)據(jù)庫(kù)存儲(chǔ)了零售商目錄中的所有產(chǎn)品信息。你可以創(chuàng)建幾個(gè)不同的分片,并根據(jù)它們所屬的價(jià)格范圍分配每個(gè)產(chǎn)品的信息,如下所示:
圖片
基于范圍的分片的主要好處是它相對(duì)容易實(shí)現(xiàn)。每個(gè)分片保存不同的數(shù)據(jù)集,但它們都有一個(gè)與原始數(shù)據(jù)庫(kù)相同的模式。
應(yīng)用程序代碼讀取數(shù)據(jù)屬于哪個(gè)范圍,然后將其寫入相應(yīng)的分片。
另一方面,基于范圍的分片不能防止數(shù)據(jù)分布不均,導(dǎo)致上述數(shù)據(jù)庫(kù)熱點(diǎn)??纯词纠龍D,即使每個(gè)分片保存相等數(shù)量的數(shù)據(jù),特定產(chǎn)品可能會(huì)比其他產(chǎn)品受到更多關(guān)注。它們各自的分片將反過來接收不成比例的讀取數(shù)量。
基于目錄的分片
要實(shí)現(xiàn)基于目錄的分片,必須創(chuàng)建和維護(hù)一個(gè)使用分片鍵跟蹤哪個(gè)分片保存哪個(gè)數(shù)據(jù)的查找表。查找表是一個(gè)保存有關(guān)特定數(shù)據(jù)位置的靜態(tài)信息的表。下面的圖示展示了基于目錄分片的簡(jiǎn)單示例:
圖片
在這里,配送區(qū)域列被定義為分片鍵。來自分片鍵的數(shù)據(jù)被寫入查找表,以及每行相應(yīng)的分片。這與基于范圍的分片類似,但不是確定分片鍵數(shù)據(jù)屬于哪個(gè)范圍,而是每個(gè)鍵都與其自己的特定分片相關(guān)聯(lián)?;谀夸浀姆制窃诜制I基數(shù)較低——意味著它有少量可能的值——并且對(duì)于一個(gè)分片來說存儲(chǔ)一系列鍵沒有意義的情況下,比基于范圍的分片更好的選擇。請(qǐng)注意,它也與基于鍵的分片不同,因?yàn)樗恍枰ㄟ^哈希函數(shù)處理分片鍵;它只是檢查鍵與查找表,看看數(shù)據(jù)需要寫入哪里。
基于目錄的分片的主要吸引力在于其靈活性?;诜秶姆制軜?gòu)限制你指定值的范圍,而基于鍵的分片限制你使用固定的哈希函數(shù),這如前所述,以后更改起來可能非常困難。另一方面,基于目錄的分片允許你使用任何系統(tǒng)或算法將數(shù)據(jù)條目分配給分片,并且使用這種方法動(dòng)態(tài)添加分片相對(duì)容易。
雖然基于目錄的分片是這里討論的分片方法中最靈活的,但每次查詢或?qū)懭肭岸夹枰B接到查找表可能會(huì)對(duì)應(yīng)用程序的性能產(chǎn)生不利影響。此外,查找表可能成為單點(diǎn)故障:如果它變得損壞或以其他方式失敗,可能會(huì)影響寫入新數(shù)據(jù)或訪問現(xiàn)有數(shù)據(jù)的能力。
我應(yīng)該分片嗎?
是否應(yīng)該實(shí)施分片數(shù)據(jù)庫(kù)架構(gòu)幾乎總是一個(gè)有爭(zhēng)議的問題。一些人認(rèn)為,對(duì)于達(dá)到一定規(guī)模的數(shù)據(jù)庫(kù)來說,分片是不可避免的結(jié)果,而另一些人則認(rèn)為,由于分片帶來的操作復(fù)雜性,除非絕對(duì)必要,否則應(yīng)避免分片。
由于這種增加的復(fù)雜性,分片通常只在處理非常大的數(shù)據(jù)量時(shí)才執(zhí)行。以下是一些可能有益于分片數(shù)據(jù)庫(kù)的常見場(chǎng)景:
- 應(yīng)用程序數(shù)據(jù)量增長(zhǎng)到超過單個(gè)數(shù)據(jù)庫(kù)節(jié)點(diǎn)的存儲(chǔ)容量。
- 數(shù)據(jù)庫(kù)的寫入或讀取量超過單個(gè)節(jié)點(diǎn)或其只讀副本的處理能力,導(dǎo)致響應(yīng)時(shí)間變慢或超時(shí)。
- 應(yīng)用程序所需的網(wǎng)絡(luò)帶寬超過了單個(gè)數(shù)據(jù)庫(kù)節(jié)點(diǎn)及其任何只讀副本可用的帶寬,導(dǎo)致響應(yīng)時(shí)間變慢或超時(shí)。
在進(jìn)行分片之前,你應(yīng)該嘗試所有其他優(yōu)化數(shù)據(jù)庫(kù)的選項(xiàng)。你可能需要考慮的一些優(yōu)化包括:
- 設(shè)置遠(yuǎn)程數(shù)據(jù)庫(kù)。如果你正在使用一個(gè)所有組件都駐留在同一臺(tái)服務(wù)器上的單體應(yīng)用程序,你可以通過將數(shù)據(jù)庫(kù)移動(dòng)到它自己的機(jī)器上來提高數(shù)據(jù)庫(kù)的性能。這不會(huì)像分片那樣增加太多復(fù)雜性,因?yàn)閿?shù)據(jù)庫(kù)的表保持完整。然而,它仍然允許你將數(shù)據(jù)庫(kù)與其余基礎(chǔ)設(shè)施分開垂直擴(kuò)展。
- 實(shí)施緩存。如果你的應(yīng)用程序的讀取性能是造成問題的原因,緩存是一種可以幫助提高性能的策略。緩存涉及將已經(jīng)請(qǐng)求的數(shù)據(jù)暫時(shí)存儲(chǔ)在內(nèi)存中,允許你稍后更快地訪問它。
- 創(chuàng)建一個(gè)或多個(gè)只讀副本。這是另一種可以幫助提高讀取性能的策略,它涉及將數(shù)據(jù)從一個(gè)數(shù)據(jù)庫(kù)服務(wù)器(主服務(wù)器)復(fù)制到一個(gè)或多個(gè)輔助服務(wù)器。在此之后,每個(gè)新的寫入都會(huì)先發(fā)送到主服務(wù)器,然后再?gòu)?fù)制到輔助服務(wù)器,而讀取則專門在輔助服務(wù)器上進(jìn)行。像這樣分配讀取和寫入可以防止任何一臺(tái)機(jī)器承擔(dān)過多的負(fù)載,有助于防止減速和崩潰。請(qǐng)注意,創(chuàng)建只讀副本涉及更多的計(jì)算資源,因此成本更高,這可能對(duì)一些人來說是一個(gè)重要的約束。
- 升級(jí)到更大的服務(wù)器。在大多數(shù)情況下,將數(shù)據(jù)庫(kù)服務(wù)器升級(jí)到具有更多資源的機(jī)器比分片需要的努力要少。與創(chuàng)建只讀副本一樣,升級(jí)的服務(wù)器將擁有更多的資源,可能會(huì)花費(fèi)更多的錢。因此,只有在調(diào)整大小確實(shí)是你的最佳選擇時(shí),你才應(yīng)該進(jìn)行調(diào)整。
請(qǐng)記住,如果你的應(yīng)用程序或網(wǎng)站增長(zhǎng)到一定程度,這些策略中的任何一個(gè)都將不足以單獨(dú)提高性能。在這種情況下,分片確實(shí)可能是你的最佳選擇。
結(jié)論
分片對(duì)于那些尋求水平擴(kuò)展數(shù)據(jù)庫(kù)的人來說可能是一個(gè)很好的解決方案。然而,它也增加了相當(dāng)大的復(fù)雜性,并為你的應(yīng)用程序創(chuàng)造了更多的潛在故障點(diǎn)。分片對(duì)某些人來說可能是必要的,但創(chuàng)建和維護(hù)分片架構(gòu)所需的時(shí)間和資源可能會(huì)超過其他人的利益。
通過閱讀這篇概念性文章,你應(yīng)該對(duì)分片的利弊有了更清晰的了解。展望未來,你可以利用這些見解來做出更明智的決策,關(guān)于是否分片數(shù)據(jù)庫(kù)架構(gòu)適合你的應(yīng)用程序。



























