12

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 ) を見ました。しかし、何が

パーティションが読み取りを受け入れることができない場合にスローされる例外を表します。

平均?パーティションが読み取りを受け入れられないのはなぜですか?

4

3 に答える 3

15

内部的には、Service Fabric にはいくつかの状態があり、特定のレプリカが読み取りと書き込みを安全に処理できるかどうかに影響を与える可能性があります。彼らです:

  • あり(これは通常の操作と考えてよい)
  • プライマリーではない
  • 書き込みクォーラムなし (これも主に書き込みに影響します)
  • 再構成保留中

あなたが言及した FabricNotPrimaryException は、現在プライマリではないレプリカで書き込みが試行され、NotPrimary 状態にマップされるたびにスローされる可能性があります。

FabricNotReadableException は他の状態にマップされ (特に心配したり区別したりする必要はありません)、さまざまなケースで発生する可能性があります。1 つの例は、読み取りを実行しようとしているレプリカが「スタンバイ」レプリカ (ダウンしていて回復されたが、レプリカ セットに十分な数のアクティブなレプリカが既に存在するレプリカ) である場合です。もう 1 つの例は、レプリカがプライマリであるが閉じられている場合 (たとえば、アップグレードのため、または障害が報告されたために)、または現在再構成中である場合 (たとえば、別のレプリカが追加されている場合) です。これらのすべての条件により、Service Fabric が内部で処理する必要がある特定の安全性チェックとアトミックな変更が原因で、レプリカが短時間書き込みを満たすことができなくなります。

FabricNotReadableException は再試行可能と見なすことができます。表示された場合は、もう一度呼び出してみてください。最終的には NotPrimary または Granted に解決されます。FabricNotPrimary 例外が発生した場合、通常、現在のプライマリ (Service Fabric が出荷する既定の通信スタック) を見つけるために再解決する必要があることをクライアント (または何らかの方法でクライアントに通知) にスローする必要があります。再試行不可能な例外を監視し、あなたに代わって再解決します)。

FabricNotReadableException には、現在 2 つの既知の問題があります。

  1. FabricNotReadableException には 2 つのバリアントが必要です。1 つ目は明示的に再試行可能 (FabricTransientNotReadableException) である必要があり、2 つ目は FabricNotReadableException である必要があります。最初のバージョン (Transient) が最も一般的であり、おそらく遭遇するものであり、ほとんどの場合に遭遇するものです。2 番目 (非一時的) は、スタンバイ レプリカと通信する場合に返されます。すぐに使用できるトランスポートおよび再試行ロジックでは、スタンバイとの通信は発生しませんが、独自のロジックがある場合は、それに遭遇する可能性があります。
  2. もう 1 つの問題は、現在、FabricNotReadableException が FabricTransientException から派生している必要があるため、正しい動作が何であるかを判断しやすくなっているということです。
于 2015-11-30T19:40:07.003 に答える
1

コメントには長すぎたため、回答として投稿しました (asnider のコメント - 3 月 16 日 17:42)。:)

私もこのキャッチ22で立ち往生しています。私のsvcは起動し、すぐにメッセージを受信します。OpenAsync でサービスの起動をカプセル化し、いくつかの ReliableDictionary 値を設定してから、メッセージの受信を開始したいと考えています。ただし、この時点でファブリックは読み取り可能ではないため、この「スタートアップ」を OpenAsync と RunAsync に分割する必要があります :(

RunAsync私のサービスとOpenAsyncクライアントでも異なるキャンセルトークンがあるように見えるので、これにも対処する方法を回避する必要があります。それはすべて少し面倒に感じます。コードでこれを整理する方法について多くのアイデアがありますが、エレガントな解決策を思いついた人はいますか?

ICommunicationClientに RunAsync インターフェイスがあり、Fabric が準備完了/読み取り可能になったときに呼び出され、Fabric がレプリカをシャットダウンしたときにキャンセルされると便利です。これにより、私の人生が大幅に簡素化されます。:)

于 2016-07-13T11:20:57.730 に答える
0

私は同じ問題に遭遇していました。私のリスナーは、サービスのメインスレッドの前に起動していました。開始する必要があるリスナーのリストをキューに入れ、メイン スレッドの早い段階でそれらをすべてアクティブにしました。その結果、受信したすべてのメッセージを処理し、適切な信頼できるストレージに配置することができました。私の簡単な解決策(これはサービスバスリスナーです):

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 ();

...

問題のバスにはすでにメッセージがあり、リスナーが作成された 2 番目に発火し始めたため、この問題がここで明らかになった可能性があります。状態マネージャーで何かにアクセスしようとすると、質問していた例外がスローされました。

于 2018-08-13T20:37:54.260 に答える