資源管理

在相同的節點或叢集上執行多個服務時,有可能發生某個服務取用較多資源而導致程序中的其他服務無資源可用的情況。 此問題稱為「擾鄰」問題。 Azure Service Fabric 可讓開發人員藉由指定每個服務的要求和限制來限制資源使用量,以控制這項行為。

繼續本文之前,建議您先熟悉 Service Fabric 應用程式模型Service Fabric 主控模型

資源管理計量

Service Fabric 可依服務套件支援資源控管。 指派給服務套件的資源可以進一步在程式碼套件之間分配。 Service Fabric 支援使用兩個內建的計量,來控管每個服務套件的 CPU 與記憶體:

  • CPU (計量名稱 servicefabric:/_CpuCores):主機電腦上提供的邏輯核心。 所有節點上的所有核心加權都相同。

  • 記憶體 (計量名稱 servicefabric:/_MemoryInMB):記憶體的單位為 MB,它會與電腦上可用的實體記憶體對應。

針對這兩個計量,叢集資源管理員 (CRM) 會追蹤叢集總容量、叢集中每個節點上的負載,以及叢集中剩餘的資源數。 這兩個計量相當於其他任何使用者或自訂計量。

注意

自訂計量名稱不應該使用這兩個計量名稱的其中之一,因為這會導致未定義的行為。

所有現有的功能都可以搭配這些計量使用:

  • 叢集可以根據這兩個計量來進行平衡 (預設行為)。
  • 叢集可以根據這兩個計量來進行重組
  • 描述叢集時,可以為這兩個計量設定緩衝處理的容量。

注意

這些計量不支援動態負載報告;這些計量的負載會在建立時定義。

資源控管機制

從 7.2 版開始,Service Fabric 執行階段支援指定 CPU 和記憶體資源的要求和限制。

注意

早於 7.2 的 Service Fabric 執行階段版本僅支援一個模型,其中會以單一值同時作為特定資源 (CPU 或記憶體) 的要求限制。 本文將其指稱為 RequestsOnly 規格。

  • 要求:CPU 和記憶體要求值代表叢集資源管理員 (CRM) 用於 servicefabric:/_CpuCoresservicefabric:/_MemoryInMB 計量的負載。 換句話說,CRM 會將服務的資源使用量視為等同於其要求值,並在進行放置決策時使用這些值。

  • 限制:CPU 和記憶體限制值代表在節點上啟用程序或容器時所套用的實際資源限制。

Service Fabric 允許對 CPU 和記憶體使用 RequestsOnly、LimitsOnly 以及 RequestsAndLimits 規格。

  • 使用 RequestsOnly 規格時,Service Fabric 也會使用要求值作為限制。
  • 使用 LimitsOnly 規格時,Service Fabric 會將要求值視為 0。
  • 使用 RequestsAndLimits 規格時,限制值必須大於或等於要求值。

為了進一步了解資源控管機制,我們來看看一個將 RequestsOnly 規格用於 CPU 資源範例放置案例 (記憶體控管機制也相同)。 請考量具有兩個 CPU 核心的節點,以及將置於其上的兩個服務套件。 第一個要放置的服務套件由單一容器程式碼套件組成,且僅指定一個 CPU 核心的要求。 第二個要放置的服務套件由單一程序型程式碼套件組成,且僅指定一個 CPU 核心的要求。 由於這兩個服務套件都有 RequestsOnly 規格,因此其限制值會設定為要求值。

  1. 首先,要求一個 CPU 核心的容器型服務套件會放置在節點上。 執行階段會啟用容器,並將 CPU 限制設定為一個核心。 容器無法使用多個核心。

  2. 接著,要求一個 CPU 核心的程序型服務套件會放置在節點上。 執行階段會啟用服務程序,並將其 CPU 限制設定為一個核心。

此時,要求的總和等於節點的容量。 CRM 不會再對此節點放置更多具有 CPU 要求的容器或服務程序。 在該節點上,程序和容器會各自以一個核心執行,而不會彼此爭用 CPU。

現在,我們來重新看看具有 RequestsAndLimits 規格的範例。 這次,容器型服務套件指定了一個 CPU 核心的要求,以及兩個 CPU 核心的限制。 程序型服務套件同時指定了一個 CPU 核心的要求和限制。

  1. 首先,將容器型服務套件放置在節點上。 執行階段會啟用容器,並將 CPU 限制設定為兩個核心。 容器無法使用兩個以上的核心。
  2. 接著,會將程序型服務套件放置在節點上。 執行階段會啟用服務程序,並將其 CPU 限制設定為一個核心。

此時,放置在節點上的服務套件的 CPU 要求總和,等於節點的 CPU 容量。 CRM 不會再對此節點放置更多具有 CPU 要求的容器或服務程序。 但在該節點上,限制的總和 (容器的兩個核心 + 程序的一個核心) 超過兩個核心的容量。 如果容器和程序同時高載,可能會出現爭用 CPU 資源的情形。 這類競爭將由平台的基礎作業系統管理。 在此範例中,容器最多可高載至兩個 CPU 核心,導致程序對一個 CPU 核心的要求得不到保證。

注意

如先前的範例所示,CPU 和記憶體的要求值不會導致節點上的資源獲得保留。 這些值代表叢集資源管理員在進行放置決策時所考量的資源使用量。 限制值代表在節點上啟用程序或容器時所套用的實際資源限制。

在某些情況下,可能會有競用 CPU 的情形。 在這些情況下,我們範例中的程序和容器可能會遇到擾鄰問題:

  • 混合有控管和無控管的服務和容器:如果使用者建立服務時沒有指定任何資源控管,執行階段會將它視為不會耗用任何資源,且能夠將它放在我們範例中的節點上。 在此情況下,這個新處理序會不客氣地耗用一些 CPU,犧牲已在節點上執行的服務。 此問題有兩個解決方案。 不要在相同叢集上混合有控管和無控管的服務,或使用放置條件約束,讓這兩種類型的服務不會放在同一組節點上。

  • 在 Service Fabric 外 (例如,作業系統服務) 的節點上啟動另一個處理序時:在此情況下,Service Fabric 外的處理序也會與現有服務爭用 CPU。 這個問題的解決方法是設定節點容量時正確計入 OS 額外負荷,如下一節所述。

  • 當要求不等於限制時:如先前的 RequestsAndLimits 範例所說明,要求不會導致節點上的資源獲得保留。 當限制大於要求的服務放置在節點上時,可能會耗用達到最高限制的資源 (如果有的話)。 在這種情況下,節點上的其他服務所耗用的資源可能無法達到其要求值。

設定叢集以啟用資源控管

當節點啟動並加入叢集時,Service Fabric 會偵測可用的記憶體數目與可用的核心數目,然後設定那兩個資源的節點容量。

為保留一些緩衝空間給作業系統和其他可能在節點上執行的處理序,Service Fabric 只會使用節點可用資源的 80%。 這個百分比可加以設定,並可在叢集資訊清單中變更。

以下範例指示 Service Fabric 使用可用 CPU 的 50% 以及可用記憶體的 70%:

<Section Name="PlacementAndLoadBalancing">
    <!-- 0.0 means 0%, and 1.0 means 100%-->
    <Parameter Name="CpuPercentageNodeCapacity" Value="0.5" />
    <Parameter Name="MemoryPercentageNodeCapacity" Value="0.7" />
</Section>

就大部分的客戶和案例而言,建議的設定是自動偵測節點的 CPU 和記憶體容量 (依預設會開啟自動偵測)。 但是,如果您需要完全手動設定節點容量,您可以使用描述叢集中所含節點的機制,為每個節點類型設定容量。 以下範例說明如何設定具有 4 個核心和 2 GB 記憶體的節點類型:

    <NodeType Name="MyNodeType">
      <Capacities>
        <Capacity Name="servicefabric:/_CpuCores" Value="4"/>
        <Capacity Name="servicefabric:/_MemoryInMB" Value="2048"/>
      </Capacities>
    </NodeType>

當您啟用自動偵測可用資源,並手動定義叢集資訊清單中的節點容量時,Service Fabric 會檢查節點是否有足夠資源來支援使用者已經定義的容量:

  • 如果資訊清單中定義的節點容量小於或等於節點上的可用資源,Service Fabric 會使用資訊清單中指定的容量。

  • 如果資訊清單中定義的節點容量大於可用資源,Service Fabric 會使用可用資源作為節點容量。

如果非必要,可以關閉可用資源的自動偵測。 若要將它關閉,請變更下列設定:

<Section Name="PlacementAndLoadBalancing">
    <Parameter Name="AutoDetectAvailableResources" Value="false" />
</Section>

為了獲得最佳效能,在叢集資訊清單中應該也開啟下列設定:

<Section Name="PlacementAndLoadBalancing">
    <Parameter Name="PreventTransientOvercommit" Value="true" />
    <Parameter Name="AllowConstraintCheckFixesDuringApplicationUpgrade" Value="true" />
</Section>

重要

從 Service Fabric 7.0 版開始,我們已更新在使用者手動提供節點資源容量值的情況下,應如何計算節點資源容量的規則。 讓我們試想下列案例:

  • 節點上總共有 10 個 CPU 核心
  • SF 設定為使用 80% 的使用者服務整體資源 (預設設定),而保留 20% 的緩衝區給執行於節點上的其他服務 (包含 Service Fabric 系統服務)
  • 使用者決定手動覆寫 CPU 核心計量的節點資源容量,並將其設定為 5 個核心

我們已變更關於如何為 Service Fabric 使用者服務計算可用容量的規則,說明如下:

  • 在 Service Fabric 7.0 之前,使用者服務的可用容量會計算為 5 個核心 (忽略 20% 的容量緩衝區)
  • 從 Service Fabric 7.0 開始,使用者服務的可用容量會計算為 4 個核心 (不忽略 20% 的容量緩衝區)

指定資源控管

資源控管要求和限制指定於應用程式資訊清單中 (ServiceManifestImport 區段)。 讓我們看看一些範例:

範例 1:RequestsOnly 規格

<?xml version='1.0' encoding='UTF-8'?>
<ApplicationManifest ApplicationTypeName='TestAppTC1' ApplicationTypeVersion='vTC1' xsi:schemaLocation='http://schemas.microsoft.com/2011/01/fabric ServiceFabricServiceModel.xsd' xmlns='http://schemas.microsoft.com/2011/01/fabric' xmlns:xsi='https://www.w3.org/2001/XMLSchema-instance'>
  <ServiceManifestImport>
    <ServiceManifestRef ServiceManifestName='ServicePackageA' ServiceManifestVersion='v1'/>
    <Policies>
      <ServicePackageResourceGovernancePolicy CpuCores="1"/>
      <ResourceGovernancePolicy CodePackageRef="CodeA1" CpuShares="512" MemoryInMB="1024" />
      <ResourceGovernancePolicy CodePackageRef="CodeA2" CpuShares="256" MemoryInMB="1024" />
    </Policies>
  </ServiceManifestImport>

在此範例中,CpuCores 屬性會用來為 ServicePackageA 指定 1 個 CPU 核心的要求。 由於未指定 CPU 限制 (CpuCoresLimit 屬性),Service Fabric 也會使用指定的要求值 (1 個核心) 作為服務套件的 CPU 限制。

ServicePackageA 只會放置在符合下列條件的節點上:減去放置在該節點上的所有服務套件的 CPU 要求總和之後,剩餘的 CPU 容量必須大於或等於 1 個核心。 在該節點上,服務套件將限制為一個核心。 此服務套件包含兩個程式碼套件 (CodeA1CodeA2),且兩者皆指定 CpuShares 屬性。 CpuShares 512:256 的比例會用來計算個別程式碼套件的 CPU 限制。 因此,CodeA1 會限制為一個核心的三分之二,CodeA2 則會限制為一個核心的三分之一。 若未針對所有程式碼套件指定 CpuShares,Service Fabric 就會在其間平均分配 CPU 限制。

儘管為程式碼套件指定的 CpuShares 代表套件佔服務套件整體 CPU 限制的相對比例,程式碼套件的記憶體值仍會以絕對值指定。 在此範例中,MemoryInMB 屬性用來為 CodeA1 和 CodeA2 指定 1024 MB 的記憶體要求。 由於未指定記憶體限制 (MemoryInMBLimit 屬性),Service Fabric 也會使用指定的要求值作為程式碼套件的限制。 服務套件的記憶體要求 (和限制) 的計算方式,是加總其組成程式碼套件的記憶體要求 (和限制) 的值。 因此,為 ServicePackageA 算出的記憶體要求和限制會是 2048 MB。

ServicePackageA 只會放置在符合下列條件的節點上:減去放置在該節點上的所有服務套件的記憶體要求總和之後,剩餘的記憶體容量必須大於或等於 2048 MB。 在該節點上,這兩個程式碼套件會分別限制為 1024 MB 的記憶體。 程式碼套件 (容器或程序) 無法配置超過此限制的記憶體,如果嘗試這麼做,將會導致發生記憶體不足的例外狀況。

範例 2:LimitsOnly 規格

<?xml version='1.0' encoding='UTF-8'?>
<ApplicationManifest ApplicationTypeName='TestAppTC1' ApplicationTypeVersion='vTC1' xsi:schemaLocation='http://schemas.microsoft.com/2011/01/fabric ServiceFabricServiceModel.xsd' xmlns='http://schemas.microsoft.com/2011/01/fabric' xmlns:xsi='https://www.w3.org/2001/XMLSchema-instance'>
  <ServiceManifestImport>
    <ServiceManifestRef ServiceManifestName='ServicePackageA' ServiceManifestVersion='v1'/>
    <Policies>
      <ServicePackageResourceGovernancePolicy CpuCoresLimit="1"/>
      <ResourceGovernancePolicy CodePackageRef="CodeA1" CpuShares="512" MemoryInMBLimit="1024" />
      <ResourceGovernancePolicy CodePackageRef="CodeA2" CpuShares="256" MemoryInMBLimit="1024" />
    </Policies>
  </ServiceManifestImport>

此範例使用 CpuCoresLimitMemoryInMBLimit 屬性;這些屬性僅適用於 SF 7.2 版及更新版本。 CpuCoresLimit 屬性用來為 ServicePackageA 指定 1 個核心的 CPU 限制。 CPU 要求 (CpuCores 屬性) 未指定,因此會被視為 0。 MemoryInMBLimit 屬性用來為 CodeA1 和 CodeA2 指定 1024 MB 的記憶體限制,而要求 (MemoryInMB 屬性) 未指定,因此會被視為 0。 因此,ServicePackageA 的記憶體要求和限制會分別計算為 0 和 2048。 由於 ServicePackageA 的 CPU 和記憶體要求都是 0,因此 CRM 無須考量 servicefabric:/_CpuCoresservicefabric:/_MemoryInMB 計量的放置。 因此,從資源控管的觀點來看,無論剩餘的容量是多少ServicePackageA 都可放置在任何節點上。 與範例 1 相似,在該節點上,CodeA1 會限制為一個核心的三分之二和 1024 MB 的記憶體,CodeA2 則會限制為一個核心的三分之一和 1024 MB 記憶體。

範例 3:RequestsAndLimits 規格

<?xml version='1.0' encoding='UTF-8'?>
<ApplicationManifest ApplicationTypeName='TestAppTC1' ApplicationTypeVersion='vTC1' xsi:schemaLocation='http://schemas.microsoft.com/2011/01/fabric ServiceFabricServiceModel.xsd' xmlns='http://schemas.microsoft.com/2011/01/fabric' xmlns:xsi='https://www.w3.org/2001/XMLSchema-instance'>
  <ServiceManifestImport>
    <ServiceManifestRef ServiceManifestName='ServicePackageA' ServiceManifestVersion='v1'/>
    <Policies>
      <ServicePackageResourceGovernancePolicy CpuCores="1" CpuCoresLimit="2"/>
      <ResourceGovernancePolicy CodePackageRef="CodeA1" CpuShares="512" MemoryInMB="1024" MemoryInMBLimit="3072" />
      <ResourceGovernancePolicy CodePackageRef="CodeA2" CpuShares="256" MemoryInMB="2048" MemoryInMBLimit="4096" />
    </Policies>
  </ServiceManifestImport>

此範例是根據前兩個範例建置的,會示範如何同時指定 CPU 和記憶體的要求與限制。 ServicePackageA 的 CPU 和記憶體要求分別為 1 個核心和 3072 (1024 + 2048) MB。 您只能將其放置在符合下列條件的節點上:從節點的總 CPU (和記憶體) 容量中,減去放置在節點上的所有服務套件的所有 CPU (和記憶體) 要求總和之後,至少還剩下 1 個核心 (和 3072 MB) 的容量。 在該節點上,CodeA1 會限制為 2 個核心的三分之二和 3072 MB 的記憶體,CodeA2 則會限制為 2 個核心的三分之一和 4096 MB 的記憶體。

使用應用程式參數

指定資源控管設定時,可以使用應用程式參數來管理多個應用程式設定。 下列範例會示範應用程式參數的使用方式:

<?xml version='1.0' encoding='UTF-8'?>
<ApplicationManifest ApplicationTypeName='TestAppTC1' ApplicationTypeVersion='vTC1' xsi:schemaLocation='http://schemas.microsoft.com/2011/01/fabric ServiceFabricServiceModel.xsd' xmlns='http://schemas.microsoft.com/2011/01/fabric' xmlns:xsi='https://www.w3.org/2001/XMLSchema-instance'>

  <Parameters>
    <Parameter Name="CpuCores" DefaultValue="4" />
    <Parameter Name="CpuSharesA" DefaultValue="512" />
    <Parameter Name="CpuSharesB" DefaultValue="512" />
    <Parameter Name="MemoryA" DefaultValue="2048" />
    <Parameter Name="MemoryB" DefaultValue="2048" />
  </Parameters>

  <ServiceManifestImport>
    <ServiceManifestRef ServiceManifestName='ServicePackageA' ServiceManifestVersion='v1'/>
    <Policies>
      <ServicePackageResourceGovernancePolicy CpuCores="[CpuCores]"/>
      <ResourceGovernancePolicy CodePackageRef="CodeA1" CpuShares="[CpuSharesA]" MemoryInMB="[MemoryA]" />
      <ResourceGovernancePolicy CodePackageRef="CodeA2" CpuShares="[CpuSharesB]" MemoryInMB="[MemoryB]" />
    </Policies>
  </ServiceManifestImport>

在此範例中,會針對生產環境設定預設參數值,其中每個服務套件會得到 4 個核心和 2 GB 的記憶體。 可以使用應用程式參數檔案變更預設值。 在此範例中,可以使用一個參數檔案在本機測試應用程式,其中應用程式會得到比生產環境中還少的資源:

<!-- ApplicationParameters\Local.xml -->

<Application Name="fabric:/TestApplication1" xmlns="http://schemas.microsoft.com/2011/01/fabric">
  <Parameters>
    <Parameter Name="CpuCores" DefaultValue="2" />
    <Parameter Name="CpuSharesA" DefaultValue="512" />
    <Parameter Name="CpuSharesB" DefaultValue="512" />
    <Parameter Name="MemoryA" DefaultValue="1024" />
    <Parameter Name="MemoryB" DefaultValue="1024" />
  </Parameters>
</Application>

重要

從 Service Fabric 版本 6.1 開始,可以使用應用程式參數指定資源控管。

當應用程式參數用來指定資源控管時,Service Fabric 無法降級至 6.1 版之前的版本。

對使用者服務強制執行資源限制

雖然將資源控管套用至您的 Service Fabric 服務,可確保這些資源受到控管的服務不會超過其資源配額,但許多使用者仍需要在未受控管模式下執行其某些 Service Fabric 服務。 使用未受控管的 Service Fabric 服務時,可能會遇到未受控管的「失控」服務在 Service Fabric 節點上耗用了所有可用資源的情況,而這可能會導致嚴重的問題,例如:

  • 在節點上執行的其他服務 (包括 Service Fabric 系統服務) 的資源耗盡
  • 節點最終處於狀況不良的狀態
  • Service Fabric 叢集管理 API 沒有回應

為了避免發生這些情況,Service Fabric 允許您對執行於節點上的所有 Service Fabric 使用者服務強制執行資源限制 (包括受控管和未受控管的),以確保使用者服務絕不會使用超過指定數量的資源。 將 ClusterManifest 的 PlacementAndLoadBalancing 區段中的 EnforceUserServiceMetricCapacities 組態值設定為 true,即可達此目的。 依預設會關閉此設定。

<SectionName="PlacementAndLoadBalancing">
    <ParameterName="EnforceUserServiceMetricCapacities" Value="false"/>
</Section>

其他備註:

  • 資源限制只會對 servicefabric:/_CpuCoresservicefabric:/_MemoryInMB 資源計量強制執行
  • 只有在資源計量的節點容量可用於 Service Fabric 時,才可強制執行資源限制,具體上可透過自動偵測機制,或藉由使用者手動指定節點容量 (如設定叢集以啟用資源控管一節所說明)。 若未設定節點容量,就無法使用資源限制強制執行功能,因為 Service Fabric 無法得知要保留多少資源給使用者服務。 如果 "EnforceUserServiceMetricCapacities" 為 true,但未設定節點容量,Service Fabric 將發出健康情況警告。

容器的其他資源

除了 CPU 和記憶體,也可以為容器指定其他資源限制。 這些限制是在程式碼套件層級指定,並會在容器啟動時套用。 不同於 CPU 和記憶體,叢集資源管理員不會知道這些資源,也不會進行任何容量檢查或負載平衡。

  • MemorySwapInMB:可使用的交換記憶體總數量 (以 MB 為單位)。 必須是正整數。
  • MemoryReservationInMB:記憶體控管的彈性限制 (MB),只有在節點上偵測到記憶體爭用的情況時才會強制執行。 必須是正整數。
  • CpuPercent:可用 CPU 百分比 (僅限 Windows)。 必須是正整數。 無法與 CpuShares、CpuCores 或 CpuCoresLimit 搭配使用。
  • CpuShares:相對 CPU 權數。 必須是正整數。 無法與 CpuPercent、CpuCores 或 CpuCoresLimit 搭配使用。
  • MaximumIOps:最大 IO 速率 (讀取及寫入),以可使用的 IOPS 表示。 必須是正整數。
  • MaximumIOBandwidth:可使用 (讀取及寫入) 的最大 IO (每秒位元組數)。 必須是正整數。
  • BlockIOWeight:相對於其他程式碼套件的區塊 IO 權數。 必須式介於 10 到 1000 之間的正整數。
  • DiskQuotaInMB:容器的磁碟配額。 必須是正整數。
  • KernelMemoryInMB:核心記憶體限制 (以位元組為單位)。 必須是正整數。 請注意,這是 Linux 特有的,若加以設定,Windows 上的 Docker 將會發生錯誤。
  • ShmSizeInMB/dev/shm 的大小 (以位元組為單位)。 如果省略,系統會使用 64MB。 必須是正整數。 請注意,這是 Linux 特有的,但若加以設定,Docker 會逕行忽略 (而不會發生錯誤)。

這些資源可以與 CPU 和記憶體結合。 以下是如何指定容器的其他資源的範例:

    <ServiceManifestImport>
        <ServiceManifestRef ServiceManifestName="FrontendServicePackage" ServiceManifestVersion="1.0"/>
        <Policies>
            <ResourceGovernancePolicy CodePackageRef="FrontendService.Code" CpuPercent="5"
            MemorySwapInMB="4084" MemoryReservationInMB="1024" MaximumIOPS="20" />
        </Policies>
    </ServiceManifestImport>

下一步