將一個(gè)數(shù)據(jù)存儲(chǔ)到一組水平分區(qū)或碎片。存儲(chǔ)和訪問大量數(shù)據(jù)時(shí),這個(gè)模式可以提高可擴(kuò)展性。
由一個(gè)單一的服務(wù)器托管的數(shù)據(jù)存儲(chǔ)區(qū)可能會(huì)受到以下限制:
垂直縮放通過添加更多的磁盤容量,處理能力,內(nèi)存和網(wǎng)絡(luò)連接可能會(huì)推遲一些這些限制的效果,但它很可能是只是一個(gè)臨時(shí)的解決方案。能夠支持大量用戶和大量數(shù)據(jù)的商業(yè)云應(yīng)用程序必須能夠擴(kuò)展幾乎無限,所以垂直縮放不一定是最好的解決方案。
劃分?jǐn)?shù)據(jù)存儲(chǔ)到水平分區(qū)或碎片。每個(gè)碎片都有相同的模式,但保存的數(shù)據(jù)其獨(dú)特的子集。甲碎片是在自己的權(quán)利(它可以包含許多不同類型的實(shí)體的數(shù)據(jù))的數(shù)據(jù)存儲(chǔ)器,用作存儲(chǔ)節(jié)點(diǎn)的服務(wù)器上運(yùn)行。
這種模式具有以下優(yōu)點(diǎn):
何時(shí)將一個(gè)數(shù)據(jù)存儲(chǔ)成碎片,決定哪些數(shù)據(jù)應(yīng)該被放置在每個(gè)碎片。甲碎片通常包含倒在數(shù)據(jù)中的一個(gè)或多個(gè)屬性所確定的指定范圍內(nèi)的物品。這些屬性形成的分片密鑰(有時(shí)也被稱為分區(qū)鍵)。分片的關(guān)鍵應(yīng)該是靜態(tài)的。它不應(yīng)該根據(jù)可能發(fā)生變化的數(shù)據(jù)。
分片身體組織的數(shù)據(jù)。何時(shí)一個(gè)應(yīng)用程序存儲(chǔ)和檢索數(shù)據(jù),該分片的邏輯指示應(yīng)用到相應(yīng)的碎片。此拆分邏輯可在應(yīng)用程序中被實(shí)現(xiàn)為數(shù)據(jù)訪問代碼的一部分,或者它可以由數(shù)據(jù)存儲(chǔ)系統(tǒng)中實(shí)現(xiàn),如果它透明地支持分片。
抽象的拆分邏輯的數(shù)據(jù)的物理位置提供了一個(gè)高層次的控制在其上的碎片包含的數(shù)據(jù),并且使數(shù)據(jù)分片之間遷移,而再加工的應(yīng)用程序的業(yè)務(wù)邏輯應(yīng)該需要在碎片的數(shù)據(jù)后面將要引入的(例如,如果碎片變得不平衡)。的折衷是在確定的每個(gè)數(shù)據(jù)項(xiàng)的位置,因?yàn)樗粰z索所需的附加數(shù)據(jù)存取的開銷。
為了確保最佳的性能和可擴(kuò)展性,分裂的數(shù)據(jù)的方式,適合的查詢類型的應(yīng)用程序執(zhí)行是重要的。在許多情況下,這是不可能的拆分計(jì)劃將完全符合每個(gè)查詢的要求。例如,在一個(gè)多用戶系統(tǒng)中的應(yīng)用,可能需要通過使用承租者ID來檢索租戶數(shù)據(jù),但它也可能需要基于其它屬性這個(gè)數(shù)據(jù)查找,如承租人的名稱或位置。為了處理這些情況,實(shí)行分片策略,即支持最常用的查詢執(zhí)行的一個(gè)子庫(kù)的關(guān)鍵。
如果查詢通過使用屬性值的組合來定期檢索數(shù)據(jù),這可能是可以定義通過將屬性一起的復(fù)合分片鍵。另外,使用模式,如索引表,以提供快速的查找到未覆蓋的碎片關(guān)鍵基礎(chǔ)屬性數(shù)據(jù)。
選擇所述分片密鑰,并決定如何跨碎片分發(fā)數(shù)據(jù)時(shí)的三種策略是常用的。注意,并不需要成為碎片和承載它們 - 在單個(gè)服務(wù)器可以承載多個(gè)分塊中的服務(wù)器之間的一對(duì)一的對(duì)應(yīng)關(guān)系。這些戰(zhàn)略包括:
圖1 - 基于租戶ID的分片租戶數(shù)據(jù)
分片鍵和物理存儲(chǔ)的映射關(guān)系可以基于物理分塊,每個(gè)分片鍵映射到一個(gè)物理分區(qū)??商鎿Q地,這種技術(shù)提供了重新平衡碎片時(shí)更大的靈活性是使用虛擬分區(qū)方法,其中分片鍵映射到虛擬碎片的數(shù)量相同,這又映射到較少的物理分區(qū)。在這種方法中,一個(gè)應(yīng)用程序通過使用指的是一個(gè)虛擬碎片一個(gè)碎片鍵定位數(shù)據(jù),并在系統(tǒng)的虛擬分片透明地映射到物理分區(qū)。進(jìn)行修改,以使用一組不同的碎片的鍵的虛擬碎片和物理分區(qū)可以改變,而不需要對(duì)應(yīng)用程序代碼之間的映射。
范圍的策略。這在同一個(gè)分片相關(guān)的項(xiàng)目一起策略組,并把它們的訂單通過分片密鑰分片鍵是連續(xù)的。它是用于應(yīng)用程序通過使用范圍查詢(即返回一組數(shù)據(jù)項(xiàng)的為落在給定范圍內(nèi)的碎片鍵查詢)經(jīng)常檢索項(xiàng)集有用的。例如,如果應(yīng)用程序經(jīng)常需要找到放置在給定月份所有的訂單,該數(shù)據(jù)可被檢索更快如果一個(gè)月的所有命令被存儲(chǔ)在日期和時(shí)間的順序在同一個(gè)分片。如果每個(gè)訂單被存儲(chǔ)在不同的碎片,它們將必須通過進(jìn)行大量的點(diǎn)查詢(返回單個(gè)數(shù)據(jù)項(xiàng)的查詢)的單獨(dú)取出。圖2示出了這種策略的一個(gè)例子。
圖2 - 數(shù)據(jù)中的碎片存儲(chǔ)順序集合(范圍)
在這個(gè)例子中,分片鍵是一個(gè)組合鍵,包括訂單月作為最顯著元件,其次是為了日和時(shí)間。創(chuàng)建和附加到一個(gè)碎片新訂單時(shí),訂單中的數(shù)據(jù)自然排序。一些數(shù)據(jù)存儲(chǔ)支持包括識(shí)別所述碎片和行密鑰唯一地標(biāo)識(shí)該子庫(kù)中的項(xiàng)分區(qū)鍵元件的兩部分分片密鑰。數(shù)據(jù)通常是在碎片中排鍵順序舉行。該受的范圍內(nèi)的查詢和需要的項(xiàng)目組合在一起可以使用一個(gè)分片鍵具有用于分區(qū)鍵但該行鍵的唯一值相同的值。
哈希策略。這種策略的目的是減少在數(shù)據(jù)熱點(diǎn)的機(jī)會(huì)。它的目的是分配在實(shí)現(xiàn)每個(gè)碎片的大小和平均負(fù)載,每個(gè)碎片會(huì)遇到之間的平衡的方式在整個(gè)碎片中的數(shù)據(jù)。分片的邏輯計(jì)算,其中基于所述數(shù)據(jù)的一個(gè)或多個(gè)屬性的散列來存儲(chǔ)中的項(xiàng)目的子庫(kù)。所選擇的散列函數(shù)應(yīng)該均勻地分布在整個(gè)數(shù)據(jù)碎片,可能通過引入一些隨機(jī)元素插入的計(jì)算。圖2示出了這種策略的一個(gè)例子。
圖3 - 基于租戶ID的哈希分片租戶數(shù)據(jù)
了解超過其他分片策略哈希策略的優(yōu)勢(shì),考慮如何依序錄取新租戶多租戶應(yīng)用程序可能分配租戶碎片中的數(shù)據(jù)存儲(chǔ)。當(dāng)使用范圍的策略,租戶1到n的數(shù)據(jù)都將存儲(chǔ)在分片 A 中,數(shù)據(jù)為住戶的 n+1 到 m 都將存儲(chǔ)在分片 B,依此類推。如果最近登記的租戶也是最活躍,最數(shù)據(jù)活動(dòng)將發(fā)生在少數(shù)碎片,這可能會(huì)導(dǎo)致熱點(diǎn)。與此相反,哈希策略分配租戶基于對(duì)其租戶ID的散列碎片。這意味著順序租戶是最有可能被分配到不同的碎片,如圖 3 所示為住戶 55 和 56,這將在這些碎片分配負(fù)載。
下表列出的主要優(yōu)點(diǎn)和考慮這三個(gè)分片策略。
Lookup 查找
更好地控制碎片的配置和使用方式。
重新平衡數(shù)據(jù)時(shí),因?yàn)樾碌奈锢矸謪^(qū)可以被添加到拉平工作量使用虛擬碎片減少的影響??梢栽诓挥绊懯褂靡粋€(gè)分片鍵來存儲(chǔ)和檢索數(shù)據(jù)的應(yīng)用程序代碼被修改的虛擬碎片和實(shí)現(xiàn)該分片的物理分區(qū)之間的映射。
Range 范圍
易于實(shí)現(xiàn)和使用范圍查詢工作得很好,因?yàn)樗鼈兺ǔ?梢匀≡趩蝹€(gè)操作中從單個(gè)分片的多個(gè)數(shù)據(jù)項(xiàng)。
更簡(jiǎn)便的數(shù)據(jù)管理。例如,如果用戶在相同的區(qū)域是在相同的子庫(kù),更新可以安排在基于本地負(fù)載和需求模式的每個(gè)時(shí)區(qū)。
Hash 哈希
一個(gè)甚至更多的數(shù)據(jù)和負(fù)荷分布的更好的機(jī)會(huì)。
請(qǐng)求路由可以直接通過使用哈希函數(shù)來實(shí)現(xiàn)。沒有必要來維護(hù)一個(gè)地圖。
最常見的拆分方案實(shí)現(xiàn)上述方法之一,但你也應(yīng)該考慮你的應(yīng)用程序的業(yè)務(wù)需求和他們的數(shù)據(jù)使用模式。例如,在一個(gè)多用戶應(yīng)用:
每個(gè)分片策略意味著不同的功能和復(fù)雜性管理的規(guī)模,向外擴(kuò)展,數(shù)據(jù)移動(dòng),并保持水平狀態(tài)。
查找策略允許縮放和數(shù)據(jù)移動(dòng)操作來進(jìn)行,在用戶層面,無論是在線還是離線。該技術(shù)暫停部分或全部用戶活動(dòng)(也許是在非高峰時(shí)段),移動(dòng)數(shù)據(jù)到新的虛擬分區(qū)或物理碎片,改變映射,無效或刷新持有該數(shù)據(jù)的緩存,然后讓用戶活動(dòng)恢復(fù)。通常這種類型的操作可以進(jìn)行集中管理。查找戰(zhàn)略要求的狀態(tài)是高度可緩存和副本友好。
的范圍的策略規(guī)定了結(jié)垢和數(shù)據(jù)移動(dòng)操作,這通常必須進(jìn)行時(shí)的一部分或全部的數(shù)據(jù)存儲(chǔ)為脫機(jī),因?yàn)閿?shù)據(jù)必須被分割和整個(gè)碎片合并的一些限制。移動(dòng)的數(shù)據(jù),以重新平衡碎片可能無法解決不均勻負(fù)荷的問題,如果大多數(shù)的活性是對(duì)相鄰分片密鑰或數(shù)據(jù)標(biāo)識(shí)符是相同的范圍之內(nèi)的。范圍的策略可能也需要進(jìn)行維護(hù),以圖范圍內(nèi)的物理分區(qū)的一些狀態(tài)。
哈希策略使得擴(kuò)展和數(shù)據(jù)移動(dòng)操作更為復(fù)雜,因?yàn)榉謪^(qū)鍵是碎片密鑰或數(shù)據(jù)標(biāo)識(shí)符的哈希值。每個(gè)碎片的新位置,必須從散列函數(shù)來確定,或者該函數(shù)修改,以提供正確的映射。然而,哈希策略不需要維護(hù)狀態(tài)。
在決定如何實(shí)現(xiàn)這個(gè)模式時(shí),請(qǐng)考慮以下幾點(diǎn):
注意:在不包括分片鍵也可能導(dǎo)致問題字段自動(dòng)遞增值。例如,如果您使用自增字段來生成唯一標(biāo)識(shí),并分布在不同的碎片兩個(gè)不同的項(xiàng)目可能被分配相同的ID。
注意:如果在一個(gè)子庫(kù)的實(shí)體引用存儲(chǔ)在另一個(gè)分片的一個(gè)實(shí)體,包括分片鍵用于第二實(shí)體,作為第一實(shí)體的架構(gòu)的一部分。這可以幫助提高引用跨碎片相關(guān)數(shù)據(jù)查詢的性能。
注意:如果在多個(gè)分塊的變化保持的基準(zhǔn)數(shù)據(jù),該系統(tǒng)必須同步所有碎片這些變化。而此同步發(fā)生時(shí),系統(tǒng)可能會(huì)出現(xiàn)一定程度的混亂。如果你按照這種方法,你應(yīng)該設(shè)計(jì)自己的應(yīng)用程序能夠處理這個(gè)矛盾。
使用這種模式:
注意:分片的主要焦點(diǎn)是改進(jìn)系統(tǒng)的性能和可擴(kuò)展性,而作為副產(chǎn)物,也可以借助于其中數(shù)據(jù)被劃分成單獨(dú)的分區(qū)的方式提高可用性。在一個(gè)分區(qū)中的故障不一定阻止應(yīng)用程序訪問的其他分區(qū)中保存的數(shù)據(jù),并且操作者無需使得整個(gè)數(shù)據(jù)為應(yīng)用程序無法訪問的可以執(zhí)行的一個(gè)或多個(gè)分區(qū)的維護(hù)或復(fù)原。欲了解更多信息,請(qǐng)參閱數(shù)據(jù)分區(qū)指導(dǎo)。
下面的示例使用了一組充當(dāng)碎片的 SQL Server 數(shù)據(jù)庫(kù)。每個(gè)數(shù)據(jù)庫(kù)包含一個(gè)應(yīng)用程序使用的數(shù)據(jù)的一個(gè)子集。應(yīng)用程序檢索該被分布在整個(gè)碎片通過使用它自己的分片邏輯(這是一個(gè)扇出查詢的一個(gè)例子)的數(shù)據(jù)。將位于每個(gè)子庫(kù)中的數(shù)據(jù)的細(xì)節(jié)是通過這樣的方法稱為 GetShards 返回。此方法返回 ShardInformation 對(duì)象,其中 ShardInformation 類型包含一個(gè)標(biāo)識(shí)符為每個(gè)碎片和 SQL Server 的連接字符串,應(yīng)用程序應(yīng)該使用連接到碎片的枚舉列表(在連接字符串中沒有代碼示例所示)。
private IEnumerable<ShardInformation> GetShards()
{
// This retrieves the connection information from a shard store
// (commonly a root database).
return new[]
{
new ShardInformation
{
Id = 1,
ConnectionString = ...
},
new ShardInformation
{
Id = 2,
ConnectionString = ...
}
};
}
下面的代碼顯示了如何在應(yīng)用程序使用 ShardInformation 對(duì)象名單進(jìn)行了從并行每個(gè)碎片獲取數(shù)據(jù)的查詢。查詢的細(xì)節(jié)沒有示出,但在本實(shí)施例中所檢索的數(shù)據(jù)包括可以存放信息,如客戶的名稱,如果碎片包含客戶的細(xì)節(jié)的字符串。該結(jié)果由應(yīng)用聚集成 ConcurrentBag 集合進(jìn)行處理。
// Retrieve the shards as a ShardInformation[] instance.
var shards = GetShards();
?
var results = new ConcurrentBag<string>();
?
// Execute the query against each shard in the shard list.
// This list would typically be retrieved from configuration
// or from a root/master shard store.
Parallel.ForEach(shards, shard =>
{
// NOTE: Transient fault handling is not included,
// but should be incorporated when used in a real world application.
using (var con = new SqlConnection(shard.ConnectionString))
{
con.Open();
var cmd = new SqlCommand("SELECT ... FROM ...", con);
?
Trace.TraceInformation("Executing command against shard: {0}", shard.Id);
?
var reader = cmd.ExecuteReader();
// Read the results in to a thread-safe data structure.
while (reader.Read())
{
results.Add(reader.GetString(0));
}
}
});
?
Trace.TraceInformation("Fanout query complete - Record Count: {0}",
results.Count);
更多建議: