設計適用于 Azure 資料表儲存體的可調整資料分割策略

本文討論在 Azure 資料表儲存體中分割資料表,以及可用來確保有效率延展性的策略。

Azure 提供高可用性且可高度擴充的雲端儲存體。 Azure 的基礎儲存體系統是透過一組服務提供,包括 Azure Blob 儲存體、Azure 資料表儲存體、Azure 佇列儲存體和Azure 檔案儲存體。

Azure 資料表儲存體的設計目的是儲存結構化資料。 Azure 儲存體服務支援無限數量的資料表。 每個資料表都可以調整為大量層級,並提供數 TB 的實體儲存體。 若要充分利用資料表,您必須以最佳方式分割資料。 本文將探索可用來有效率地分割 Azure 資料表儲存體資料的策略。

資料表實體

資料表實體代表儲存在資料表中的資料單位。 資料表實體類似于一般關係資料庫資料表中的資料列。 每一個實體定義一組屬性。 每個屬性都會依其名稱、值和值的資料類型,定義為索引鍵/值組。 實體的屬性集合中必須定義下列三個系統屬性:

  • PartitionKeyPartitionKey 屬性會儲存字串值,以識別實體所屬的資料分割。 我們稍後討論的資料分割是資料表延展性不可或缺的一部分。 具有相同 PartitionKey 值的實體會儲存在相同的分割區中。

  • RowKeyRowKey 屬性會儲存可唯一識別每個資料分割內實體的字串值。 PartitionKeyRowKey一起形成實體的主鍵。

  • TimestampTimestamp 屬性提供實體的可追蹤性。 時間戳記是日期/時間值,會告訴您上次修改實體的時間。 時間戳記有時稱為實體 的版本。 因為資料表服務會在所有插入和更新作業期間維護此屬性的值,所以會忽略時間戳記的修改。

資料表主鍵

Azure 實體的主鍵是由合併的 PartitionKeyRowKey 屬性所組成。 這兩個屬性形成資料表內的單一叢集索引。 PartitionKeyRowKey屬性最多可儲存 1 KiB 的字串值。 也允許空字串;不過,不允許 Null 值。

叢集索引會依 PartitionKey 的遞增順序排序,然後依 RowKey 的遞增順序排序。 所有查詢回應中都遵守此排序次序。 排序作業期間會使用語彙比較。 字串值 「111」 會出現在字串值 「2」 之前。 在某些情況下,您可能會希望排序次序為數值。 若要以數值和遞增順序排序,您必須使用固定長度、零填補字串。 在上述範例中,「002」 會出現在 「111」 之前。

資料表的資料分割

資料分割代表具有相同 PartitionKey 值的實體集合。 資料分割一律會從一部資料分割伺服器提供服務。 每個資料分割伺服器都可以提供一或多個分割區。 對於一個資料分割在一段時間內可提供的實體數量,資料分割伺服器有一定的速率限制。 具體而言,資料分割的延展性目標為每秒 2000 個實體。 在儲存體節點上的最小負載期間,此輸送量可能會較高,但當節點變成作用中或作用中時,會進行節流。

為了進一步說明資料分割的概念,下圖顯示一個資料表,其中包含一小部分的資料進行腳部競爭事件註冊。 此圖呈現資料分割的概念檢視,其中 PartitionKey 包含三個不同的值:事件的名稱結合三個距離, (完整 marathon、半 marathon 和 10 km) 。 此範例使用兩部資料分割伺服器。 伺服器 A 包含半 marathon 和 10 公里距離的註冊。 伺服器 B 只包含完整的 marathon 距離。 RowKey值會顯示為提供內容,但此範例的值不有意義。

顯示具有三個數據分割AZU_CH03_Figure1資料表的圖表
具有三個資料分割的資料表

延展性

因為資料分割一律由單一資料分割伺服器提供,而每一個資料分割伺服器可以提供一或多個資料分割,所以提供實體的效率與伺服器的健康情況有關。 遇到其分割區高流量的伺服器可能無法維持高輸送量。 例如,在上圖中,如果收到「2011 紐約市Marathon__Half」的許多要求,伺服器 A 可能會變得太忙碌。 為了提高伺服器輸送量,儲存系統會將資料分割的負載分攤給其他伺服器。 結果,流量會分散到其他許多伺服器。 為了達到最佳的流量負載平衡,您應該使用更多分割區,讓 Azure 資料表儲存體可以將分割區分散到更多資料分割伺服器。

實體群組交易

實體群組交易是在具有相同 PartitionKey 值的實體上以不可部分完成方式實作的一組儲存體作業。 如果實體群組中的任何儲存體作業失敗,則會復原實體中的所有儲存體作業。 實體群組交易包含不超過 100 個儲存體作業,且大小可能不超過 4 MiB。 實體群組交易提供 Azure 資料表儲存體,其形式為不可部分完成性、一致性、隔離和持久性, (關係資料庫所提供的 ACID) 語意。

實體群組交易可改善輸送量,因為它們會減少必須提交至 Azure 資料表儲存體的個別儲存體作業數目。 實體群組交易也提供經濟優勢。 不論它包含多少個儲存體作業,實體群組交易都會以單一儲存體作業計費。 由於實體群組交易中的所有儲存體作業都會影響具有相同 PartitionKey 值的實體,因此需要使用實體群組交易可驅動 PartitionKey 值的選取。

範圍分割區

如果您針對實體使用唯一 的 PartitionKey 值,則每個實體都屬於自己的分割區。 如果您使用的值增加或減少的唯一值,Azure 可能會建立範圍分割區。 範圍分割區會群組具有循序唯一 PartitionKey 值的實體,以改善範圍查詢的效能。 如果沒有範圍資料分割,範圍查詢必須跨越分割區界限或伺服器界限,這可能會降低查詢效能。 請考慮使用下表的應用程式,其具有 PartitionKey的遞增順序值:

PartitionKey RowKey
"0001" -
"0002" -
"0003" -
"0004" -
"0005" -
"0006" -

Azure 可能會將前三個實體分組為範圍分割區。 如果您將範圍查詢套用至使用 PartitionKey 作為準則的資料表,並要求從 「0001」 到 「0003」 的實體,查詢可能會有效率地執行,因為實體是從單一資料分割伺服器提供。 不保證何時及如何建立範圍分割區。

如果您插入具有增加或減少 PartitionKey 值的實體,資料表的範圍資料分割可能會影響插入作業的效能。 插入具有增加 PartitionKey 值的實體稱為僅限附加模式。 插入具有遞減值的實體稱為僅限前置模式。 請考慮不使用這類模式,因為插入要求的整體輸送量受限於單一資料分割伺服器。 這是因為,如果範圍分割存在,則第一個和最後一個 (範圍) 分割區分別包含最小和最大的 PartitionKey 值。 因此,插入具有循序較低或更高 PartitionKey 值的新實體,會以其中一個結束資料分割為目標。 下圖顯示一組可能以上述範例為基礎的範圍分割區。 如果插入了一組 「0007」、「0008」 和 「0009」 實體,則會指派給最後一個 (橙色) 分割區。

顯示一組範圍分割AZU_CH03_Figure2的圖表
一組範圍分割區

請務必注意,如果插入作業使用更分散的 PartitionKey 值,則效能不會有任何負面影響。

分析資料

不同于關係資料庫中可用來管理索引的資料表,Azure 資料表儲存體中的資料表只能有一個索引。 Azure 資料表儲存體中的索引一律包含 PartitionKeyRowKey 屬性。

在 Azure 資料表中,您不需要藉由新增更多索引,或在推出資料表之後改變現有的資料表,來調整資料表的效能。您必須在設計資料表時分析資料。 為了獲得最佳延展性和查詢和插入效率,要考慮的最重要層面是 PartitionKeyRowKey 值。 本文強調如何選擇 PartitionKey ,因為它與資料表的分割方式直接相關。

分割大小

資料分割大小是指資料分割包含的實體數量。 如延 展性所述,擁有更多分割區表示您獲得更好的負載平衡。 PartitionKey值的資料細微性會影響分割區的大小。 在粗略層級,如果使用單一值做為 PartitionKey,則所有實體都位於非常大的單一分割區中。 在最精細的細微性層級上, PartitionKey 可以包含每個實體的唯一值。 結果是每個實體都有一個分割區。 下表顯示資料細微性範圍的優缺點:

PartitionKey 資料細微性 分割區大小 優點 缺點
單一值 少量實體 任何實體都可能進行批次交易。

所有實體都是本機實體,並從相同的儲存體節點提供服務。
單一值 大量實體 任何實體都可以使用實體群組交易。 如需實體群組交易限制的詳細資訊,請參閱 執行實體群組交易 延展性受限。

輸送量受限於單一伺服器的效能。
多個值 多個分割區

資料分割大小取決於實體散發。
某些實體可以進行批次交易。

動態資料分割是可行的。

單一要求查詢可能 (沒有接續權杖) 。

可以跨更多分割區伺服器進行負載平衡。
跨分割區的實體分佈高度不平均,可能會限制較大且更作用中分割區的效能。
唯一值 許多小型分割區 資料表可高度擴充。

範圍分割區可能會改善跨分割區範圍查詢的效能。
涉及範圍的查詢可能需要造訪多個伺服器。

不支援批次交易。

僅限附加或僅限附加模式可能會影響插入輸送量。

下表顯示 PartitionKey 值如何影響縮放比例。 最佳做法是偏好較小的分割區,因為它們提供更佳的負載平衡。 在某些情況下,較大的分割區可能適用,而且不一定是缺點。 例如,如果您的應用程式不需要延展性,則單一大型分割區可能適用。

判斷查詢

查詢會從資料表擷取資料。 當您分析 Azure 資料表儲存體中資料表的資料時,請務必考慮應用程式將使用的查詢。 如果應用程式有數個查詢,您可能必須排定其優先順序,雖然您的決策可能具有主旨。 在許多情況下,主要查詢可以與其他查詢辨識。 在效能方面,查詢分成不同類別。 因為資料表只有一個索引,所以查詢效能通常與 PartitionKeyRowKey 屬性有關。 下表顯示不同類型的查詢及其效能評等:

查詢類型 PartitionKey 比對 RowKey 比對 效能評等
資料列範例掃描 精確 Partial 較小型的資料分割較佳。

使用非常大型的資料分割時發生錯誤。
資料分割範圍掃描 Partial Partial 適合使用少量的資料分割伺服器。

更糟的是,有更多伺服器受到觸控。
完整資料表掃描 部分,無 部分,無 更糟的是,掃描的資料分割子集。

掃描所有分割區最差。

注意

表格中定義彼此相對的效能評等。 分割區的數目和大小最終可能會決定查詢的執行方式。 例如,分割區範圍掃描具有許多大型分割區的資料表,相較于具有少數小型資料分割之資料表的完整資料表掃描,可能會效能不佳。

上表中所列的查詢類型會根據其效能評等,顯示從最佳查詢類型到最差類型的進度。 點查詢是最佳的查詢類型,因為完全使用資料表的叢集索引。 下列點查詢會使用腳部競爭註冊資料表中的資料:

http://<account>.windows.core.net/registrations(PartitionKey=”2011 New York City Marathon__Full”,RowKey=”1234__John__M__55”)  
  

如果應用程式使用多個查詢,則不可能全部都是點查詢。 在效能方面,範圍查詢低於點查詢。 有兩種類型的範圍查詢:資料列範圍掃描和資料分割範圍掃描。 資料列範圍掃描指定單一資料分割。 由於作業發生在單一資料分割伺服器上,因此資料列範圍掃描通常比資料分割範圍掃描更有效率。 不過,資料列範圍掃描效能的一個重要因素是選擇性查詢的效能。 查詢選擇性決定必須逐一查看多少資料列才能找到相符的資料列。 在資料列範圍掃描期間,查詢的選擇性越高,越有效率。

若要評估查詢的優先順序,請考慮每個查詢的頻率和回應時間需求。 經常執行的查詢可能會優先順序較高。 不過,重要但很少使用的查詢可能會有低延遲需求,可能會將它排名在優先順序清單上較高。

選擇 PartitionKey 值

任何資料表設計的核心是其延展性、用來存取它的查詢,以及儲存體作業需求。 您選擇的 PartitionKey 值會決定如何分割資料表,以及您可以使用的查詢類型。 儲存體作業,特別是插入,也可能會影響您選擇的 PartitionKey 值。 PartitionKey值的範圍可以從單一值到唯一值。 您也可以使用多個值來建立它們。 您可以使用實體屬性來形成 PartitionKey 值。 或者,應用程式可以計算值。 下列各節將討論重要的考慮。

實體群組交易

開發人員應該先考慮應用程式是否會使用實體群組交易 (批次更新) 。 實體群組交易需要實體具有相同 的 PartitionKey 值。 此外,由於批次更新適用于整個群組,因此 PartitionKey 值的選擇可能會受到限制。 例如,維護現金交易的銀行業應用程式必須自動將現金交易插入至資料表。 現金交易同時代表轉帳和信用端,而且必須淨為零。 這項需求表示帳戶號碼不能當做 PartitionKey 值的任何部分使用,因為交易的每一端都會使用不同的帳戶號碼。 相反地,交易識別碼可能是較佳的選擇。

資料分割

分割區編號和大小會影響載入中資料表的延展性。 它們也會受到 PartitionKey 值的細微程度所控制。 根據資料分割大小來判斷 PartitionKey 可能很困難,特別是當值的分佈難以預測時。 根據經驗法則,建議使用多個較小的資料分割。 許多資料表分割可讓您更輕鬆地讓 Azure 資料表儲存體管理從中提供資料分割的儲存體節點。

PartitionKey 選擇唯一或更精細的值,會導致較小的資料分割,但更多資料分割。 這通常比較好,因為系統可以負載平衡許多分割區,以將負載分散到多個分割區。 不過,對於跨資料分割的範圍查詢,您應該考量較多資料分割所產生的效果。 這些類型的查詢必須造訪多個分割區以滿足查詢。 分割區可能會分散到許多資料分割伺服器。 如果查詢跨越伺服器界限,則必須傳回接續 Token。 接續標記會指定下一個 PartitionKeyRowKey 值,以擷取查詢的下一組資料。 換句話說,接續權杖至少代表一個對服務的要求,這可能會降低查詢的整體效能。

查詢選擇性是另一個會影響查詢效能的因素。 查詢選擇性可測量每一個資料分割必須逐一查看多少資料列。 查詢越有選擇性,查詢在傳回您想要的資料列時越有效率。 範圍查詢的整體效能可能取決於必須觸及的資料分割伺服器數目,或查詢的選擇性程度。 當您將資料插入資料表時,也應該避免使用僅限附加或僅附加模式。 如果您使用這些模式,儘管建立小型和許多分割區,您可能會限制插入作業的輸送量。 僅附加和僅附加模式會在 Range 資料分割中討論。

查詢

瞭解您將使用的查詢可協助您判斷 針對 PartitionKey 值考慮哪些屬性很重要。 您在查詢中使用的屬性是 PartitionKey 值的候選項目。 下表提供如何判斷 PartitionKey 值的一般指導方針:

如果實體... 動作
有一個索引鍵屬性 使用它作為 PartitionKey
有兩個索引鍵屬性 使用一個作為 PartitionKey ,另一個則作為 RowKey
有兩個以上的索引鍵屬性 使用串連值的複合索引鍵。

如果有一個以上相同的基準查詢,您可以使用您需要的不同 RowKey 值多次插入資訊。 您的應用程式將會管理次要 (或第三個,依此類) 資料列。 您可以使用這種類型的模式來滿足查詢的效能需求。 下列範例會使用來自腳部競爭註冊範例的資料。 它有兩個主要查詢:

  • 依 bib 號碼查詢
  • 依年齡查詢

為了處理這兩個支配查詢,插入兩個資料列當作實體群組交易。 下表顯示此案例的 PartitionKeyRowKey 屬性。 RowKey值會提供 bib 和 age 的前置詞,讓應用程式可以區分這兩個值。

PartitionKey RowKey
2011 New York City Marathon__Full BIB:01234__John__M__55
2011 New York City Marathon__Full AGE:055__1234__John__M

在此範例中,實體群組交易是可行的,因為 PartitionKey 值相同。 群組交易提供插入作業的不可部分完成性。 雖然此模式可以搭配不同的 PartitionKey 值使用,但建議您使用相同的值來獲得這項好處。 否則,您可能必須撰寫額外的邏輯,以確保使用不同 PartitionKey 值的不可部分完成交易。

儲存體作業

Azure 資料表儲存體中的資料表可能不只會從查詢載入。 它們也可能會遇到來自儲存體作業的負載,例如插入、更新和刪除。 請考慮您將在資料表上執行的儲存體作業類型,以及速率為何。 如果您不常執行這些作業,您可能不需要擔心這些作業。 不過,對於像是在短時間內執行許多插入的頻繁作業,您必須考慮這些作業如何因您選擇的 PartitionKey 值而提供。 重要範例是僅限附加和僅限附加的模式。 僅附加和僅附加模式會在 Range 資料分割中討論。

當您使用僅限附加或僅附加模式時,會在後續插入時,針對 PartitionKey 使用唯一的遞增或遞減值。 如果您結合此模式與頻繁的插入作業,您的資料表將無法以絕佳的延展性來服務插入作業。 您的資料表延展性會受到影響,因為 Azure 無法對其他資料分割伺服器對作業要求進行負載平衡。 在此情況下,您可能想要考慮使用隨機的值,例如 GUID 值。 然後,您的分割區大小可能會保持小,而且仍會在儲存體作業期間維持負載平衡。

資料表分割壓力測試

PartitionKey 值很複雜或需要與其他 PartitionKey 對應的比較時,您可能需要測試資料表的效能。 此測試應該檢查資料分割在尖峰負載下的表現。

執行壓力測試

  1. 建立測試資料表
  2. 使用資料載入測試資料表,使其包含具有您目標 PartitionKey 值的實體。
  3. 使用應用程式模擬資料表的尖峰負載。 使用步驟 2 的 PartitionKey 值,以單一資料分割為目標。 此步驟對於每個應用程式都不同,但模擬應該包含所有必要的查詢和儲存體作業。 您可能需要調整應用程式,使其以單一分割區為目標。
  4. 檢查 GET 或 PUT 作業在資料表上的輸送量。

若要檢查輸送量,請比較實際值與單一伺服器上單一資料分割的指定限制。 分割區每秒限制為 2000 個實體。 如果分割區的輸送量超過每秒 2000 個實體,伺服器可能會在生產設定中執行太忙碌。 在此情況下, PartitionKey 值可能太粗略,因此沒有足夠的資料分割或分割區太大。 您可能需要修改 PartitionKey 值,讓分割區分散到更多伺服器。

負載平衡

當分割區太熱時,就會發生分割層的負載平衡。 當分割區太忙碌時,分割區特別是資料分割伺服器會運作超過其目標延展性。 針對 Azure 儲存體,每個分割區每秒都有 2000 個實體的延展性目標。 負載平衡也會發生在分散式檔案系統 (DFS) 層。

DFS 層的負載平衡會處理 I/O 負載,而且不在本文的範圍內。 超出延展性目標之後,分割層的負載平衡不會立即發生。 相反地,系統會在開始負載平衡程式之前等候幾分鐘。 這樣可確定資料分割已確實變得忙碌。 由於系統會自動執行工作,因此不需要以產生負載來觸發負載平衡的品質分割。

如果資料表已使用特定負載來定型,則系統可能會根據實際負載平衡分割區,這會導致分割區分佈明顯不同。 請考慮撰寫處理逾時和伺服器忙碌錯誤的程式碼,而不是預備資料分割。 當系統進行負載平衡時,會傳回錯誤。 藉由使用重試策略處理這些錯誤,您的應用程式可以更有效地處理尖峰負載。 下一節詳細討論重試策略。

發生負載平衡時,分割區會離線幾秒鐘。 在離線期間,系統會將分割區重新指派給不同的分割區伺服器。 請務必注意,您的資料不會由資料分割伺服器儲存。 反之,資料分割伺服器會從 DFS 層提供實體。 因為您的資料不會儲存在分割層,所以將資料分割移至不同的伺服器是快速的程式。 此彈性可大幅限制您的應用程式可能會遇到的停機時間。

重試策略

請務必讓應用程式處理儲存體作業失敗,以確保您不會遺失任何資料更新。 某些失敗不需要重試策略。 例如,傳回 401 未經授權錯誤的更新無法受益于重試作業,因為應用程式狀態可能不會在解決 401 錯誤的重試之間變更。 不過,伺服器忙碌或逾時之類的錯誤與 Azure 的負載平衡功能相關,可提供資料表延展性。 當服務實體的儲存體節點變成經常性存取時,Azure 會藉由將分割區移至其他節點來平衡負載。 在此期間,資料分割可能會無法存取,這會導致伺服器忙碌或逾時錯誤。 最後,重新啟用分割區,並繼續更新。

重試策略適用于伺服器忙碌或逾時錯誤。 在大部分情況下,您可以從重試邏輯中排除 400 個層級的錯誤和一些 500 層級的錯誤。 可以排除的錯誤包括 501 未實作和不支援 505 HTTP 版本。 然後,您可以針對最多 500 個層級的錯誤實作重試策略,例如伺服器忙碌 (503) 和逾時 (504) 。

您可以選擇應用程式的三種常見重試策略:

  • 無重試:未嘗試重試。
  • 已修正輪詢:作業會以常數輪詢值重試 N 次。
  • 指數輪詢:使用指數輪詢值重試 N 次作業。

「不重試」策略是處理作業失敗的一種簡單 (規避) 的方法。 不過,沒有重試策略並不實用。 不強制任何重試很可能在失敗作業之後無法正確儲存資料。 更好的策略是使用固定輪詢策略。 可讓您使用相同的輪詢持續時間重試作業。

不過,策略並未針對處理高度可調整的資料表進行優化。 如果許多執行緒或進程正在等候相同的持續時間,可能會發生衝突。 建議的重試策略是使用指數輪詢的重試策略,其中每個重試嘗試的時間超過上次嘗試的時間。 它類似于電腦網路中使用的衝突避免演算法,例如乙太網路。 指數型輪詢使用隨機因子來提供結果間隔的額外變化。 然後將輪詢值限制在上下限之間。 下列公式採用指數型演算法來計算下一個輪詢值:

y = Rand(0.8z, 1.2z)(2x-1

y = Min(zmin + y, zmax

其中:

z = 預設輪詢 (以亳秒為單位)

zmin = 預設最小輪詢 (以亳秒為單位)

zmax = 預設最大輪詢 (以亳秒為單位)

x = 重試次數

y = 輪詢值 (以亳秒為單位)

Rand (隨機) 函式中使用的 0.8 和 1.2 乘數會產生原始值±20% 內預設輪詢的隨機變異數。 大部分重試策略都可以接受±20% 的範圍,而且可防止進一步的衝突。 您可以使用下列程式碼來實作公式:

int retries = 1;  
  
// Initialize variables with default values  
var defaultBackoff = TimeSpan.FromSeconds(30);  
var backoffMin = TimeSpan.FromSeconds(3);  
var backoffMax = TimeSpan.FromSeconds(90);  
  
var random = new Random();  
  
double backoff = random.Next(  
    (int)(0.8D * defaultBackoff.TotalMilliseconds),   
    (int)(1.2D * defaultBackoff.TotalMilliseconds));  
backoff *= (Math.Pow(2, retries) - 1);  
backoff = Math.Min(  
    backoffMin.TotalMilliseconds + backoff,   
    backoffMax.TotalMilliseconds);  
  

總結

Azure 資料表儲存體中的應用程式可以儲存大量資料,因為資料表儲存體會管理及重新指派多個儲存體節點的分割區。 您可以使用資料分割來控制資料表的延展性。 在定義資料表架構時事先規劃,以確保您實作有效率的資料分割策略。 具體而言,請先分析應用程式的需求、資料和查詢,再選取 PartitionKey 值。 當系統回應流量時,每個分割區可能會重新指派給不同的儲存體節點。 使用資料分割壓力測試來確保資料表具有正確的 PartitionKey 值。 此測試可協助您判斷資料分割何時太忙碌,並協助您進行必要的分割區調整。

若要確保您的應用程式處理間歇性錯誤,並保存您的資料,請使用重試策略搭配輪詢。 Azure 儲存體用戶端程式庫使用的預設重試原則具有指數輪詢,可避免衝突,並將應用程式的輸送量最大化。