FabricNotReadableException是什么意思?我们该如何应对呢?

时间:2015-11-27 15:25:34

标签: c# azure-service-fabric

我们在Service-Fabric上的状态服务中使用以下方法。该服务有分区。有时我们从代码的安静中获得FabricNotReadableException。

public async Task HandleEvent(EventHandlerMessage message)
{
    var queue = await StateManager.GetOrAddAsync<IReliableQueue<EventHandlerMessage>>(EventHandlerServiceConstants.EventHandlerQueueName);
    using(ITransaction tx = StateManager.CreateTransaction())
    {
      await queue.EnqueueAsync(tx, message);
      await tx.CommitAsync();
    }
}

这是否意味着分区已关闭并正在移动?我们打了一个二级分区?因为在某些情况下还会引发FabricNotPrimaryException。

我看过MSDN链接(https://msdn.microsoft.com/en-us/library/azure/system.fabric.fabricnotreadableexception.aspx)。但是

是什么
  

表示当分区无法接受读取时引发的异常。

意思?分区无法接受读取的情况发生了什么?

3 个答案:

答案 0 :(得分:13)

在幕后,Service Fabric有几种状态可以影响给定副本是否可以安全地提供读写操作。他们是:

  • 授予(您可以将其视为正常操作)
  • 非主要
  • No Write Quorum(再次主要影响写入)
  • 待重新配置
每当在当前不是主副本的副本上尝试写入时,都会抛出您提到的FabricNotPrimaryException,并映射到NotPrimary状态。

FabricNotReadableException映射到其他状态(您实际上不需要担心或区分它们),并且可能在各种情况下发生。一个示例是,如果您尝试执行读取的副本是“备用”副本(副本已关闭且已恢复,但副本集中已有足够的活动副本)。另一个例子是副本是主节点但是正在关闭(例如由于升级或因为它报告了故障),或者它当前正在进行重新配置(例如,正在添加另一个副本)。由于某些安全检查和Service Fabric需要在引擎盖下处理的原子更改,所有这些条件都将导致副本无法满足写入的少量时间。

您可以将FabricNotReadableException视为可重复。如果您看到它,只需再次尝试呼叫,最终它将解析为NotPrimary或​​Granted。如果你得到FabricNotPrimary异常,通常这应该被抛回到客户端(或以某种方式通知客户端),它需要重新解析才能找到当前的主服务器(Service Fabric发布的默认通信堆栈)注意不可重复的异常并代表您重新解决。

FabricNotReadableException目前存在两个已知问题。

  1. FabricNotReadableException应该有两个变体。第一个应该是显式可重复的(FabricTransientNotReadableException),第二个应该是FabricNotReadableException。第一个版本(Transient)是最常见的,可能是你遇到的,当然在大多数情况下会遇到什么。在您最终与备用副本进行通信的情况下,将返回第二个(非瞬态)。开箱即用的传输和重试逻辑不会与备用数据库进行通信,但如果您有自己的存储,则可能会遇到它。
  2. 另一个问题是今天FabricNotReadableException应该从FabricTransientException派生,这样可以更容易地确定正确的行为。

答案 1 :(得分:1)

发布作为回答(对于asnider的评论 - 3月16日17:42)因为评论太长了! :)

我也陷入了这个问题22.我的svc启动并立即收到消息。我想在OpenAsync中封装服务启动并设置一些ReliableDictionary值,然后开始接收消息。但是,此时Fabric不可读,我需要拆分这个&#34; startup&#34;在OpenAsync和RunAsync之间:(

我的服务中的

RunAsync和我的客户端中的OpenAsync似乎也有不同的取消令牌,所以我还需要解决如何处理这个问题。它只是感觉有点凌乱。关于如何在我的代码中整理这个问题,我有很多想法,但是有没有人想出一个优雅的解决方案?

如果ICommunicationClient有一个RunAsync接口,当Fabric变得准备/可读时被取消并且当Fabric关闭副本时被取消,那将是很好的 - 这将严重简化我的生活。 :)

答案 2 :(得分:0)

我遇到了同样的问题。我的监听器在服务的主线程之前启动。我将需要启动的侦听器列表排队,然后在主线程中尽早激活了所有侦听器。结果,可以处理所有传入的消息并将其放入适当的可靠存储中。我的简单解决方案(这是服务总线侦听器):

|         t.NAME | t1.REPORTINGTYPE | t1.REPORTINGPERIOD |
|----------------|------------------|--------------------|
|  Mr John Smith |            Final |           Mar 2017 |
| Ms Janet Smith |            Draft |           Jun 2018 |

======================

在主线程中,调用该函数以启动侦听器操作:

public Task<string> OpenAsync (CancellationToken cancellationToken)
{
  string uri;

  Start ();
  uri = "<your endpoint here>";
  return Task.FromResult (uri);
}

public static object lockOperations = new object ();
public static bool operationsStarted = false;
public static List<ClientAuthorizationBusCommunicationListener> pendingStarts = new List<ClientAuthorizationBusCommunicationListener> ();
public static void StartOperations ()
{
  lock (lockOperations)
  {
    if (!operationsStarted)
    {
      foreach (ClientAuthorizationBusCommunicationListener listener in pendingStarts)
      {
        listener.DoStart ();
      }
      operationsStarted = true;
    }
  }
}

private static void QueueStart (ClientAuthorizationBusCommunicationListener listener)
{
  lock (lockOperations)
  {
    if (operationsStarted)
    {
      listener.DoStart ();
    }
    else
    {
      pendingStarts.Add (listener);
    }
  }
}

private void Start ()
{
  QueueStart (this);
}

private void DoStart ()
{
  ServiceBus.WatchStatusChanges (HandleStatusMessage,
    this.clientId,
    out this.subscription);
}

...

此问题很可能在此处出现,因为所讨论的总线已经具有消息,并在创建侦听器的第二秒开始触发。尝试访问状态管理器中的任何内容都会引发您所询问的异常。