疑難排解應用程式升級

本文將介紹升級 Azure Service Fabric 應用程式的一些常見問題,以及如何解決這些問題。

排除應用程式升級失敗的問題

當升級失敗時, Get-ServiceFabricApplicationUpgrade 指令的輸出包含用於除錯失敗的額外資訊。 以下清單說明了額外資訊的使用方式:

  1. 辨識故障類型。
  2. 找出失敗的原因。
  3. 隔離一個或多個失效元件以供進一步調查。

無論 FailureAction 是要復原還是暫停升級,只要 Service Fabric 偵測到失敗,就會提供這項資訊。

辨識失效類型

Get-ServiceFabricApplicationUpgrade 的輸出中, FailureTimestampUtc 會標示 Service Fabric 偵測升級失敗並觸發 FailureAction 的時間戳(UTC)。 FailureReason 指出三種可能的高階故障原因之一:

  1. UpgradeDomainTimeout - 表示某個升級網域花太久才完成,且 UpgradeDomainTimeout 已過期。
  2. OverallUpgradeTimeout - 表示整體升級時間過長且 UpgradeTimeout 已過期。
  3. HealthCheck - 表示升級更新網域後,應用程式依照指定的健康政策仍保持不健康狀態,且 HealthCheckRetryTimeout 已過期。

這些項目只有在升級失敗並開始回滾時才會出現在輸出中。 根據故障類型,會顯示更多資訊。

調查升級超時

升級逾時失敗最常由服務可用性問題引起。 本段後的輸出是升級時服務副本或實例無法在新程式碼版本中啟動的典型情況。 UpgradeDomainProgressAtFailure 欄位會擷取失敗時任何尚未完成的升級工作之快照。

Get-ServiceFabricApplicationUpgrade fabric:/DemoApp
ApplicationName                : fabric:/DemoApp
ApplicationTypeName            : DemoAppType
TargetApplicationTypeVersion   : v2
ApplicationParameters          : {}
StartTimestampUtc              : 4/14/2015 9:26:38 PM
FailureTimestampUtc            : 4/14/2015 9:27:05 PM
FailureReason                  : UpgradeDomainTimeout
UpgradeDomainProgressAtFailure : MYUD1

                                 NodeName            : Node4
                                 UpgradePhase        : PostUpgradeSafetyCheck
                                 PendingSafetyChecks :
                                     WaitForPrimaryPlacement - PartitionId: 744c8d9f-1d26-417e-a60e-cd48f5c098f0

                                 NodeName            : Node1
                                 UpgradePhase        : PostUpgradeSafetyCheck
                                 PendingSafetyChecks :
                                     WaitForPrimaryPlacement - PartitionId: 4b43f4d8-b26b-424e-9307-7a7a62e79750
UpgradeState                   : RollingBackCompleted
UpgradeDuration                : 00:00:46
CurrentUpgradeDomainDuration   : 00:00:00
NextUpgradeDomain              :
UpgradeDomainsStatus           : { "MYUD1" = "Completed";
                                 "MYUD2" = "Completed";
                                 "MYUD3" = "Completed" }
UpgradeKind                    : Rolling
RollingUpgradeMode             : UnmonitoredAuto
ForceRestart                   : False
UpgradeReplicaSetCheckTimeout  : 00:00:00

在此範例中,升級在升級域 MYUD1 失敗,兩個分割區(744c8d9f-1d26-417e-a60e-cd48f5c098f04b43f4d8-b26b-424e-9307-7a7a62e79750)卡住。 分割區卡住是因為執行時無法在目標節點 Node1Node4 放置主要副本(WaitForPrimaryPlacement)。

Get-ServiceFabricNode 指令可用來驗證這兩個節點是否屬於升級網域 MYUD1升級階段顯示 PostUpgradeSafetyCheck,表示這些安全檢查是在升級領域中所有節點完成升級後進行的。 所有這些資訊都指向新版應用程式碼可能存在問題。 最常見的問題,是服務在開啟或升級為主要複本程式碼路徑中發生錯誤。

PreUpgradeSafetyCheckUpgradePhase 表示在升級網域執行前準備時遇到問題。 在此情況下,最常見的問題,是服務在關閉或從主要複本降級的程式碼路徑中發生錯誤。

目前的 UpgradeStateRollingBackCompleted,因此原始升級必定是使用可復原的 FailureAction 執行,系統便會在失敗時自動復原升級。 若原始升級是透過手動 FailureAction 執行,則升級將處於暫停狀態,以便應用程式進行即時除錯。

在少數情況下,如果整體升級剛好在系統完成目前升級網域的所有工作時逾時,則 UpgradeDomainProgressAtFailure 欄位可能會是空白。 如果發生這種情況,試著提高 UpgradeTimeoutUpgradeDomainTimeout 的升級參數值,然後重新嘗試升級。

調查健康情況檢查失敗

健康檢查失敗可能由升級域內所有節點完成升級並通過安全檢查後發生的各種問題所觸發。 本段落後方的輸出,是因健康情況檢查失敗而導致升級失敗的典型情況。 UnhealthyEvaluations 欄位會擷取升級時依據指定健康情況原則而失敗之健康情況檢查的快照。

Get-ServiceFabricApplicationUpgrade fabric:/DemoApp
ApplicationName                         : fabric:/DemoApp
ApplicationTypeName                     : DemoAppType
TargetApplicationTypeVersion            : v4
ApplicationParameters                   : {}
StartTimestampUtc                       : 4/24/2015 2:42:31 AM
UpgradeState                            : RollingForwardPending
UpgradeDuration                         : 00:00:27
CurrentUpgradeDomainDuration            : 00:00:27
NextUpgradeDomain                       : MYUD2
UpgradeDomainsStatus                    : { "MYUD1" = "Completed";
                                          "MYUD2" = "Pending";
                                          "MYUD3" = "Pending" }
UnhealthyEvaluations                    :
                                          Unhealthy services: 50% (2/4), ServiceType='PersistedServiceType', MaxPercentUnhealthyServices=0%.

                                          Unhealthy service: ServiceName='fabric:/DemoApp/Svc3', AggregatedHealthState='Error'.

                                              Unhealthy partitions: 100% (1/1), MaxPercentUnhealthyPartitionsPerService=0%.

                                              Unhealthy partition: PartitionId='3a9911f6-a2e5-452d-89a8-09271e7e49a8', AggregatedHealthState='Error'.

                                                  Error event: SourceId='Replica', Property='InjectedFault'.

                                          Unhealthy service: ServiceName='fabric:/DemoApp/Svc2', AggregatedHealthState='Error'.

                                              Unhealthy partitions: 100% (1/1), MaxPercentUnhealthyPartitionsPerService=0%.

                                              Unhealthy partition: PartitionId='744c8d9f-1d26-417e-a60e-cd48f5c098f0', AggregatedHealthState='Error'.

                                                  Error event: SourceId='Replica', Property='InjectedFault'.

UpgradeKind                             : Rolling
RollingUpgradeMode                      : Monitored
FailureAction                           : Manual
ForceRestart                            : False
UpgradeReplicaSetCheckTimeout           : 49710.06:28:15
HealthCheckWaitDuration                 : 00:00:00
HealthCheckStableDuration               : 00:00:10
HealthCheckRetryTimeout                 : 00:00:10
UpgradeDomainTimeout                    : 10675199.02:48:05.4775807
UpgradeTimeout                          : 10675199.02:48:05.4775807
ConsiderWarningAsError                  :
MaxPercentUnhealthyPartitionsPerService :
MaxPercentUnhealthyReplicasPerPartition :
MaxPercentUnhealthyServices             :
MaxPercentUnhealthyDeployedApplications :
ServiceTypeHealthPolicyMap              :

調查健康檢查失敗首先需要了解 Service Fabric 健康模式。 但即使沒有如此深入的理解,我們仍能看到有兩個服務不健康: fabric:/DemoApp/Svc3fabric:/DemoApp/Svc2,以及錯誤健康報告(此處為「InjectedFault」)。 在這個例子中,四分之二的服務屬於不健康狀態,低於預設目標 0% 不健康(MaxPercentUnhealthyServices)。

啟動升級時指定 FailureAction 為手動,系統便會在失敗時暫停升級。 此模式讓我們能在故障狀態下調查正在運行的系統,再採取進一步行動。

從暫停升級中恢復

使用回滾 FailureAction 時,升級失敗後會自動回滾,因此不需要復原。 使用手動 FailureAction 時,有幾種復原選項:

  1. 觸發復原
  2. 手動完成剩餘升級
  3. 恢復受監控的升級

Start-ServiceFabricApplicationRollback 命令可在任何時候使用,以開始應用程式回滾流程。 命令成功傳回後,系統就已登錄復原要求,並會在之後不久開始執行。

Resume-ServiceFabricApplicationUpgrade 指令可用來手動完成剩餘升級,一次只升級一個域。 在此模式下,系統僅執行安全檢查。 不再進行健康檢查。 此指令僅在 升級狀態 顯示 RollingForwardPending 時使用,表示當前升級網域已完成升級,但下一個網域尚未開始(待處理)。

可用 Update-ServiceFabricApplicationUpgrade 指令恢復監控升級,同時執行安全與健康檢查。

Update-ServiceFabricApplicationUpgrade fabric:/DemoApp -UpgradeMode Monitored
UpgradeMode                             : Monitored
ForceRestart                            :
UpgradeReplicaSetCheckTimeout           :
FailureAction                           :
HealthCheckWaitDuration                 :
HealthCheckStableDuration               :
HealthCheckRetryTimeout                 :
UpgradeTimeout                          :
UpgradeDomainTimeout                    :
ConsiderWarningAsError                  :
MaxPercentUnhealthyPartitionsPerService :
MaxPercentUnhealthyReplicasPerPartition :
MaxPercentUnhealthyServices             :
MaxPercentUnhealthyDeployedApplications :
ServiceTypeHealthPolicyMap              :

升級會從上次暫停的升級網域繼續進行,並使用與之前相同的升級參數和健康政策。 如有需要,在升級恢復時,可以在同一個指令中更改上述輸出中顯示的任何升級參數與健康政策。 在此範例中,升級在監控模式下繼續進行,參數與健康政策保持不變。

進一步疑難排解

Service Fabric 沒有遵守指定的健康政策

可能的原因一:

Service Fabric 會將所有百分比轉換為健康情況評估所需的實際實體數目 (例如複本、分割區和服務),並一律無條件進位為整數實體。 例如,如果最大 MaxPercentUnhealthyReplicasPerPartition 是 21%,且有五個副本,那麼 Service Fabric 最多允許兩個不健康的副本(也就是說,Math.Ceiling (5*0.21))。 因此,健康政策應相應制定。

可能原因二:

健康政策是以總服務的百分比來定義,而非具體服務個案。 例如,升級前,若應用程式有四個服務實例 A、B、C 和 D,其中服務 D 不健康,但對應用程式影響不大。 我們想在升級時忽略已知的不健康服務 D,並將 參數 MaxPercentUnhealthyServices 設為 25%,假設只有 A、B 和 C 需要健康。

然而,在升級過程中,D可能會變得健康,而C則變得不健康。 升級仍會成功,因為只有25% 的服務不健康。 然而,這可能會導致因 C 而非 D 意外不健康而產生意料之外的錯誤。在這種情況下,D 應被建模為與 A、B、C 不同的服務類型。由於健康政策是依服務類型指定,不同服務可套用不同的不健康百分比門檻。

我沒有為應用程式升級指定健康政策,但升級仍會因一些我未曾規定的逾時而失敗。

當升級請求未提供健康政策時,則會從目前應用程式版本的 ApplicationManifest.xml 中取得。 例如,如果你要將應用程式 X 從版本 1.0 升級到 版本 2.0,會使用版本 1.0 中指定的應用程式健康政策。 若升級時應使用不同的健康政策,則該政策必須在應用程式升級 API 呼叫中指定。 API 呼叫中指定的政策僅在升級期間適用。 升級完成後, ApplicationManifest.xml 中指定的政策會被使用。

指定了不正確的逾時

你可能曾好奇當暫停時間設定不一致時會發生什麼事。 舉例來說,你的 升級超時 可能比 升級網域超時 還短。 答案是會回傳一個錯誤訊息。 當 UpgradeDomainTimeout 小於 HealthCheckWaitDurationHealthCheckRetryTimeout 的總和,或 UpgradeDomainTimeout 小於 HealthCheckWaitDurationHealthCheckStableDuration 的總和時,會回傳錯誤。

我的升級進度太慢了

升級完成所需的時間,取決於指定的健康情況檢查和逾時。 健康檢查與逾時時間取決於複製、部署及穩定應用程式所需的時間。 逾時設得太激進,可能代表升級失敗次數會更多,因此我們建議一開始採取保守做法,使用較長的逾時。

以下是暫停時間與升級時間如何交互運作的快速回顧:

某個升級網域的升級,不可能比 HealthCheckWaitDuration + HealthCheckStableDuration 更快完成。

升級失敗不能比 HealthCheckWaitDuration + HealthCheckRetryTimeout 更快發生。

升級網域的升級時間受 UpgradeDomainTimeout 限制。 如果 HealthCheckRetryTimeoutHealthCheckStableDuration 都不是零,且應用程式的健康狀況不斷切換,那麼升級最終會在 UpgradeDomainTimeout 上逾時。 UpgradeDomainTimeout 會在目前升級網域的升級開始後開始倒數。

下一步

使用 Visual Studio 升級你的應用程式 ,會引導你完成使用 Visual Studio 進行應用程式升級。

使用 PowerShell 升級應用程式 會引導你完成使用 PowerShell 進行應用程式升級。

透過升級參數來控制應用程式的升級方式。

透過學習使用 資料序列化,讓您的應用程式升級相容。

透過參考 進階主題,學習如何在升級應用程式時使用進階功能。