Partager via

应用程序升级故障排除

本文介绍一些围绕升级 Azure Service Fabric 应用程序的常见问题以及这些问题的解决方法。

应用程序升级失败故障排除

当升级失败时,Get-ServiceFabricApplicationUpgrade 命令的输出将包含用于调试失败的附加信息。 以下列表指定如何使用这些附加信息:

  1. 识别失败类型。
  2. 识别失败原因。
  3. 隔离一个或多个失败组件以进行进一步调查。

该信息在 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)已停滞。 分区由于运行时无法将主副本 (WaitForPrimaryPlacement) 放在目标节点 Node1Node4 上而停滞。

可使用 Get-ServiceFabricNode 命令验证这两个节点是否位于升级域 MYUD1 中。 UpgradePhasePostUpgradeSafetyCheck,这意味着这些安全检查在升级域中所有节点完成升级后发生。 所有这些信息表明应用程序代码的新版本可能存在问题。 最常见的问题是打开或升级到主代码路径时的服务错误。

UpgradePhasePreUpgradeSafetyCheck,表示在执行升级之前,准备升级域时出现了问题。 这种情况下最常见的问题是关闭主代码路径或从该路径降级时的服务错误。

当前 UpgradeStateRollingBackCompleted,因此可以确定原始升级是使用了回滚 FailureAction 执行的,该操作在失败时会自动回滚升级。 如果已使用手动 FailureAction 执行了原始升级,则升级将改为处于挂起状态,以允许对应用程序进行实时调试。

在极少数情况下,当系统刚好完成当前升级域的所有工作时,如果整体升级因超时而失败,UpgradeDomainProgressAtFailure 字段可能为空。 如果发生这种情况,请尝试增加 UpgradeTimeout 和 UpgradeDomainTimeout 升级参数值,然后重试升级

调查健康检查失败

运行状况检查失败可能由各种其他问题触发,这些问题可能发生在升级域中所有节点完成升级、通过所有安全检查之后。 此段落后面的输出是升级因运行状况检查失败而失败时的典型输出。 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 命令可用于手动继续执行剩余的升级过程,逐个升级域进行。 在此模式下,系统只执行安全检查, 不再进行运行状况检查。 仅当 UpgradeState 显示 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 未遵循指定的健康策略

可能的原因 1:

Service Fabric 将所有百分比转换为实际实体(如副本、分区和服务)数,以进行运行状况评估,并且此数目将始终调高到实体整数。 例如,如果最大值 MaxPercentUnhealthyReplicasPerPartition 是 21% 且有 5 个副本,则 Service Fabric 允许最多 2 个运行状况不正常的副本(即 Math.Ceiling (5*0.21))。 因此,健康政策应该相应地设置。

可能的原因 2:

健康政策以总服务的百分比来指定,而非具体服务实例的百分比。 例如,如果在升级前应用程序有四个服务实例 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 中指定的策略。

错误地指定了超时值

您可能会想知道当超时设置不一致时会出现什么情况。 例如,UpgradeTimeout 小于 UpgradeDomainTimeout。 答案是返回一个错误。 返回错误的情况包括:UpgradeDomainTimeout 小于 HealthCheckWaitDurationHealthCheckRetryTimeout 的总和,或者 UpgradeDomainTimeout 小于 HealthCheckWaitDurationHealthCheckStableDuration 的总和。

我的升级耗时过长

升级完成所需的时间取决于健康检查和指定的超时时间。 ** 运行状况检查和超时取决于应用程序的复制、部署和稳定过程耗时多久。 过于积极地设置超时时间可能会导致更多的升级失败,因此我们建议开始时使用较长的超时时间以保持保守。

快速回顾一下超时时间与升级时间的交互方式:

升级域的升级完成时间不能快于 HealthCheckWaitDuration 和 + 。

升级失败发生的时间不会早于 HealthCheckWaitDuration + HealthCheckRetryTimeout

升级域的升级时间受到 UpgradeDomainTimeout 的限制。 如果 HealthCheckRetryTimeoutHealthCheckStableDuration 均不为零,并且应用程序的运行状况保持来回切换,那么升级最终将于 UpgradeDomainTimeout 超时。 在当前升级域的升级开始时,UpgradeDomainTimeout 就开始倒计时。

后续步骤

Upgrading your Application Using Visual Studio (使用 Visual Studio 升级应用程序)逐步讲解了如何使用 Visual Studio 进行应用程序升级。

使用 PowerShell 升级应用程序逐步讲解了如何使用 PowerShell 进行应用程序升级。

使用升级参数来控制应用程序的升级方式。

了解如何使用数据序列化,使应用程序在升级后保持兼容。

参考高级主题,了解如何在升级应用程序时使用高级功能。