FabricNotReadableException 是什么意思?我们应该如何应对?
What does the FabricNotReadableException mean? And how should we respond to it?
我们在 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 link (https://msdn.microsoft.com/en-us/library/azure/system.fabric.fabricnotreadableexception.aspx)。但是
是什么意思
Represents an exception that is thrown when a partition cannot accept reads.
是什么意思?分区不能接受读取是怎么回事?
在幕后,Service Fabric 有几种状态可以影响给定副本是否可以安全地提供读取和写入服务。他们是:
- 授予(您可以认为这是正常操作)
- 不是小学
- 无写入仲裁(再次主要影响写入)
- 重新配置待定
每当尝试对当前不是主副本并映射到 NotPrimary 状态的副本进行写入时,都会抛出您提到的 FabricNotPrimaryException。
FabricNotReadableException 映射到其他状态(您实际上不需要担心或区分它们),并且可能在各种情况下发生。一个示例是,如果您尝试对其执行读取的副本是 "Standby" 副本(一个已关闭且已恢复的副本,但副本集中已经有足够的活动副本)。另一个例子是如果副本是主副本但正在关闭(比如由于升级或因为它报告故障),或者如果它当前正在进行重新配置(比如正在添加另一个副本)。由于某些安全检查和 Service Fabric 需要在后台处理的原子更改,所有这些情况都将导致副本在短时间内无法满足写入。
您可以考虑 FabricNotReadableException 可重试。如果您看到它,只需再次尝试调用,最终它将解析为 NotPrimary 或 Granted。如果你得到 FabricNotPrimary 异常,通常这应该被抛回给客户端(或以某种方式通知客户端)它需要重新解析以找到当前的主(Service Fabric 提供的默认通信堆栈)监视不可重试的异常并代表您重新解决)。
FabricNotReadableException 目前有两个已知问题。
- FabricNotReadableException 应该有两个变体。第一个应该是显式可重试的 (FabricTransientNotReadableException),第二个应该是 FabricNotReadableException。第一个版本 (Transient) 是最常见的,可能是您 运行 正在进入的版本,当然在大多数情况下您会 运行 进入。第二个(非瞬态)将在您最终与备用副本对话的情况下返回。开箱即用的传输和重试逻辑不会与备用数据库通信,但如果您有自己的逻辑,则可以 运行 加入其中。
- 另一个问题是,今天 FabricNotReadableException 应该派生自 FabricTransientException,这样更容易确定正确的行为是什么。
作为答案发布(针对 asnider 的评论 - 3 月 16 日 17:42),因为评论太长了! :)
我也卡在这个catch 22了。我的svc启动后立即收到消息。我想在 OpenAsync 中封装服务启动并设置一些 ReliableDictionary 值,然后开始接收消息。但是,此时 Fabric 不可读,我需要在 OpenAsync 和 RunAsync 之间拆分 "startup" :(
我的服务中的 RunAsync
和我的客户端中的 OpenAsync
似乎也有不同的取消标记,所以我也需要解决如何处理这个问题。只是感觉有点乱。关于如何在我的代码中整理它,我有很多想法,但有没有人想出一个优雅的解决方案?
如果 ICommunicationClient 有一个 RunAsync 接口,该接口在 Fabric 变为 ready/readable 时调用并在 Fabric 关闭副本时取消 - 这将大大简化我的生活。 :)
我 运行 遇到了同样的问题。我的监听器在服务的主线程之前启动。我将需要启动的侦听器列表排队,然后在主线程中尽早将它们全部激活。结果,所有传入的消息都能够得到处理并放入适当的可靠存储中。我的简单解决方案(这是一个服务总线监听器):
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);
}
========================
在主线程中,调用函数开始监听操作:
protected override async Task RunAsync (CancellationToken cancellationToken)
{
ClientAuthorizationBusCommunicationListener.StartOperations ();
...
这个问题很可能在这里表现出来,因为有问题的总线已经有了消息,并且在创建侦听器的那一刻就开始触发。尝试访问状态管理器中的任何内容都会抛出您所询问的异常。
我们在 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 link (https://msdn.microsoft.com/en-us/library/azure/system.fabric.fabricnotreadableexception.aspx)。但是
是什么意思Represents an exception that is thrown when a partition cannot accept reads.
是什么意思?分区不能接受读取是怎么回事?
在幕后,Service Fabric 有几种状态可以影响给定副本是否可以安全地提供读取和写入服务。他们是:
- 授予(您可以认为这是正常操作)
- 不是小学
- 无写入仲裁(再次主要影响写入)
- 重新配置待定
每当尝试对当前不是主副本并映射到 NotPrimary 状态的副本进行写入时,都会抛出您提到的 FabricNotPrimaryException。
FabricNotReadableException 映射到其他状态(您实际上不需要担心或区分它们),并且可能在各种情况下发生。一个示例是,如果您尝试对其执行读取的副本是 "Standby" 副本(一个已关闭且已恢复的副本,但副本集中已经有足够的活动副本)。另一个例子是如果副本是主副本但正在关闭(比如由于升级或因为它报告故障),或者如果它当前正在进行重新配置(比如正在添加另一个副本)。由于某些安全检查和 Service Fabric 需要在后台处理的原子更改,所有这些情况都将导致副本在短时间内无法满足写入。
您可以考虑 FabricNotReadableException 可重试。如果您看到它,只需再次尝试调用,最终它将解析为 NotPrimary 或 Granted。如果你得到 FabricNotPrimary 异常,通常这应该被抛回给客户端(或以某种方式通知客户端)它需要重新解析以找到当前的主(Service Fabric 提供的默认通信堆栈)监视不可重试的异常并代表您重新解决)。
FabricNotReadableException 目前有两个已知问题。
- FabricNotReadableException 应该有两个变体。第一个应该是显式可重试的 (FabricTransientNotReadableException),第二个应该是 FabricNotReadableException。第一个版本 (Transient) 是最常见的,可能是您 运行 正在进入的版本,当然在大多数情况下您会 运行 进入。第二个(非瞬态)将在您最终与备用副本对话的情况下返回。开箱即用的传输和重试逻辑不会与备用数据库通信,但如果您有自己的逻辑,则可以 运行 加入其中。
- 另一个问题是,今天 FabricNotReadableException 应该派生自 FabricTransientException,这样更容易确定正确的行为是什么。
作为答案发布(针对 asnider 的评论 - 3 月 16 日 17:42),因为评论太长了! :)
我也卡在这个catch 22了。我的svc启动后立即收到消息。我想在 OpenAsync 中封装服务启动并设置一些 ReliableDictionary 值,然后开始接收消息。但是,此时 Fabric 不可读,我需要在 OpenAsync 和 RunAsync 之间拆分 "startup" :(
我的服务中的RunAsync
和我的客户端中的 OpenAsync
似乎也有不同的取消标记,所以我也需要解决如何处理这个问题。只是感觉有点乱。关于如何在我的代码中整理它,我有很多想法,但有没有人想出一个优雅的解决方案?
如果 ICommunicationClient 有一个 RunAsync 接口,该接口在 Fabric 变为 ready/readable 时调用并在 Fabric 关闭副本时取消 - 这将大大简化我的生活。 :)
我 运行 遇到了同样的问题。我的监听器在服务的主线程之前启动。我将需要启动的侦听器列表排队,然后在主线程中尽早将它们全部激活。结果,所有传入的消息都能够得到处理并放入适当的可靠存储中。我的简单解决方案(这是一个服务总线监听器):
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);
}
========================
在主线程中,调用函数开始监听操作:
protected override async Task RunAsync (CancellationToken cancellationToken)
{
ClientAuthorizationBusCommunicationListener.StartOperations ();
...
这个问题很可能在这里表现出来,因为有问题的总线已经有了消息,并且在创建侦听器的那一刻就开始触发。尝试访问状态管理器中的任何内容都会抛出您所询问的异常。