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