リソース ログを使用して SignalR Service を監視する

この記事では、Azure Monitor 機能を使用して、Azure SignalR によって生成されたリソース ログ監視データを分析およびトラブルシューティングする方法について説明します。

Azure portal の各 Azure SignalR Service の [概要] ページには、コンカレント接続数やメッセージ数など、リソースの使用状況の要約が表示されます。 この有用な情報は、ポータルで使用できる監視データのごく一部です。 このデータの一部は自動的に収集され、リソースを作成するとすぐに分析に使用できるようになります。

構成の後には、他の種類のデータ収集を有効にできます。 この記事では、Azure Monitor ツールを使用してログ データ収集を構成し、このデータの分析とトラブルシューティングを行う手順について説明します。

前提条件

リソース ログを有効にするには、Azure Storage や Log Analytics など、ログ データを格納する場所を設定する必要があります。

  • Azure Storage ではポリシー監査、スタティック分析、バックアップのリソース ログを保持します。
  • Log Analytics は、Azure リソースによって生成された生ログの分析を可能にする柔軟なログ検索および分析ツールです。

リソース ログの有効化

Azure SignalR Service では、接続ログ、メッセージング ログ、HTTP 要求ログがサポートされます。 これらの種類のログの詳細については、「リソース ログのカテゴリ」を参照してください。 ログは、[診断ログ] ペインで構成したストレージ アカウントに格納されます。 ストレージの形式とフィールドの詳細については、「データ ストレージ」を参照してください。

診断設定の作成

既定では、リソース ログは無効になっています。 診断設定を使用してリソース ログを有効にするには、「Azure Monitor での診断設定の作成」を参照してください。

リソース ログのクエリを実行する

リソース ログのクエリを実行するには、次の手順に従います。

  1. 対象の Log Analytics の [ログ] を選びます。

    Log Analytics メニュー項目

  2. SignalRServiceDiagnosticLogs」と入力し、時間の範囲を選択します。 詳細なクエリについては、「Azure Monitor で Log Analytics の使用を開始する」を参照してください。

    Log Analytics のクエリ ログ

Azure SignalR Service のサンプル クエリを使用するには、次の手順に従います。

  1. 対象の Log Analytics の [ログ] を選びます。

  2. [クエリ] タブを選択してクエリ エクスプローラーを開きます。

  3. [リソースの種類] を選択して、リソースの種類でサンプル クエリをグループ化します。

  4. [実行] を選び、スクリプトを実行します。

    Log Analytics のサンプル クエリ

Azure SignalR Service のクエリの例については、「SignalRServiceDiagnosticLogs テーブルのクエリ」を参照してください。

Note

Storage の保存先のクエリ フィールド名は、Log Analytics のフィールド名とは若干異なります。 Storage テーブルと Log Analytics テーブル間のフィールド名マッピングの詳細については、「リソース ログ テーブルのマッピング」を参照してください。

リソース ログを使用したトラブルシューティング

Azure SignalR Service のトラブルシューティングを行うには、サーバー/クライアント側のログ上でエラーをキャプチャできるようにします。 Azure SignalR Service でリソース ログが公開されている場合は、リソース ログを利用してサービスのログのトラブルシューティングを行うことができます。

接続が予期せず増えた、または切断された場合は、接続ログを利用してトラブルシューティングを行うことができます。 多くの場合、一般的な問題は、予期しない接続数の変化、接続数の上限への到達、承認エラーに関連しています。 以下のセクションでは、トラブルシューティングの方法について説明します。

予期しない接続の削除

予期せずに接続が切断された場合は、まず、サービス、サーバー、クライアント側のログを有効にします。

接続が切断されると、リソース ログにこの切断イベントが記録され、operationName には ConnectionAborted または ConnectionEnded が表示されます。

ConnectionAbortedConnectionEnded の違いは、ConnectionEnded はクライアントまたはサーバー側によってトリガーされた予期された切断であるという点です。 ConnectionAborted は多くの場合、予期しない接続の切断イベントであり、中断の理由は message に示されます。

次の表に、中断の理由を示します。

理由 説明
接続数が上限に達している 接続数が現在の価格レベルの上限に達しています。 サービス ユニットのスケールアップを検討してください
アプリケーション サーバーによって接続が閉じられた アプリ サーバーでは中断がトリガーされます。 予期された中断と考えることができます
接続の ping がタイムアウトした 通常はネットワークの問題が原因です。 インターネットからアプリ サーバーの利用可否を確認することを検討してください
サービスの再読み込み中、再接続を試行中 Azure SignalR Service が再読み込み中です。 Azure SignalR では、自動での再接続をサポートしています。Azure SignalR Service に再接続されるまで待機するか、または手動で再接続することができます
内部サーバーの一時的なエラー Azure SignalR Service で一時的なエラーが発生しています。自動的に復旧されます
サーバー接続が削除された 不明なエラーによってサーバー接続が削除されています。まず、サービス/サーバー/クライアント側のログを利用して自己トラブルシューティングすることを検討してください。 基本的な問題 (ネットワークの問題、アプリ サーバー側の問題など) を除外してみてください。 問題が解決されない場合は、Microsoft にお問い合わせください。 詳細については、「ヘルプの参照」セクションを参照してください。

予期せずに接続が増加している

予期しない接続の増加に関するトラブルシューティングを行うには、最初に余計な接続をフィルターで除外する必要があります。 テスト クライアント接続に、一意のテスト ユーザー ID を追加できます。 リソースを確認してください。 複数のクライアント接続に同じテスト ユーザー ID または IP があることがわかった場合は、クライアント側では想定よりも多くの接続が作成されている可能性があります。 クライアント側を確認します。

承認エラー

クライアント要求に対して未承認 401 が返された場合は、リソース ログを確認します。 Failed to validate audience. Expected Audiences: <valid audience>. Actual Audiences: <actual audience> が発生している場合は、アクセス トークン内のすべてのユーザーが無効になっていることを意味します。 ログ上に提示されている有効なユーザーを使用してみてください。

調整

Azure SignalR Service への SignalR クライアント接続を確立できないことがわかった場合は、リソース ログを確認してください。 リソース ログ上で Connection count reaches limit が発生している場合は、確立している SignalR Service への接続が多すぎて、接続数の上限に到達しています。 SignalR サービスのスケールアップを検討してください。 リソース ログ上で Message count reaches limit が発生している場合は、Free レベルを利用しており、メッセージのクォータを最大まで使用していることを意味します。 さらにメッセージを送信する場合は、SignalR Service を Standard レベルに変更して追加のメッセージを送信することを検討してください。 詳細については、「Azure SignalR Service の価格」を参照してください。

メッセージ関連の問題が発生した場合は、メッセージング ログを利用してトラブルシューティングすることができます。 まず、サービスでリソース ログを有効にし、サーバーとクライアントのログを記録します。

Note

ASP.NET Core の場合は、こちらを参照して、サーバーとクライアントでログを有効にします。

ASP.NET の場合は、こちらを参照して、サーバーとクライアントでログを有効にします。

パフォーマンスへの影響があることやクライアントからサーバー方向のメッセージがないことが気にならない場合は、Log Source Settings/TypesMessaging を確認して、collect-all ログ収集動作を有効にします。 この動作の詳細については、「すべて収集」を参照してください。

それ以外の場合は、Messaging をオフにして collect-partially のログ収集動作を有効にします。 この動作を有効にするには、クライアントとサーバーで構成する必要があります。 詳細については、「一部収集」を参照してください。

メッセージの損失

メッセージの損失の問題が発生した場合、メッセージの損失が発生した場所を特定することが重要です。 Azure SignalR Service を使う場合、基本的に 3 つのコンポーネント (SignalR サービス、サーバー、クライアント) があります。 ネゴシエーションが完了すると、サーバーとクライアントの両方が SignalR サービスに接続されますが、相互に直接接続されません。 そのため、メッセージには 2 つの方向を考慮する必要があります。それぞれの方向について、2 つのパスを考慮する必要があります。

  • SignalR サービス経由でクライアントからサーバーへ
    • パス 1: クライアントから SignalR サービスへ
    • パス 2: SignalR サービスからサーバーへ
  • SignalR サービス経由でサーバーからクライアントへ
    • パス 3: サーバーから SignalR サービスへ
    • パス 4: SignalR サービスからクライアントへ

メッセージ パス

すべて収集の収集動作の場合:

Azure SignalR Service は、SignalR サービス経由のサーバーからクライアント方向のメッセージのみをトレースします。 トレース ID はサーバーで生成されます。 このメッセージは、トレース ID を SignalR サービスに伝達します。

Note

アプリ サーバーでメッセージをトレースし、ハブの外部からメッセージを送信する場合は、すべて収集の収集動作を有効にして、診断クライアントから送信されたものではないメッセージのメッセージ ログを収集する必要があります。 診断クライアントは、すべて収集一部収集の両方の収集動作で機能しますが、ログ収集の優先順位が高くなります。 詳細については、「診断クライアント」セクションを参照してください。

サインイン サーバーとサービスの側を確認することで、メッセージがサーバーから送信されるかどうか、SignalR サービスに到着するかどうか、SignalR サービスから送信されるかどうかを簡単に確認できます。 基本的に、メッセージ トレース ID に基づいて "受信済み" と "送信済み" のメッセージが一致するかどうかを確認することで、メッセージの損失の問題がこの方向のサーバーまたは SignalR サービスの側にあるかどうかを判断できます。 詳細については、以下の詳細を参照してください。

一部収集の収集動作の場合:

クライアントを診断クライアントとしてマークすると、Azure SignalR Service は両方の方向のメッセージをトレースします。

サインイン サーバーとサービスの側を確認することで、メッセージがサーバーまたは SignalR サービスを正常に通過したかどうかを簡単に確認できます。 基本的に、メッセージ トレース ID に基づいて "受信済み" と "送信済み" のメッセージが一致するかどうかを確認することで、メッセージの損失の問題がサーバーまたは SignalR サービスの側にあるかどうかを判断できます。 詳しくは、次の詳細をご覧ください。

メッセージ フローの詳細

SignalR サービス経由でクライアントからサーバー方向の場合、SignalR サービスは、診断クライアントから送信された呼び出し、つまり診断クライアントで直接生成されたメッセージ、または診断クライアントの呼び出しにより間接的に生成されたサービス メッセージのみを考慮します。

パス 1 では、メッセージが SignalR サービスに到着した時点で、SignalR サービス内にトレース ID が生成されます。 SignalR サービスは、診断クライアントの各メッセージに対してログ Received a message <MessageTracingId> from client connection <ConnectionId>. を生成します。 SignalR からサーバーにメッセージが送信されると、SignalR サービスから次のログ メッセージが生成されます: Sent a message <MessageTracingId> to server connection <ConnectionId> successfully.。 この 2 つのログを見れば、メッセージが SignalR サービスを正常に通過したことを確認できます。

Note

ASP.NET Core SignalR の制限があるため、クライアントから送信されるメッセージにはメッセージ レベル ID が含まれていませんが、ASP.NET SignalR は、各メッセージに呼び出し ID を生成します。 これを使用して、トレース ID とマップできます。

次に、このメッセージはパス 2 のトレース ID サーバーを伝達します。 メッセージが到着すると、サーバーによってログ Received message <messagetracingId> from client connection <connectionId> が生成されます。

メッセージがサーバー内でハブ メソッドを呼び出すと、"新しいトレース ID" で新しいサービス メッセージが生成されます。 サービス メッセージが生成されると、サーバーによってサインイン テンプレート Start to broadcast/send message <MessageTracingId> ... が生成されます。 実際のログは、実際のシナリオに基づいています。 その後、メッセージは、パス 3 で SignalR サービスに送信されます。 サービス メッセージがサーバーから送信されると、Succeeded to send message <MessageTracingId> というログが生成されます。

Note

クライアントからのメッセージのトレース ID は、SignalR サービスに送信されるサービス メッセージのトレース ID にマップできません。

サービス メッセージが SignalR サービスに到着すると、Received a <MessageType> message <MessageTracingId> from server connection <ConnectionId>. というログが生成されます。 次に、SignalR サービスはサービス メッセージを処理し、対象のクライアントに配信します。 パス 4 のクライアントにメッセージが送信されると、ログ Sent a message <MessageTracingId> to client connection <ConnectionId> successfully. が生成されます。

まとめると、SignalR サービスとサーバーでメッセージが送受信されると、メッセージ ログが生成されます。 これらのログを使って、これらのコンポーネントでメッセージが失われたかどうかを検証できます。

次の例は、一般的なメッセージ損失の問題です。

あるクライアントがグループ内のメッセージを受信できない

この問題の一般的なストーリーは、グループ メッセージを送信した後に、クライアントがグループに参加する場合です。

Class Chat : Hub
{
    public void JoinAndSendGroup(string name, string groupName)
    {
        Groups.AddToGroupAsync(Context.ConnectionId, groupName); // join group
        Clients.Group(groupName).SendAsync("ReveiceGroupMessage", name, "I'm in group"); // send group message
    }
}

たとえば、誰かが同じハブ メソッドで join groupsend group message を呼び出したとします。 ここで問題なのは、AddToGroupAsyncasync メソッドであることです。 AddToGroupAsync が完了するまで待機するための await がないため、AddToGroupAsync が完了する前にグループ メッセージが送信されます。 ネットワークの遅延、クライアントがあるグループに参加するプロセスの遅延により、join group アクションはグループ メッセージの配信よりも遅れて完了することがあります。 その場合、クライアントがグループに参加しておらず、最初のグループ メッセージに受信者としてのクライアントがないため、メッセージが失われる問題が発生します。

リソース ログがなければ、クライアントがいつグループに参加し、いつグループ メッセージが送信されたかを把握できません。 メッセージング ログを有効にすると、SignalR サービスのメッセージ到着時刻を比較できます。 次の手順に従ってトラブルシューティングを行います。

  1. サーバーのメッセージ ログを見つけて、クライアントがグループに参加した時刻と、グループ メッセージが送信された時刻を確認します。
  2. メッセージ ログから、グループ参加のメッセージ トレース ID A とグループ メッセージのメッセージ トレース ID B を取得します。
  3. ログ アーカイブ ターゲット内のメッセージング ログの中からこれらのメッセージ トレース ID を絞り込み、到着タイムスタンプを比較します。 SignalR サービスで最初に到着したメッセージを見つけます。
  4. メッセージ トレース ID A の到着時刻が B の到着時刻より後の場合は、クライアントがグループに参加する前にグループ メッセージを送信する必要があります。 グループ メッセージを送信する前に、クライアントがグループ内にあることを確認する必要があります。

メッセージが SignalR またはサーバーで失われた場合、メッセージのトレース ID に基づいた警告ログを取得して、その理由を確認してみてください。 さらにヘルプが必要な場合は、「ヘルプの参照」セクションを参照してください。

リソース ログの収集動作

リソース ログ (特にメッセージング ログ) の使用には、2 つの一般的なシナリオがあります。

誰かが各メッセージの品質を気にする場合があります。 たとえば、メッセージの送受信に成功したかどうかについて配慮する場合や、SignalR サービス経由で配信されたすべてのメッセージを記録したい場合があります。

一方で、パフォーマンスを気にする場合もあります。 メッセージの待機時間について配慮し、何らかの理由ですべての接続ではなく、一部の接続のメッセージを追跡する必要がある場合もあります。

そのため、SignalR サービスには 2 種類の収集動作があります。

  • すべて収集: すべての接続のログを収集します
  • 一部収集: 特定の接続のログを収集します

Note

ログを収集する接続と収集しない接続を区別するために、SignalR サービスは、サーバーとクライアントの診断クライアント構成に基づいて、一部のクライアントを診断クライアントとして扱います。診断クライアントでは、リソース ログが常に収集され、それ以外では収集されません。 詳細については、「一部収集」セクションを参照してください。

すべて収集

リソース ログは、すべての接続で収集されます。 メッセージング ログを例にとってみましょう。 この動作を有効にすると、SignalR サービスからサーバーに通知が送信され、各メッセージのトレース ID の生成が開始されます。 トレース ID は、メッセージに含まれており、サービスに送信されます。 このサービスでは、トレース ID を使用してメッセージもログに記録されます。

Note

SignalR サービスのパフォーマンスを確保するために、SignalR サービスはクライアントから送信されたメッセージ全体を待機して解析しないことに注意してください。 このため、クライアント メッセージはログに記録されません。 クライアントが診断クライアントとしてマークされている場合、クライアント メッセージは SignalR サービスに記録されます。

構成ガイド

この動作を有効にするには、[Log Source Settings]\(ログ ソースの設定\)[種類] セクションのチェックボックスをオンにします。

この動作の場合、サーバー側の構成を更新する必要はありません。 この構成の変更は常に自動的にサーバーに送信されます。

一部収集

リソース ログは診断クライアントによってのみ収集されます。 診断クライアントのクライアント メッセージと接続イベントを含むすべてのメッセージがログに記録されます。

Note

診断クライアント数の上限は 100 です。 診断クライアント数が 100 を超えると、超えた分の診断クライアントは SignalR サービスによって調整されます。 新しい、超過分のクライアントは SignalR サービスに接続できず、System.Net.Http.HttpRequestException をスローします。これには、メッセージ Response status code does not indicate success: 429 (Too Many Requests) が含まれます。 既に接続されているクライアントは、調整ポリシーの影響を受けずに動作します。

診断クライアント

診断クライアントは論理的な概念です。 任意のクライアントを診断クライアントにすることができます。 サーバーは、診断クライアントにすることができるクライアントを制御します。 あるクライアントを診断クライアントとしてマークすると、このクライアントではすべてのリソース ログが有効になります。 クライアントを診断クライアントに設定するには、構成ガイドを参照してください。

構成ガイド

この動作を有効にするには、サービス、サーバー、クライアント側を構成する必要があります。

サービス側

この動作を有効にするには、[Log Source Settings]\(ログ ソースの設定\)[種類] セクションで、該当するログの種類のチェックボックスをオフにします。

サーバー側

また、クライアントから送信される HTTP コンテキストに基づいて、診断クライアントのフィルターを定義するように ServiceOptions.DiagnosticClientFilter を設定します。 たとえば、ハブ URL が <HUB_URL>?diag=yes であるクライアントを作成し、ServiceOptions.DiagnosticClientFilter を設定して診断クライアントをフィルター処理します。 true が返される場合、クライアントは診断クライアントとしてマークされます。 それ以外の場合は、通常のクライアントのままです。 ServiceOptions.DiagnosticClientFilter はスタートアップ クラスで次のように設定できます。

// sample: mark a client as diagnostic client when it has query string "?diag=yes" in hub URL
public IServiceProvider ConfigureServices(IServiceCollection services)
{
    services.AddMvc();
    services
        .AddSignalR()
        .AddAzureSignalR(o =>
        {
            o.ConnectionString = "<YOUR_ASRS_CONNECTION_STRING>";
            o.DiagnosticClientFilter = context => context.Request.Query["diag"] == "yes";
        });

    return services.BuildServiceProvider();
}
クライアント側

HTTP コンテキストを構成して、クライアントを診断クライアントとしてマークします。 たとえば、クエリ文字列 diag=yes を追加することで、クライアントは診断クライアントとしてマークされます。

var connection = new HubConnectionBuilder()
    .WithUrl("<HUB_URL>?diag=yes")
    .Build();

ヘルプを参照する

最初に自分でトラブルシューティングを行うことをお勧めします。 ほとんどの問題は、アプリ サーバーまたはネットワークの問題によって引き起こされています。 根本原因を探るには、リソース ログを使用したトラブルシューティングのガイド基本のトラブルシューティング ガイドに従ってください。 それでも問題が解決しない場合は、GitHub でイシューをオープンするか、Azure portal でチケットを作成することを検討してください。 [プロバイダー]:

  1. 問題が発生したときの時間範囲約 30 分
  2. Azure SignalR Service のリソース ID
  3. 問題の詳細 (可能な限り具体的に示す)。たとえば、appserver からメッセージが送信されていない、クライアント接続が削除されたなど。
  4. サーバー/クライアント側から収集されたログと、役に立つ可能性があるその他の資料
  5. [省略可能] 再現コード

Note

GitHub でイシューをオープンする場合は、機密情報 (リソース ID、サーバー/クライアント ログなど) は非公開のままにします。 非公開で、Microsoft 組織内のメンバーにのみ送信します。