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

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

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

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

容錯網域

容錯網域是協調失敗的任何區域。 單一機器是容錯網域。 其本身可能因各種原因而失敗,例如電源供應器故障、磁碟機故障或 NIC 韌體不正確。

連線到相同乙太網路交換器的機器位於相同的容錯網域中。 共用單一電源來源或單一位置的機器也一樣。

由於硬體故障重疊是很自然的情況,因此容錯網域本質上為階層式。 它們在 Service Fabric 中以 URI 表示。

必須正確設定容錯網域,因為 Service Fabric 會使用這項資訊來安全地放置服務。 Service Fabric 放置服務時會注意不要因為遺失容錯網域 (某個元件失敗所造成) 而導致服務中斷。

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

警告

必須將正確的容錯網域資訊提供給 Service Fabric。 例如,假設 Service Fabric 叢集是在 10 部虛擬機器上執行,這些虛擬機器是在 5 部實體主機上執行。 在此情況下,即使有 10 部虛擬機器,也只有 5 個不同的 (最上層) 容錯網域。 共用相同的實體主機會造成 VM 共用相同的根容錯網域,因為如果其實體主機失敗,VM 會遇到協調失敗。

Service Fabric 預期節點的容錯網域不會變更。 確保 VM 高可用性的其他機制 (例如 HA-VMs) 可能會造成與 Service Fabric 衝突。 這些機制會使用透明方式,將 VM 從某部主機移轉至另一部主機。 它們不會重新設定或通知 VM 內的執行中程式碼。 因此,「不支援」它們作為執行中 Service Fabric 叢集的環境。

Service Fabric 應該僅採用高可用性技術。 不需要像是即時 VM 移轉和 SAN 機制。 如果這些機制搭配 Service Fabric 使用,則其會「降低」應用程式的可用性和可靠性。 原因是它們引進額外的複雜性、新增集中式失敗來源,以及使用的可靠性和可用性策略與 Service Fabric 中的策略衝突。

下圖中,我們將所有參與容錯網域的實體塗上顏色,並列出形成的所有不同容錯網域。 在此範例中,我們有資料中心 ("DC")、機架 ("R") 和刀鋒伺服器 ("B")。 如果每個刀鋒伺服器包含多部虛擬機器,容錯網域階層中可能還有另一層。

Nodes organized via fault domains

在執行階段,Service Fabric 叢集資源管理員會考慮叢集中的容錯網域,並規劃配置。 服務的具狀態複本或無狀態執行個體會分散,讓它們位在不同的容錯網域中。 跨容錯網域分散服務,可確保當容錯網域在階層的任何層級失敗時,服務的可用性不會受到危害。

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

在容錯網域階層中的每個深度層級上,若有相同的節點數目,這是最好的。 如果叢集中的容錯網域「樹狀結構」不平衡,叢集資源管理員會很難找出服務的最佳配置。 不平衡的容錯網域配置表示遺失某些網域時,服務可用性受影響的程度可能大於其他網域。 因此,叢集資源管理員在兩個目標之間掙扎:

  • 其想要使用該「繁重」網域中的機器,方法是將服務放在這些機器上。
  • 其想要將服務放在其他網域中,以便遺失網域也不會造成問題。

不平衡網域外觀為何? 下圖顯示兩個不同的叢集配置。 在第一個範例中,節點在容錯網域之間平均分散。 在第二個範例中,一個容錯網域比其他容錯網域具有更多節點。

Two different cluster layouts

在 Azure 中會替您選擇哪一個容錯網域包含節點。 但是,根據您佈建的節點數目,某些容錯網域具有的節點最後仍可能比其他容錯網域更多。

例如,假設您在叢集中有五個容錯網域,但針對節點類型 (NodeType) 佈建七個節點。 在此情況下,前兩個容錯網域最後會有較多節點。 如果您繼續在只有幾個執行個體的情況下,部署更多的 NodeType 執行個體,則問題會更糟。 基於這個原因,建議每個節點類型中的節點數目是容錯網域數目的倍數。

升級網域

升級網域是另一項功能,可協助 Service Fabric 叢集資源管理員了解叢集的配置。 升級網域定義一組同時升級的節點。 升級網域可協助叢集資源管理員了解及協調例如升級的管理作業。

升級網域非常類似容錯網域,但是有幾個主要的差異。 首先,協調硬體失敗的區域會定義容錯網域。 另一方面,升級網域是由原則定義。 您可以決定想要多少個,而不是讓環境決定該數目。 您可以具有與節點一樣多的升級網域。 容錯網域和升級網域的另一個差異在於升級網域不是階層式。 相反地,它們更像是簡單的標籤。

下圖顯示三個升級網域等量分佈在三個容錯網域上。 其中也顯示不具狀態服務的三個不同複本有一個可能的位置,而每一個最後都在不同的容錯網域和升級網域。 在服務升級期間,即使遺失容錯網域,這個位置可讓我們仍然保有一份程式碼和資料。

Placement With fault and upgrade domains

大量升級網域有其利弊。 升級網域越多表示每個升級步驟會更細微,而且會影響更少的節點或服務。 必須一次移動的服務較少,對系統的影響較小。 這樣較容易改善可靠性,因為升級期間發生的任何問題會影響較少的服務。 升級網域越多,也表示其他節點上需要較少的可用緩衝區來處理升級的影響。

例如,若您有五個升級網域,則每個網域的節點可處理大約 20% 的流量。 如果您需要關閉升級網域以進行升級,通常必須將負載移至別處。 因為您有四個剩餘的升級網域,每一個都必須有大約總流量 25% 的空間。 多個升級網域表示您在叢集之節點上需要較少的緩衝區。

請改為考慮您若有 10 個升級網域。 在此情況下,每個升級網域只會處理大約總流量的 10%。 當升級步驟是透過叢集時,每個網域只需要有大約總流量 11% 的空間。 多個升級網域通常可讓您在更高的使用率之下執行您的節點,因為您需要較少的保留容量。 同樣的作法也適用於容錯網域。

擁有許多升級網域的缺點是升級通常需要較長的時間。 Service Fabric 會在升級網域完成之後短暫等候一段時間,並且在開始升級下一個升級網域之前執行檢查。 這些延遲可讓系統在升級繼續之前偵測由升級帶來的問題。 缺點是可接受的,因為它會防止不良的變更一次影響到太多服務。

若升級網域太少,會有許多負面效果。 當每個升級網域關閉並正在升級時,整體容量中的大部分都無法使用。 例如,若您只有三個升級網域,則一次就關閉大約三分之一的整體服務或叢集容量。 服務不宜一下子就關閉這麼多,因為叢集的剩餘部分必須有足夠容量來處理工作負載。 維護該緩衝區表示這些節點在一般作業期間的負載比其他期間少。 這會增加執行服務的成本。

環境中容錯或升級網域的總數沒有實際限制,對於它們如何重疊也沒有條件約束。 但有一些常見的模式:

  • 1:1 對應的容錯網域和升級網域
  • 每個節點 (實體或虛擬作業系統執行個體) 一個升級網域
  • 「等量」或「矩陣」模型,其中的容錯網域和升級網域形成一個矩陣,而電腦通常沿著對角線排列

Layouts of fault and upgrade domains

選擇哪種配置並沒有最佳的答案。 各有其優缺點。 例如,1FD:1UD 模型相當容易設定。 每個節點一個升級網域的模型,是使用者最常使用的模型。 在升級期間,每個節點會獨立更新。 這類似於以往手動升級小型集合機器的方式。

最常見的模型是 FD/UD 矩陣,其中容錯網域和升級網域形成一個表格,而節點沿著對角線開始放置。 這是在 Azure 中的 Service Fabric 叢集預設使用的模型。 對於具有許多節點的叢集,所有項目最後看起來就像是密集矩陣模式。

注意

裝載於 Azure 中的 Service Fabric 叢集不支援變更預設策略。 只有獨立叢集提供該自訂。

容錯和升級網域條件約束及產生的行為

預設方法

根據預設,叢集資源管理員會讓服務在容錯網域與升級網域之間保持平衡。 這會經由模型化成為條件約束。 容錯網域和升級網域的條件約束陳述:「針對特定的服務分割區,相同階層層級上任兩個網域之間的服務物件 (無狀態服務執行個體或具狀態服務複本) 數目差異應該一律不能大於一」。

假設此條件約束提供「差異上限」保證。 容錯網域和升級網域的條件約束可防止違反規則的某些措施或安排。

例如,假設我們的叢集有六個節點,且已設定五個容錯網域和五個升級網域。

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 之間的差異總計為 2,大於差異上限 1。 因為違反條件約束,所以叢集資源管理員不會允許這個安排。

同樣地,如果挑選 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 是 5,則由任 3 個複本組成的集合即代表仲裁。 同樣地,如果 TargetReplicaSetSize 是 6,則仲裁必須要有 4 個複本。 在這兩種情況下,如果分割區想要繼續正常運作,就不可以有超過 2 個複本同時停止運作。

若為無狀態服務,沒有「仲裁遺失」的情況。 即使大部分的執行個體同時關閉,無狀態服務仍會繼續正常運作。 因此,在本文的其餘部分中,我們會著重於具狀態服務。

讓我們回到先前的範例。 使用「仲裁防護」版本的條件約束時,所有三個配置都將有效。 即使 FD0 在第二個配置中失敗,或 UD1 在第三個配置中失敗,分割區仍會具有仲裁。 (大部分的複本仍處於啟動狀態。)使用此版本的條件約束時,幾乎一律會使用 N6。

「仲裁防護」方法提供比「差異上限」方法更多的彈性。 原因是,您可以更輕鬆地找到幾乎任何叢集拓撲中都有效的複本分配方式。 不過,此方法無法保證最佳容錯特性,因為有些錯誤比其他錯誤來得嚴重。

在最糟糕的案例情況中,可能因一個網域再加上一個複本發生錯誤,就遺失大多數複本。 例如,在有 5 個複本或執行個體的情況下,您現在可能只要有 2 個失敗就會失去多數地位,而不是必須要有 3 個失敗才會遺失仲裁。

調適型方法

由於這兩種方法都有優缺點,因此我們引進一個結合這兩種策略的調適型方法。

注意

從 Service Fabric 6.2 版開始,這是預設行為。

調適型方法預設會使用「差異上限」邏輯,而只有在必要時,才會切換至「仲裁防護」邏輯。 叢集資源管理員會查看叢集和服務的設定方式,來自動查明哪個策略是必要策略。

叢集資源管理員應該針對下列兩個條件都為 true 的服務使用「仲裁型」邏輯:

  • 服務的 TargetReplicaSetSize 會平均地除以容錯網域數目和升級網域數目。
  • 節點數目小於或等於容錯網域數目乘以升級網域數目。

請記住,即使仲裁遺失與無狀態服務並不相關,「叢集資源管理員」仍會針對無狀態服務和具狀態服務使用此方法。

讓我們回到先前的範例,並假設叢集現在有 8 個節點。 叢集仍設定有 5 個容錯網域和 5 個升級網域,而該叢集上所裝載服務的 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 上分配其餘 4 個複本。 如此一來,就不會違反容錯網域和升級網域邏輯的「差異上限」版本。

在先前的配置中,如果 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 -

設定容錯和升級網域

在 Azure 託管的 Service Fabric 部署中,會自動定義容錯網域和升級網域。 Service Fabric 會從 Azure 中取用環境資訊。

如果想要建立您自己的叢集 (或想要在開發環境中執行特定拓撲),您可以自行提供容錯網域和升級網域資訊。 在此範例中,我們定義本機開發叢集,具有 9 個節點,且跨越 3 個資料中心 (各有 3 個機架)。 此叢集也有 3 個升級網域等量分散於這 3 個資料中心。 以下是 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,而其他工作負載可能不需要。

將硬體專用於特定工作負載的最佳範例幾乎都是多層式架構。 特定電腦作為應用程式的前端或 API 供應端,並且公開至用戶端或網際網路。 其他電腦 (通常有不同的硬體資源) 處理計算層或儲存層的工作。 它們通常不會直接公開至用戶端或網際網路。

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

  • 現有的多層式架構應用程式已「提升並移轉」到 Service Fabric 環境。
  • 基於效能、規範調整或安全性隔離原因,工作負載必須在特定硬體上執行。
  • 基於原則或資源耗用量原因,工作負載應該彼此隔離。

為了支援這類設定,Service Fabric 包含您可以套用至節點的標籤。 這些標記稱為節點屬性放置條件約束是陳述式,其會附加至針對一或多個節點屬性選取的個別服務。 放置條件約束會定義應該執行服務的位置。 這組條件約束是可擴充的。 任何金鑰/值組都可以運作。

Different workloads for a cluster layout

內建節點屬性

Service Fabric 會定義一些可以自動使用的預設節點屬性,讓您不需要定義它們。 每個節點上定義的預設屬性是 NodeTypeNodeName

例如,您可以將放置條件約束撰寫成 "(NodeType == NodeType03)"NodeType 是經常使用的屬性。 因為其與機器類型的對應是 1:1,所以很有用。 每個機器類型都對應至傳統多層式架構應用程式中的工作負載類型。

Placement constraints and node properties

放置條件約束和節點屬性語法

節點屬性中指定的值可以是字串、布林值,或帶正負號長值。 服務的陳述式稱為放置「條件約束」,因為其會限制服務在叢集中可執行的位置。 條件約束可以是任何在叢集中於節點屬性上運作的布林值陳述式。 這些布林值陳述式中的有效選取器如下:

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

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

    陳述式 語法
    「和」 "&&"
    「或」 "||"
    「否」 "!"
    「組成單一陳述式」 "()"

以下是基本條件約束陳述式的一些範例:

  • "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 (若為獨立部署) 或 Template.json (若為 Azure 託管叢集) 定義的節點屬性。

注意

在您的 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 會管理這些輪流升級。

描述與管理叢集資源

任何 Orchestrator 的其中一個最重要的作業是協助管理叢集中的資源耗用量。 管理叢集資源可以表示幾個不同的項目。

首先,確保電腦不會多載。 這表示確定電腦不會執行比它們能夠處理還多的服務。

第二,平衡和最佳化,對於有效率地執行服務至關重要。 符合成本效益或效能的敏感服務供應項目不允許某些節點忙碌,而其他節點閒置。 熱節點會導致資源競爭和效能不佳。 冷節點代表資源浪費和成本增加。

Service Fabric 以「計量」來代表資源。 度量是您想要向 Service Fabric 描述的任何邏輯或實體資源。 計量的範例是 “WorkQueueDepth” 或 “MemoryInMb”。 如需 Service Fabric 可以在節點上管理的實體資源相關資訊,請參閱資源管理。 如需叢集資源管理員所使用預設計量,以及如何設定自訂度量的相關資訊,請參閱這篇文章

計量不同於放置條件約束和節點屬性。 節點屬性是節點本身的靜態描述項。 計量描述節點所擁有的資源,以及服務在節點上執行時取用的資源。 節點屬性可能是 HasSSD,而且可能設定為 true 或 false。 該 SSD 上可用的空間數量和服務耗用多少將是 "DriveSpaceInMb" 之類的計量。

就像放置條件約束和節點屬性一樣,Service Fabric 叢集資源管理員也不了解計量名稱的意義。 計量名稱只是字串。 如果您建立的計量名稱可能引起歧義,最好宣告單位。

Capacity

如果您關閉所有資源「平衡」,Service Fabric 的叢集資源管理員仍會確保節點不超出其容量。 除非叢集已滿或工作負載大於任何節點,否則管理容量溢位是可能的。 容量是另一個「條件約束」,可讓叢集資源管理員了解節點使用某項資源的多寡。 另外也會追蹤整個叢集的剩餘容量。

服務層級的容量和耗用量均以度量來表示。 例如,計量可能是 "ClientConnections",而節點的 "ClientConnections" 容量可能是 32,768。 其他節點可以有其他限制。 在該節點上執行的服務,可以假設其目前耗用計量 "ClientConnections" 的 32,256。

在執行階段期間,叢集資源管理員會追蹤叢集中和節點上的剩餘容量。 為了追蹤容量,叢集資源管理員會從服務執行所在的節點容量減去每個服務的使用量。 利用此資訊,叢集資源管理員即可決定將複本放置或移至何處,不會讓節點超出容量。

Cluster nodes and capacity

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 (若為獨立部署) 或 Template.json (若為 Azure 託管叢集) 定義的容量範例:

"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 單位的負載放置在節點上。

Total capacity equals node capacity (Node buffer + Unbuffered)

當您想要保留節點容量的一部分,只用於增加服務可用性的上述動作時,應該使用節點緩衝區。

另一方面,如果使用節點超額預訂百分比並設定為 20%,則總計和未緩衝的容量將分別為 120 和 100。

Total capacity equals overbooking capacity plus node capacity (Overbooking + Unbuffered)

當您想要允許叢集資源管理員將複本放置在節點上,即使其總資源使用量超過容量也一樣時,應該使用超額預訂容量。 這可以用來為服務提供額外可用性,但代價是效能。 如果使用超額預訂,則使用者應用程式邏輯必須能夠以比其可能所需更少的實體資源運作。

如果指定了節點緩衝區或超額預訂容量,則在目標節點上的總容量超過總容量時 (在節點緩衝區和節點容量的情況下,指的是節點容量,而在超額預訂的情況下,指的是節點容量 + 超額預訂容量),叢集資源管理員將不會移動或放置複本。

超額預訂容量也可以指定為無限。 在此情況下,叢集資源管理員會嘗試將節點的總負載維持在指定的節點容量之下,但允許可在節點上放置大很多的負載,這可能會導致嚴重的效能降低。

計量不能同時具有針對其指定的節點緩衝區和超額預訂容量。

以下是如何在 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 (若為獨立部署) 或 Template.json (若為 Azure 託管叢集) 指定節點緩衝區或超額預訂容量的範例:

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

下一步