共用方式為


使用叢集資源管理員描述 Service Fabric Cluster

Azure Service Fabric 的叢集資源管理員功能提供數種用來描述叢集的機制:

  • 容錯網域
  • 升級網域
  • 節點內容
  • 節點容量

在執行階段,叢集資源管理員會使用這些資訊來確保叢集中執行之服務的高可用性。 在強制執行這些重要規則的同時,它也會嘗試最佳化叢集內的資源使用。

容錯網域

容錯網域是任何發生協同失敗的區域。 單一機器即是一個容錯網域。 它可能因各種原因而自行失敗,從電源供應故障、磁碟故障到 NIC 韌體不良。

連接到同一個乙太網路交換器的機器位於相同的容錯網域。 共用單一電源來源或位於同一個位置的機器亦然。

由於硬體故障自然會重疊,容錯網域本質上具備階層式結構。 Service Fabric 以 URI 來表示它們。

正確設定容錯網域相當重要,因為 Service Fabric 會使用這些資訊來安全地放置服務。 Service Fabric 不希望放置服務的方式會在某個容錯網域喪失 (由某個元件故障所造成) 時,導致服務停止。

在 Azure 環境中,Service Fabric 會使用環境所提供的容錯網域資訊,代表您正確地設定叢集中的節點。 對於獨立部署的 Service Fabric 執行個體,容錯網域會在設定叢集時定義。

警告

提供給 Service Fabric 的容錯網域資訊必須準確,這一點相當重要。 例如,假設您的 Service Fabric Cluster 節點執行在 10 部虛擬機器中,而這些虛擬機器執行在 5 部實體主機上。 在此情況下,即使有 10 部虛擬機器,仍然只有 5 個不同的 (最上層) 容錯網域。 共用相同的實體主機會使 VM 共用相同的根容錯網域,因為當實體主機失敗時,VM 會經歷協同失敗。

Service Fabric 期望節點的容錯網域不會變更。 確保 VM 高可用性的其他機制,例如 HA-VMs,可能會與 Service Fabric 發生衝突。 這些機制會在主機之間透明地移轉 VM。 它們不會重新設定或通知 VM 內正在執行的程式碼。 因此,這些環境不支援作為執行 Service Fabric Cluster 的環境。

Service Fabric 應該成為唯一採用的高可用性技術。 即時 VM 移轉與 SAN 等機制並非必要。 如果這些機制與 Service Fabric 一起使用,它們會降低應用程式的可用性與可靠性。 原因在於它們引入額外的複雜性、增加集中式失敗來源,並使用與 Service Fabric 相衝突的可靠性與可用性策略。

在下列圖形中,我們會以顏色標示所有構成容錯網域的實體,並列出所有產生的不同容錯網域。 在此範例中,我們有資料中心 (DC)、機架 (R) 與刀鋒伺服器 (B)。 如果每個刀鋒伺服器承載多個虛擬機器,容錯網域階層中可能還會有另一層。

透過容錯網域組織的節點

在執行階段,Service Fabric 叢集資源管理員會考量叢集中的容錯網域並規劃配置。 某個服務的具狀態複本或無狀態執行個體會被分散放置,使其位於不同的容錯網域中。 將服務分散到不同容錯網域,可確保當階層中任一層級的容錯網域失效時,服務的可用性不會受到影響。

叢集資源管理員不在意容錯網域階層中有多少層。 它會嘗試確保階層中任何一個部分的喪失,都不會影響在其中執行的服務。

若容錯網域階層的每一個深度層級都有相同數量的節點,效果會最好。 如果叢集中的容錯網域「樹狀結構」不平衡,叢集資源管理員就較難判斷最佳的服務配置方式。 不平衡的容錯網域配置代表某些網域的喪失,對服務可用性的影響會比其他網域更大。 因此,叢集資源管理員會在兩個目標之間拉扯:

  • 它希望透過在「節點較多」的網域上放置服務來使用這些機器。
  • 它也希望將服務放置在其他網域中,避免單一網域的喪失造成問題。

不平衡的網域會是什麼樣子? 下列圖表顯示兩種不同的叢集配置。 在第一個範例中,節點平均分散在各個容錯網域。 在第二個範例中,其中一個容錯網域的節點數量遠多於其他容錯網域。

兩種不同的叢集配置

在 Azure 中,節點屬於哪一個容錯網域會由系統替您管理。 但根據您佈建的節點數量,仍可能出現某些容錯網域中的節點數量多於其他網域的情況。

例如,假設叢集中有五個容錯網域,但您為某個節點類型佈建了七個節點 (NodeType)。 在此情況下,前兩個容錯網域最後會擁有較多節點。 如果您持續部署更多只有少量執行個體的 NodeType,這個問題會變得更嚴重。 基於這個原因,我們建議每一個節點類型中的節點數量,應該是容錯網域數量的倍數。

升級網域

升級網域是另一項協助 Service Fabric 叢集資源管理員理解叢集配置的功能。 升級網域會定義一組在同一時間進行升級的節點。 升級網域可協助叢集資源管理員理解並協調升級等管理作業。

升級網域與容錯網域非常相似,但有幾個關鍵差異。 首先,容錯網域是由協同硬體失敗的區域所定義。 相對地,升級網域是由原則所定義。 您可以自行決定需要多少個,而不是由環境來決定數量。 升級網域的數量可以與節點數量相同。 容錯網域與升級網域的另一個差異在於,升級網域不是階層式結構。 相反地,它們更像是一個簡單的標記。

下列圖表顯示三個升級網域橫跨三個容錯網域。 圖中也顯示某個具狀態服務的三個不同複本,其中每一個都位於不同的容錯網域與升級網域。 這種配置方式允許在服務升級進行到一半時,即使某個容錯網域喪失,仍然能保有一份程式碼與資料的複本。

結合容錯網域與升級網域的配置

擁有大量升級網域有其優點與缺點。 升級網域越多,每一個升級步驟就越細緻,影響的節點或服務數量也越少。 每次需要移動的服務較少,對系統造成的變動也較小。 這通常能提升可靠性,因為任何升級引入的問題,影響的服務範圍較小。 更多的升級網域也代表,您需要較少的可用緩衝容量來因應升級的影響。

例如,如果您有五個升級網域,每個升級網域中的節點大約會處理 20% 的輸送量。 當需要為其中一個升級網域進行升級並暫停時,負載通常需要轉移到其他地方。 由於還有四個升級網域存在,每一個都必須能承擔約 25% 的總輸送量。 升級網域越多,叢集中節點所需的緩衝容量就越少。

假設您改為使用 10 個升級網域。 在這種情況下,每個升級網域只需處理約 10% 的總輸送量。 當升級在叢集中逐步進行時,每個網域只需要為約 11% 的總輸送量預留空間。 更多的升級網域通常可讓節點在較高的使用率下運作,因為所需保留的容量較少。 容錯網域也是如此。

升級網域數量多的缺點在於,升級作業通常會花費較長時間。 Service Fabric 會在完成一個升級網域後等待一小段時間,並執行檢查,再開始升級下一個網域。 這些延遲可在升級繼續進行前,協助偵測升級所引入的問題。 這樣的取捨是可以接受的,因為它能防止不良變更一次影響過多服務。

升級網域數量過少也會帶來許多負面影響。 在每一個升級網域停機並進行升級期間,您整體容量中的一大部分將無法使用。 例如,如果您只有三個升級網域,每次大約會有三分之一的整體服務或叢集容量被停用。 一次讓這麼多服務下線並不理想,因為您仍需要在叢集的其他部分保有足夠容量來處理工作負載。 維持這些緩衝容量,代表在正常運作期間,這些節點的負載會低於理想狀態。 這會增加執行服務的成本。

在某個環境中,容錯網域或升級網域的總數並沒有實際上限,也沒有它們如何重疊的限制。 但仍有一些常見模式:

  • 容錯網域與升級網域以 1:1 對應
  • 每個節點 (實體或虛擬 OS 執行個體) 對應一個升級網域
  • 一種「條紋式」或「矩陣」模型,其中容錯網域與升級網域形成一個矩陣,機器通常沿著對角線配置。

容錯網域與升級網域的配置

選擇哪一種配置並沒有最佳答案。 每一種都有其優缺點。 例如,1FD:1UD 模型相當容易設定。 每個節點對應一個升級網域的模型,最接近多數人熟悉的方式。 在升級期間,每個節點會各自獨立更新。 這類似於過去手動升級少量機器的方式。

最常見的模型是 FD/UD 矩陣,其中容錯網域與升級網域形成一個表格,節點從對角線開始放置。 這是 Azure 中 Service Fabric Cluster預設使用的模型。 對於具有大量節點的叢集而言,整體外觀會像是一個密集的矩陣模式。

容錯網域與升級網域的限制與其結果行為

最大差分方法

叢集資源管理器的目標是維持服務在故障與升級領域間的平衡。 這會建模為一項限制。 容錯網域與升級網域的限制規則指出:「對於指定的服務分割區,在同一個階層層級中的任何兩個網域之間,服務物件 (無狀態服務執行個體或具狀態服務複本) 的數量差異不得超過一。」

我們可以說,這項限制提供了一個「最大差異」保證。 容錯網域與升級網域的限制會防止違反此規則的移動或配置。

例如,假設我們有一個包含六個節點的叢集,設定了五個容錯網域與五個升級網域。

FD0 FD1 FD2 FD3 FD4
UD0 N1
UD1 N6 N2
UD2 N3
UD3 N4
UD4 N5

現在假設我們建立一個服務,其 TargetReplicaSetSize (或對於無狀態服務而言,InstanceCount) 的值為五。 複本會落在 N1–N5 上。 事實上,不論您建立多少個類似的服務,N6 都不會被使用。 但為什麼會這樣? 讓我們比較目前的配置,以及如果選擇 N6 會發生什麼情況。

以下是我們目前的配置,以及每個容錯網域與升級網域中的複本總數:

FD0 FD1 FD2 FD3 FD4 UDTotal
UD0 R1 1
UD1 R2 1
UD2 R3 1
UD3 R4 1
UD4 R5 1
FDTotal 1 1 1 1 1 -

此配置在每個容錯網域與升級網域中的節點數量上是平衡的。 在每個容錯網域與升級網域中的複本數量上也同樣平衡。 每一個網域都有相同數量的節點與相同數量的複本。

現在,讓我們看看如果使用 N6 而不是 N2,會發生什麼事。 複本將會如何分布?

FD0 FD1 FD2 FD3 FD4 UDTotal
UD0 R1 1
UD1 R5 1
UD2 R2 1
UD3 R3 1
UD4 R4 1
FDTotal 2 0 1 1 1 -

此配置違反了我們對容錯網域限制中「最大差異」保證的定義。 FD0 有兩個複本,而 FD1 則為零。 FD0 與 FD1 之間的差異為二,大於允許的一之最大差異。 由於違反限制,叢集資源管理員不允許這種配置。

同樣地,如果我們選擇 N2 與 N6 (而不是 N1 與 N2),結果會是:

FD0 FD1 FD2 FD3 FD4 UDTotal
UD0 0
UD1 R5 R1 2
UD2 R2 1
UD3 R3 1
UD4 R4 1
FDTotal 1 1 1 1 1 -

此配置在容錯網域方面是平衡的。 但它違反了升級網域限制,因為 UD0 沒有複本,而 UD1 有兩個複本。 這個配置同樣無效,叢集資源管理員不會選擇它。

這種分配具狀態複本或無狀態執行個體的方法,可提供最佳的容錯能力。 當某個網域失效時,遺失的複本或執行個體數量會降到最低。

另一方面,這種方式可能過於嚴格,導致叢集無法充分利用所有資源。 對於某些叢集組態而言,某些節點無法使用。 這可能導致 Service Fabric 無法放置您的服務,並產生警告訊息。 在前述範例中,叢集中的部分節點無法使用 (例如 N6)。 即使您在該叢集中新增節點 (N7–N10),由於容錯網域與升級網域的限制,複本或執行個體仍只會放置在 N1–N5 上。

FD0 FD1 FD2 FD3 FD4
UD0 N1 N10
UD1 N6 N2
UD2 N7 N3
UD3 N8 N4
UD4 N9 N5

具備仲裁安全性的做法

叢集資源管理員支援另一種版本的容錯網域與升級網域限制。 它允許放置,同時仍保證最低程度的安全性。 這種替代限制可以表述為:「對於指定的服務分割區,跨網域的複本分配應確保該分割區不會發生仲裁遺失。」 我們可以說,這項限制提供了一個「仲裁安全」保證。

附註

對於具狀態服務,當某個分割區的大多數複本同時停止運作時,我們將其定義為仲裁遺失。 例如,如果 TargetReplicaSetSize 為五,任何三個複本的集合即代表仲裁。 同樣地,如果 TargetReplicaSetSize 為六,則需要四個複本才能形成仲裁。 在這兩種情況下,如果分割區希望維持正常運作,同一時間最多只能有兩個複本停止運作。

對於無狀態服務而言,並不存在仲裁遺失這種情況。 即使大多數執行個體同時停止運作,無狀態服務仍可正常運作。 因此,本文接下來將聚焦於具狀態服務。

讓我們回到先前的範例。 在使用「仲裁安全」版本的限制時,三種配置全都有效。 即使在第二個配置中 FD0 失效,或在第三個配置中 UD1 失效,分割區仍然保有仲裁。 (大多數複本仍然處於運作狀態。) 在此限制版本下,幾乎總是能夠使用 N6。

「仲裁安全」做法比「最大差異」做法更具彈性。 原因在於,在幾乎任何叢集拓撲中,都更容易找到有效的複本分配方式。 然而,這種做法無法保證最佳的容錯特性,因為某些失敗情境比其他情境更嚴重。

在最糟的情況下,只要一個網域失效再加上一個額外的複本失效,就可能導致大多數複本遺失。 例如,原本在五個複本或執行個體的情況下需要三次失敗才會失去仲裁,現在只需要兩次失敗就可能失去大多數。

調適型做法

由於這兩種做法各有優缺點,我們引入了一種結合這兩種策略的調適型做法。

附註

調適型做法預設使用「最大差異」邏輯,僅在必要時才切換為「仲裁安全」邏輯。 叢集資源管理員會根據叢集與服務的設定,自動判斷需要使用哪一種策略。 透過 設定 將 QuorumBasedLogicAutoSwitch 設為 false,可以停用「quorum 安全模式」的自動切換邏輯。

當下列兩個條件同時成立時,叢集資源管理員會對某個服務使用「以仲裁為基礎」的邏輯:

  • 服務的 TargetReplicaSetSize 可以被容錯網域數量與升級網域數量整除。
  • 節點數量小於或等於容錯網域數量乘以升級網域數量。

請注意,叢集資源管理員會對無狀態與具狀態服務都使用這種做法,即使仲裁遺失對無狀態服務並不相關。

讓我們回到先前的範例,並假設叢集現在有八個節點。 該叢集仍然設定為五個容錯網域與五個升級網域,而在該叢集上執行的某個服務,其 TargetReplicaSetSize 值仍為 5。

FD0 FD1 FD2 FD3 FD4
UD0 N1
UD1 N6 N2
UD2 N7 N3
UD3 N8 N4
UD4 N5

由於所有必要條件皆已滿足,叢集資源管理員會在分配服務時使用「以仲裁為基礎」的邏輯。 這使得 N6–N8 能夠被使用。 在此情況下,一種可能的服務分配方式如下所示:

FD0 FD1 FD2 FD3 FD4 UDTotal
UD0 R1 1
UD1 R2 1
UD2 R3 R4 2
UD3 0
UD4 R5 1
FDTotal 2 1 1 0 1 -

假設您服務的 TargetReplicaSetSize 值降低為 4,叢集資源管理員會注意到這個變更。 由於 TargetReplicaSetSize 已無法再被容錯網域與升級網域數量整除,它會恢復使用「最大差異」邏輯。 結果是,為了將剩餘的四個複本分配到 N1–N5 上,某些複本移動會發生。 如此一來,就不會違反容錯網域與升級網域邏輯中的「最大差異」版本。

在先前的配置中,如果 TargetReplicaSetSize 值為 5,且 N1 從叢集中移除,升級網域的數量就會變成 4。 此時,由於升級網域數量已無法再平均分配服務的 TargetReplicaSetSize 值,叢集資源管理員會再次開始使用「最大差異」邏輯。 結果是,當複本 R1 重新建立時,它必須放置在 N4 上,才能避免違反容錯網域與升級網域的限制。

FD0 FD1 FD2 FD3 FD4 UDTotal
UD0 N/A N/A N/A N/A N/A N/A
UD1 R2 1
UD2 R3 R4 2
UD3 R1 1
UD4 R5 1
FDTotal 1 1 1 1 1 -

附註

當使用「定額安全」邏輯時,必須考慮同一階層層級任兩個域間服務物件(無狀態服務實例或有狀態服務副本)數量可能超過一個。 在設定 MinInstancePercent 設定時,這點應被考慮,因為過高的值可能會延長整體升級時間,甚至導致升級回滾。

設定容錯網域與升級網域

在 Azure 託管的 Service Fabric 部署中,容錯網域與升級網域會自動定義。 Service Fabric 會取得並使用 Azure 提供的環境資訊。

如果您要建立自己的叢集 (或想在開發環境中執行特定拓撲),您可以自行提供容錯網域與升級網域資訊。 在此範例中,我們定義一個包含九個節點的本機開發叢集,橫跨三個資料中心 (每個資料中心有三個機架)。 此叢集也有三個升級網域,以條紋方式跨越這三個資料中心。 以下是 ClusterManifest.xml 中的組態範例:

  <Infrastructure>
    <!-- IsScaleMin indicates that this cluster runs on one box/one single server -->
    <WindowsServer IsScaleMin="true">
      <NodeList>
        <Node NodeName="Node01" IPAddressOrFQDN="localhost" NodeTypeRef="NodeType01" FaultDomain="fd:/DC01/Rack01" UpgradeDomain="UpgradeDomain1" IsSeedNode="true" />
        <Node NodeName="Node02" IPAddressOrFQDN="localhost" NodeTypeRef="NodeType02" FaultDomain="fd:/DC01/Rack02" UpgradeDomain="UpgradeDomain2" IsSeedNode="true" />
        <Node NodeName="Node03" IPAddressOrFQDN="localhost" NodeTypeRef="NodeType03" FaultDomain="fd:/DC01/Rack03" UpgradeDomain="UpgradeDomain3" IsSeedNode="true" />
        <Node NodeName="Node04" IPAddressOrFQDN="localhost" NodeTypeRef="NodeType04" FaultDomain="fd:/DC02/Rack01" UpgradeDomain="UpgradeDomain1" IsSeedNode="true" />
        <Node NodeName="Node05" IPAddressOrFQDN="localhost" NodeTypeRef="NodeType05" FaultDomain="fd:/DC02/Rack02" UpgradeDomain="UpgradeDomain2" IsSeedNode="true" />
        <Node NodeName="Node06" IPAddressOrFQDN="localhost" NodeTypeRef="NodeType06" FaultDomain="fd:/DC02/Rack03" UpgradeDomain="UpgradeDomain3" IsSeedNode="true" />
        <Node NodeName="Node07" IPAddressOrFQDN="localhost" NodeTypeRef="NodeType07" FaultDomain="fd:/DC03/Rack01" UpgradeDomain="UpgradeDomain1" IsSeedNode="true" />
        <Node NodeName="Node08" IPAddressOrFQDN="localhost" NodeTypeRef="NodeType08" FaultDomain="fd:/DC03/Rack02" UpgradeDomain="UpgradeDomain2" IsSeedNode="true" />
        <Node NodeName="Node09" IPAddressOrFQDN="localhost" NodeTypeRef="NodeType09" FaultDomain="fd:/DC03/Rack03" UpgradeDomain="UpgradeDomain3" IsSeedNode="true" />
      </NodeList>
    </WindowsServer>
  </Infrastructure>

此範例針對獨立部署使用 ClusterConfig.json:

"nodes": [
  {
    "nodeName": "vm1",
    "iPAddress": "localhost",
    "nodeTypeRef": "NodeType0",
    "faultDomain": "fd:/dc1/r0",
    "upgradeDomain": "UD1"
  },
  {
    "nodeName": "vm2",
    "iPAddress": "localhost",
    "nodeTypeRef": "NodeType0",
    "faultDomain": "fd:/dc1/r0",
    "upgradeDomain": "UD2"
  },
  {
    "nodeName": "vm3",
    "iPAddress": "localhost",
    "nodeTypeRef": "NodeType0",
    "faultDomain": "fd:/dc1/r0",
    "upgradeDomain": "UD3"
  },
  {
    "nodeName": "vm4",
    "iPAddress": "localhost",
    "nodeTypeRef": "NodeType0",
    "faultDomain": "fd:/dc2/r0",
    "upgradeDomain": "UD1"
  },
  {
    "nodeName": "vm5",
    "iPAddress": "localhost",
    "nodeTypeRef": "NodeType0",
    "faultDomain": "fd:/dc2/r0",
    "upgradeDomain": "UD2"
  },
  {
    "nodeName": "vm6",
    "iPAddress": "localhost",
    "nodeTypeRef": "NodeType0",
    "faultDomain": "fd:/dc2/r0",
    "upgradeDomain": "UD3"
  },
  {
    "nodeName": "vm7",
    "iPAddress": "localhost",
    "nodeTypeRef": "NodeType0",
    "faultDomain": "fd:/dc3/r0",
    "upgradeDomain": "UD1"
  },
  {
    "nodeName": "vm8",
    "iPAddress": "localhost",
    "nodeTypeRef": "NodeType0",
    "faultDomain": "fd:/dc3/r0",
    "upgradeDomain": "UD2"
  },
  {
    "nodeName": "vm9",
    "iPAddress": "localhost",
    "nodeTypeRef": "NodeType0",
    "faultDomain": "fd:/dc3/r0",
    "upgradeDomain": "UD3"
  }
],

附註

當您透過 Azure Resource Manager 定義叢集時,Azure 會指派容錯網域與升級網域。 因此,您在 Azure Resource Manager 範本中對節點類型與虛擬機器擴展集的定義,不會包含容錯網域或升級網域資訊。

節點屬性與放置限制

有時 (事實上,多數時候) 您會希望確保特定工作負載只在叢集中某些類型的節點上執行。 例如,有些工作負載可能需要 GPU 或 SSD,而另一些則不需要。

將特定硬體對準特定工作負載的一個絕佳例子,是幾乎所有的 n 層式架構。 某些機器作為應用程式的前端或提供 API 的一側,並對用戶端或網際網路公開。 其他機器通常具有不同的硬體資源,用來處理計算層或儲存層的工作。 這些機器通常不會直接對用戶端或網際網路公開。

Service Fabric 預期在某些情況下,特定工作負載需要在特定硬體組態上執行。 例如:

  • 既有的 n 層式應用程式已「原樣移轉」到 Service Fabric 環境中。
  • 某個工作負載因效能、規模或安全性隔離的原因,必須在特定硬體上執行。
  • 某個工作負載因原則或資源使用量的原因,需要與其他工作負載隔離。

為了支援這類組態,Service Fabric 提供可套用到節點的標籤。 這些標籤稱為節點屬性放置限制是附加在個別服務上的陳述式,您會選取一或多個節點屬性來使用。 放置限制會定義服務應該在哪裡執行。 限制集合具備可延伸性。 任何索引鍵 / 值組都可以運作。

叢集配置的不同工作負載

內建的節點屬性

Service Fabric 定義了一些可自動使用的預設節點屬性,讓您不必自行定義。 每個節點上定義的預設屬性是 NodeTypeNodeName

例如,您可以寫出如下的放置限制:"(NodeType == NodeType03)"NodeType 是常用的屬性。 它很有用,因為它與某種類型的機器以 1:1 對應。 在傳統 n 層式應用程式中,每一種類型的機器都對應到一種類型的工作負載。

放置限制與節點屬性

放置限制與節點屬性語法

在節點屬性中指定的值可以是字串、布林值或帶正負號的長整數。 服務上的陳述式稱為放置限制,因為它限制服務在叢集中可執行的位置。 限制可以是任何對叢集中節點屬性進行運算的布林陳述式。 這些布林陳述式中可用的有效選取器如下:

  • 用來建立特定陳述式的條件檢查:

    陳述式 語法
    「等於」 "=="
    「不等於」 "!="
    「大於」 「>」
    「大於或等於」 「>=」
    「小於」 「<」
    「小於或等於」 「<=」
  • 用於分組與邏輯運算的布林陳述式:

    陳述式 語法
    「且」 "&&"
    「或」 "||"
    「非」 "!"
    「將群組視為單一陳述式」 "()"

以下是一些基本限制陳述式的範例:

  • "Value >= 5"
  • "NodeColor != green"
  • "((OneProperty < 100) || ((AnotherProperty == false) && (OneProperty >= 100)))"

只有在整體放置限制陳述式評估為「True」的節點上,服務才會被放置。 未定義某個屬性的節點,不會符合任何包含該屬性的放置限制。

假設在 ClusterManifest.xml 中,針對某個節點類型定義了下列節點屬性:

    <NodeType Name="NodeType01">
      <PlacementProperties>
        <Property Name="HasSSD" Value="true"/>
        <Property Name="NodeColor" Value="green"/>
        <Property Name="SomeProperty" Value="5"/>
      </PlacementProperties>
    </NodeType>

下列範例顯示在獨立部署時透過 ClusterConfig.json 定義節點屬性,或在 Azure 託管叢集中透過 Template.json 定義節點屬性。

附註

在您的 Azure Resource Manager 範本中,節點類型通常會參數化。 它看起來會像 "[parameters('vmNodeType1Name')]",而不是 NodeType01。

"nodeTypes": [
    {
        "name": "NodeType01",
        "placementProperties": {
            "HasSSD": "true",
            "NodeColor": "green",
            "SomeProperty": "5"
        },
    }
],

您可以如下為服務建立服務放置限制

FabricClient fabricClient = new FabricClient();
StatefulServiceDescription serviceDescription = new StatefulServiceDescription();
serviceDescription.PlacementConstraints = "(HasSSD == true && SomeProperty >= 4)";
// Add other required ServiceDescription fields
//...
await fabricClient.ServiceManager.CreateServiceAsync(serviceDescription);
New-ServiceFabricService -ApplicationName $applicationName -ServiceName $serviceName -ServiceTypeName $serviceType -Stateful -MinReplicaSetSize 3 -TargetReplicaSetSize 3 -PartitionSchemeSingleton -PlacementConstraint "HasSSD == true && SomeProperty >= 4"

如果 NodeType01 的所有節點都有效,您也可以使用限制 "(NodeType == NodeType01)" 來選取該節點類型。

服務的放置限制可在執行階段動態更新。 如果需要,您可以在叢集中移動服務、加入與移除需求等。 即使進行這類變更,Service Fabric 仍會確保服務持續運作且可用。

StatefulServiceUpdateDescription updateDescription = new StatefulServiceUpdateDescription();
updateDescription.PlacementConstraints = "NodeType == NodeType01";
await fabricClient.ServiceManager.UpdateServiceAsync(new Uri("fabric:/app/service"), updateDescription);
Update-ServiceFabricService -Stateful -ServiceName $serviceName -PlacementConstraints "NodeType == NodeType01"

放置限制會針對每個具名服務執行個體指定。 更新一律會取代 (覆寫) 先前指定的內容。

叢集定義會定義節點上的屬性。 變更節點屬性需要升級叢集組態。 升級節點屬性需要每個受影響的節點重新啟動,以回報新的屬性。 Service Fabric 會管理這些輪替升級。

描述與管理叢集資源

任何協調流程引擎最重要的工作之一,就是協助管理叢集中的資源使用量。 管理叢集資源可能包含幾種不同意義。

第一,是確保機器不會超載。 也就是確保機器執行的服務數量不會超過其可承擔的範圍。

第二,是平衡與最佳化,這對於高效率執行服務至關重要。 具成本效益或對效能敏感的服務供應,無法允許某些節點過熱而其他節點過冷。 過熱的節點會導致資源競爭與效能不佳。 過冷的節點代表資源浪費與成本增加。

Service Fabric 會以指標來表示資源。 指標是您想要向 Service Fabric 描述的任何邏輯或實體資源。 指標的範例包含「WorkQueueDepth」或「MemoryInMb」。 如需 Service Fabric 可在節點上治理的實體資源資訊,請參閱資源控管。 如需叢集資源管理員使用的預設指標,以及如何設定自訂指標,請參閱本文

指標不同於放置限制與節點屬性。 節點屬性是節點本身的靜態描述。 指標描述節點擁有的資源,以及服務在節點上執行時所消耗的資源。 某個節點屬性可能是 HasSSD,並設為 true 或 false。 該 SSD 的可用空間量,以及服務消耗了多少空間,則會以像「DriveSpaceInMb」這類指標來表示。

就如同放置限制與節點屬性一樣,Service Fabric 叢集資源管理員不會理解指標名稱的意義。 指標名稱只是字串。 當您建立的指標名稱可能含義不明確時,將單位宣告為指標名稱的一部分是一項良好做法。

容量

如果您關閉所有資源平衡,Service Fabric 叢集資源管理員仍會確保沒有任何節點超過其容量。 除非叢集過於滿載或工作負載大於任何一個節點,否則可以管理容量超限。 容量是叢集資源管理員用來理解節點擁有多少資源的另一種限制。 叢集資源管理員也會追蹤整個叢集的剩餘容量。

節點容量與服務層級的耗用都會以指標表示。 例如,指標可能是「ClientConnections」,而某個節點對「ClientConnections」的容量可能是 32,768。 其他節點可以有不同的上限。 在該節點上執行的服務可以表示它目前正在耗用「ClientConnections」指標的 32,256。

在執行階段,叢集資源管理員會追蹤叢集與節點上的剩餘容量。 為了追蹤容量,叢集資源管理員會從服務執行所在節點的容量中,扣除該服務的使用量。 透過這些資訊,叢集資源管理員可以判斷要把複本放在哪裡,或要把複本移到哪裡,避免節點超過容量。

叢集節點與容量

StatefulServiceDescription serviceDescription = new StatefulServiceDescription();
ServiceLoadMetricDescription metric = new ServiceLoadMetricDescription();
metric.Name = "ClientConnections";
metric.PrimaryDefaultLoad = 1024;
metric.SecondaryDefaultLoad = 0;
metric.Weight = ServiceLoadMetricWeight.High;
serviceDescription.Metrics.Add(metric);
await fabricClient.ServiceManager.CreateServiceAsync(serviceDescription);
New-ServiceFabricService -ApplicationName $applicationName -ServiceName $serviceName -ServiceTypeName $serviceTypeName –Stateful -MinReplicaSetSize 3 -TargetReplicaSetSize 3 -PartitionSchemeSingleton –Metric @("ClientConnections,High,1024,0)

您可以在叢集資訊清單中看到已定義的容量。 以下是 ClusterManifest.xml 的範例:

    <NodeType Name="NodeType03">
      <Capacities>
        <Capacity Name="ClientConnections" Value="65536"/>
      </Capacities>
    </NodeType>

以下是針對獨立部署透過 ClusterConfig.json 定義容量,或針對 Azure 託管叢集透過 Template.json 定義容量的範例:

"nodeTypes": [
    {
        "name": "NodeType03",
        "capacities": {
            "ClientConnections": "65536",
        }
    }
],

服務的負載經常會動態變更。 假設某個複本的「ClientConnections」負載從 1,024 變更為 2,048。 該複本所在的節點在該指標上只剩下 512 的容量。 此時該複本或執行個體的放置就變成無效,因為該節點上沒有足夠空間。 叢集資源管理員必須讓該節點回到低於容量的狀態。 它會透過將一或多個複本或執行個體,從超限的節點移到其他節點,來降低該節點上的負載。

叢集資源管理員會嘗試將移動複本的成本降到最低。 您可以深入了解移動成本,以及重新平衡策略與規則

叢集容量

Service Fabric 叢集資源管理員如何避免整體叢集過於滿載? 在動態負載的情況下,它能做的事情不多。 服務的負載可能會在叢集資源管理員未採取任何動作的情況下獨立飆升。 因此,今天仍有充足餘裕的叢集,明天如果出現尖峰就可能算力不足。

叢集資源管理員中的控制項可協助防止問題。 您能做的第一件事,就是避免建立會使叢集滿載的新工作負載。

假設您建立一個無狀態服務,並且它伴隨一些負載。 該服務在意「DiskSpaceInMb」指標。 該服務的每個執行個體會耗用 5 單位的「DiskSpaceInMb」。 您想建立三個服務執行個體。 這代表在您建立這些服務執行個體之前,叢集中至少需要有 15 單位的「DiskSpaceInMb」。

叢集資源管理員會持續計算每個指標的容量與耗用量,以便判斷叢集中剩餘的容量。 如果空間不足,叢集資源管理員會拒絕建立服務的呼叫。

由於需求只是必須有 15 單位可用,您可以用許多不同方式來配置這個空間。 例如,可能有 15 個不同節點各剩下 1 單位容量,或有 5 個節點各剩下 3 單位容量。 如果叢集資源管理員可以重新安排,使得有 3 個節點各具備 5 單位可用容量,它就會放置該服務。 重新安排叢集通常可行,除非叢集幾乎滿載,或既有服務因某些原因無法被合併。

節點緩衝與超額配置容量

如果針對某個指標指定了節點容量,叢集資源管理員永遠不會將複本放置或移動到某個節點,若總負載會超過該節點所指定的容量。 當叢集接近滿載容量時,若必須放置、取代或移動負載很大的複本,這有時會阻止新複本的放置或失敗複本的取代。

為了提供更多彈性,您可以指定節點緩衝或超額配置容量。 當針對某個指標指定節點緩衝或超額配置容量時,叢集資源管理員會嘗試以讓緩衝或超額配置容量保持未使用的方式來放置或移動複本,但也允許在必要時使用緩衝或超額配置容量,以便執行可提升服務可用性的動作,例如:

  • 新複本放置或取代失敗複本
  • 升級期間的放置
  • 修正軟性與硬性限制違規
  • 重組

節點緩衝容量代表低於指定節點容量的保留容量,而超額配置容量代表高於指定節點容量的額外容量。 在這兩種情況下,叢集資源管理員都會嘗試讓這些容量保持可用。

例如,如果某個節點對指標 CpuUtilization 的指定容量為 100,且該指標的節點緩衝百分比設為 20%,那麼總容量與未緩衝容量分別為 100 與 80,且在一般情況下,叢集資源管理員不會將超過 80 單位的負載放置到該節點上。

總容量等於節點容量 (節點緩衝 + 未緩衝)

當您想保留一部分節點容量,且這部分容量只會用於上述可提升服務可用性的動作時,您應該使用節點緩衝。

另一方面,如果使用超額配置百分比並設為 20%,那麼總容量與未緩衝容量分別為 120 與 100。

總容量等於超額配置容量加上節點容量 (超額配置 + 未緩衝)

當您想允許叢集資源管理員即使在總資源使用量會超過容量時,仍能將複本放置到節點上,您應該使用超額配置容量。 這可在犧牲效能的前提下,為服務提供額外可用性。 如果使用超額配置,使用者應用程式邏輯必須能在可用的實體資源少於其理想需求時仍能運作。

如果指定了節點緩衝或超額配置容量,當目標節點上的總負載會超過總容量時,叢集資源管理員不會移動或放置複本 (節點緩衝時的總容量為節點容量;超額配置時的總容量為節點容量 + 超額配置容量)。

超額配置容量也可以指定為無限。 在此情況下,叢集資源管理員會嘗試讓節點上的總負載低於指定節點容量,但也允許可能在該節點上放置遠高於容量的負載,這可能導致嚴重的效能降低。

同一個指標無法同時指定節點緩衝與超額配置容量。

以下是如何在 ClusterManifest.xml 中指定節點緩衝或超額配置容量的範例:

<Section Name="NodeBufferPercentage">
    <Parameter Name="SomeMetric" Value="0.15" />
</Section>
<Section Name="NodeOverbookingPercentage">
    <Parameter Name="SomeOtherMetric" Value="0.2" />
    <Parameter Name=”MetricWithInfiniteOverbooking” Value=”-1.0” />
</Section>

以下是如何在獨立部署透過 ClusterConfig.json 指定節點緩衝或超額配置容量,或在 Azure 託管叢集透過 Template.json 指定節點緩衝或超額配置容量的範例:

"fabricSettings": [
  {
    "name": "NodeBufferPercentage",
    "parameters": [
      {
          "name": "SomeMetric",
          "value": "0.15"
      }
    ]
  },
  {
    "name": "NodeOverbookingPercentage",
    "parameters": [
      {
          "name": "SomeOtherMetric",
          "value": "0.20"
      },
      {
          "name": "MetricWithInfiniteOverbooking",
          "value": "-1.0"
      }
    ]
  }
]

後續步驟