【问题标题】:Diagnosing 'System.Fabric.FabricNotPrimaryException'诊断“System.Fabric.FabricNotPrimaryException”
【发布时间】:2018-10-03 12:55:23
【问题描述】:

[下面更新]

我们遇到了一个问题,即“System.Fabric.FabricNotPrimaryException”经常从我们正在开发的新服务中抛出。

数据流为:

  • 通过修改唯一标识符并查找正确的分区 ID 将消息发布到特定分区。这已确认工作正常,因此我们知道数据将进入正确的分区。
  • 消息存储在可靠队列中以供将来处理。此步骤似乎工作正常,我们在此阶段未收到 SF 异常
  • 消息被出列并交给一个处理程序,该处理程序决定是否需要更新 ReliableDictionary 中的状态。如果是这样,则使用事务中的“rety”助手处理更新。 这是发生错误的地方,并被扔回主服务类

通过流程跟踪异常的特定实例表明:

  • 消息到达正确的分区
  • 消息已添加到分区上的可靠存储中
  • 消息已处理
  • 尝试更新现有状态时引发了FabricNotPrimaryException
  • 在查看 SF 集群时,记录的异常的分区 ID 和节点名称都与预期分区的主副本的详细信息相匹配。

最后一点让“FabricNotPrimaryException”让我非常困惑,所以我想知道是否有更多信息可以记录以最终证明这是否是根本原因?

除了显而易见的情况外,还有其他情况会导致抛出此异常吗?

这是异常示例中的堆栈:

System.Fabric.FabricNotPrimaryException:在 System.Fabric.Store.TStore5.ThrowIfNotWritable (Microsoft.ServiceFabric.Data.Impl, Version=6.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35) at System.Fabric.Store.TStore5+d__218.MoveNext (Microsoft.ServiceFabric.Data.Impl,版本=6.0.0.0,文化=中性, PublicKeyToken=31bf3856ad364e35) 在 System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw (mscorlib,版本=4.0.0.0,文化=中性, PublicKeyToken=b77a5c561934e089) 在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (mscorlib,版本=4.0.0.0,文化=中性, PublicKeyToken=b77a5c561934e089) 在 Microsoft.ServiceFabric.Data.Collections.DistributedDictionary2+<GetOrAddAsync>d__109.MoveNext (Microsoft.ServiceFabric.Data.Impl, Version=6.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35) at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw (mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089) at System.Runtime.CompilerServices.TaskAwaiter1.GetResult (mscorlib, 版本=4.0.0.0,文化=中性,PublicKeyToken=b77a5c561934e089)
在 Clients.CoreEngine.Generic.StateManager.CoreEngineStateManager+c__DisplayClass32_0+d.MoveNext (Clients.CoreEngine.Generic,版本=1.0.0.0, 文化=中性,PublicKeyToken=null) 在 System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw (mscorlib,版本=4.0.0.0,文化=中性, PublicKeyToken=b77a5c561934e089) 在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (mscorlib,版本=4.0.0.0,文化=中性, PublicKeyToken=b77a5c561934e089) 在 Resiliency.Retry.RetryHelper+c__DisplayClass2_01+<<ExecuteInTransaction>b__0>d.MoveNext (Resiliency, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null) at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw (mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089) at Resiliency.Retry.RetryHelper+<ExecuteInTransaction>d__21.MoveNext (弹性,版本=1.0.0.0,文化=中性, PublicKeyToken=null) 在 System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw (mscorlib,版本=4.0.0.0,文化=中性, PublicKeyToken=b77a5c561934e089) 在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (mscorlib,版本=4.0.0.0,文化=中性, PublicKeyToken=b77a5c561934e089) 在 System.Runtime.CompilerServices.TaskAwaiter1.GetResult (mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089)
at Clients.CoreEngine.Generic.StateManager.CoreEngineStateManager+<ApplyUpdate>d__32.MoveNext (Clients.CoreEngine.Generic, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null) at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw (mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089) at System.Runtime.CompilerServices.TaskAwaiter
1.GetResult (mscorlib, 版本=4.0.0.0,文化=中性,PublicKeyToken=b77a5c561934e089)
在 Clients.CoreEngine.Generic.Handlers.UpdateSystemEventHandler+d__7.MoveNext (Clients.CoreEngine.Generic,版本=1.0.0.0, 文化=中性,PublicKeyToken=null) 在 System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw (mscorlib,版本=4.0.0.0,文化=中性, PublicKeyToken=b77a5c561934e089) 在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (mscorlib,版本=4.0.0.0,文化=中性, PublicKeyToken=b77a5c561934e089) 在 System.Runtime.CompilerServices.TaskAwaiter.GetResult (mscorlib, 版本=4.0.0.0,文化=中性,PublicKeyToken=b77a5c561934e089)
在 Clients.CoreEngine.Generic.CoreEngineProcessor+d__25.MoveNext (Clients.CoreEngine.Generic,版本=1.0.0.0, Culture=neutral, PublicKeyToken=null)

其他信息:2018 年 4 月 24 日

我们已经能够在连接了调试器的本地集群上重新创建它。看来:

  • Flow 在初始“干净”部署时完美运行,无论负载如何
  • 在集群重新平衡后(通过 Azure 集群上的服务升级和本地集群上的重新启动节点触发)开始抛出零星的 NotPrimary 异常。这些似乎只在可靠字典上调用“AddOrUpdate”时抛出 - 写入可靠队列按预期工作。在调试器中检查其中一个异常时,它会将副本显示为主要副本,并将 PartitionInfo.ReadStatus 显示为已授予,并且 PartitionInfo.WriteStatus 也是如此
  • 一旦集群自我修复并且集群管理器显示所有分区都处于健康状态,未来很大一部分消息会导致相同状态的相同异常。

这是作为事件捕获的这些异常之一的堆栈:

"时间戳": "2018-04-24T18:03:02.4053087+01:00", "ProviderName": "Clients-CoreEngineSvc-SAMPLE_CLIENT", “身份证”:8, “消息”:“'CoreEngineProcessor - OnProcessorMessage,'异常:处理器上:[Primary]。ReadStatus:[Granted]。WriteStatus:[Granted]”, “进程 ID”:20732, “级别”:“错误”, “关键字”:“0x0000F00000000080”, "事件名称": "服务异常", “活动ID”:空, “相关活动ID”:空, “有效载荷”:{ "serviceName": "fabric:/Clients.Generic.App/CoreEngineSvc", "serviceTypeName": "CoreEngineSvcType", "partitionId": "6ee32f92-d94e-4cba-b4d1-7ce335625c9c", "applicationName": "fabric:/Clients.Generic.App", "applicationTypeName": "Clients.Generic.AppType", "nodeName": "_Node_0", "operationClass": "CoreEngineProcessor", "操作方法": "OnProcessorMessage", “异常消息”:“”, "unWrappedException": "Microsoft.ServiceFabric.Data.Impl ::: ::: 在 System.Fabric.Store.TStore5.ThrowIfNotWritable(Int64 tracer) at System.Fabric.Store.TStore5.d__224.MoveNext() --- 从先前抛出异常的位置结束堆栈跟踪 --- 在 System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() 在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务任务) 在 Microsoft.ServiceFabric.Data.Collections.DistributedDictionary2.<AddOrUpdateAsync>d__98.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter1.GetResult() 在 Clients.CoreEngine.Generic.StateManager.CoreEngineStateManager.d__40.MoveNext() --- 从先前抛出异常的位置结束堆栈跟踪 --- 在 System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() 在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务任务) 在 System.Runtime.CompilerServices.TaskAwaiter.GetResult() 在 Clients.CoreEngine.Generic.CoreEngineProcessor.d__28.MoveNext() ", "exceptionString": "System.Fabric.FabricNotPrimaryException 在 System.Fabric.Store.TStore5.ThrowIfNotWritable(Int64 tracer) at System.Fabric.Store.TStore5.d__224.MoveNext() --- 从先前抛出异常的位置结束堆栈跟踪 --- 在 System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() 在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务任务) 在 Microsoft.ServiceFabric.Data.Collections.DistributedDictionary2.<AddOrUpdateAsync>d__98.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter1.GetResult() 在 Clients.CoreEngine.Generic.StateManager.CoreEngineStateManager.d__40.MoveNext() --- 从先前抛出异常的位置结束堆栈跟踪 --- 在 System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() 在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务任务) 在 System.Runtime.CompilerServices.TaskAwaiter.GetResult() 在 Clients.CoreEngine.Generic.CoreEngineProcessor.d__28.MoveNext()", “信息”:“在处理器上:[Primary]。ReadStatus:[Granted]。WriteStatus:[Granted]”, "correlationId": "00000000-0000-0000-0000-000000000000", “fixtureId”:8173405

【问题讨论】:

  • 值得注意的是,我们最初使用的是 v2.7.198,但发现一个问题表明此版本中存在潜在问题,这意味着消息可能会发送到辅助副本。我们现在使用的是 v6.0.380,没有明显的行为变化
  • '消息到达正确的分区'。你是如何确定这一点的?与在暂存环境中运行相比,您在本地运行时是否看到了不同的行为?
  • 我们的散列是确定性的,因此我们可以根据 SF explorer 中分配的键计算消息应该去往的预期分区。我们正在使用异常/其他信息日志记录分区 ID。我们在多种环境中看到了这种行为。我以为我已经通过将日志记录添加到传递给可靠字典上的 .GetOrAdd 方法的函数来跟踪它。似乎总是在异常出现之前直接调用传递的函数。最初,此函数可能偶尔会长时间运行,因此是否有可能超出超时阈值?

标签: .net azure-service-fabric service-fabric-stateful


【解决方案1】:

总体而言,您的情况听起来像是过于频繁或不正确的资源管理平衡配置以及一旦触发异常就没有移动到副本的正确位置的组合。

即使您已到达当前的 Primary 并开始工作,您也始终可以收到 FabricNotPrimaryException。 Read 和 Write 状态标志是活泼的(出于许多相同的原因,FabricNotReadableException 可以出现并且应该重试)。这些标志主要是为了帮助人们在即将做一些长期工作(即:事务查询计划生成,或重建某些索引)时提前退出,以便他们可以在开始之前检查和退出。它们是一种有用的优化,但除了检查它们的时刻外,不会告诉您任何其他信息。

当您看到 FabricNotPrimaryException 时,您应该退出并将调用返回给客户端,以便它知道它正在与错误的副本通信,并且可以重新解析并找到新的 Primary 并从中断处继续。

大多数情况下,当您看到 NotPrimary 时,会发生以下两种情况之一:

  1. 主节点刚刚降级。这说明了您看到的竞争条件 - 当客户打电话说“给我主要”时,或者当您检查写入状态时,这 是主要的,但在工作时该状态被撤销.通常发生这种情况是因为主节点正在移动到其他节点。导致移动的正常情况是节点启动或关闭、其他服务的创建或删除或应用程序升级。如果您不进行升级,几乎可以肯定是集群资源管理在进行重新平衡和移动。如果您发现移动过多,最好深入研究该配置,看看您是否应该使用不同的metricsbalancing thresholds 或完全不同的balancing strategy,以减少不必要的移动。默认情况下,SF 仅使用默认指标并尝试保持事物完美平衡,因此如果环境是动态的,您肯定会获得破坏性的平衡水平,从而打断您的工作。

  2. 该节点的基础 Service Fabric 租约 已过期。这个节点即将被关闭。当联合层的租约失败时,所有主节点立即失去其状态,因此它们无法做更多的工作(因为它们在技术上不在集群中)。这不太常见,但可以解释当集群中没有移动时主节点丢失状态。

【讨论】:

    猜你喜欢
    • 2023-03-19
    • 1970-01-01
    • 1970-01-01
    • 2011-02-10
    • 2015-04-30
    • 1970-01-01
    • 2011-04-11
    • 2015-07-02
    • 2016-12-31
    相关资源
    最近更新 更多