【发布时间】:2018-10-03 12:55:23
【问题描述】:
[下面更新]
我们遇到了一个问题,即“System.Fabric.FabricNotPrimaryException”经常从我们正在开发的新服务中抛出。
数据流为:
- 通过修改唯一标识符并查找正确的分区 ID 将消息发布到特定分区。这已确认工作正常,因此我们知道数据将进入正确的分区。
- 消息存储在可靠队列中以供将来处理。此步骤似乎工作正常,我们在此阶段未收到 SF 异常
- 消息被出列并交给一个处理程序,该处理程序决定是否需要更新 ReliableDictionary 中的状态。如果是这样,则使用事务中的“rety”助手处理更新。 这是发生错误的地方,并被扔回主服务类
通过流程跟踪异常的特定实例表明:
- 消息到达正确的分区
- 消息已添加到分区上的可靠存储中
- 消息已处理
- 尝试更新现有状态时引发了FabricNotPrimaryException
- 在查看 SF 集群时,记录的异常的分区 ID 和节点名称都与预期分区的主副本的详细信息相匹配。
最后一点让“FabricNotPrimaryException”让我非常困惑,所以我想知道是否有更多信息可以记录以最终证明这是否是根本原因?
除了显而易见的情况外,还有其他情况会导致抛出此异常吗?
这是异常示例中的堆栈:
System.Fabric.FabricNotPrimaryException:在 System.Fabric.Store.TStore
5.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_0 1+<<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)1.GetResult (mscorlib, 版本=4.0.0.0,文化=中性,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
在 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.TStore
5.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