App Service にデプロイした .NET アプリの応答遅延を分析する

# はじめに

この記事ではApp Service にデプロイした .NET アプリの応答遅延を分析します。
下記の記事で事前準備してあります。

https://qiita.com/georgeOsdDev@github/items/a365eb6c97dc4538d045

# 応答遅延の再現

10秒スリープするエンドポイントの例

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4914/18f7926a-6918-6eb5-5af7-6e884c1ae0d4.png)

ランダムに1~10秒遅延するリクエストを5分送ります。

```js:sleepRandom.js
import http from 'k6/http';

import { sleep } from 'k6';

export default function () {

http.setResponseCallback(http.expectedStatuses(200));
// Generate a random sleep time between 1 and 10 seconds
const sleepTime = Math.floor(Math.random() * 10) + 1;
http.get('https://toshida-dotnet-buggyapp.azurewebsites.net/api/SlowRequest/sleep/' + sleepTime);

sleep(1);

}
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4914/2343c592-95ff-9b2f-430b-d35a021835e4.png)

平均応答時間は 5.67 秒でした。

## メトリックをみる

「応答時間(`HttpResponseTime`)」を見ておきます。

https://learn.microsoft.com/ja-jp/azure/app-service/web-sites-monitor#understand-metrics

https://learn.microsoft.com/ja-jp/azure/azure-monitor/reference/supported-metrics/microsoft-web-sites-metrics

なお App Service のメトリックは Kudu サイトへのアクセスも含まれるため、例えば Linux 環境で SSH 接続している場合などはメトリックに影響が出る可能性が大きいため注意が必要です。

以下のように平均、最大ともにクライアント側で得た実績と一致しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4914/d49db1ad-d017-fbad-35cb-ab534f8c1ded.png)

## ログをみる

### AppServiceHTTPLogs

`AppServiceHTTPLogs` を見ておきます。概ねメトリックのグラフと一致していることが確認できます。

```sql
AppServiceHTTPLogs
| where TimeGenerated >= ago(30m)
| where CsHost == "toshida-dotnet-buggyapp.azurewebsites.net"
| where CsUriStem startswith "/api/SlowRequest/sleep/"
| where UserAgent == "k6/0.48.0+(https://k6.io/)"
| summarize count(), min(TimeTaken),avg(TimeTaken),max(TimeTaken) by bin(TimeGenerated,1m),ScStatus
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4914/f0fdb134-26a2-1fde-816c-927f58791e24.png)

## Application Insights

### traces テーブル

アプリケーションがログを出力しているのであれば、ここである程度原因は絞り込めます。
アプリの実装を知っているという事情もありますが、ログからもスリープ処理に時間がかかっていることがわかります。

```sql
traces
| order by timestamp asc
| project-reorder timestamp,message,operation_Id,operation_Name
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4914/c8e33582-1abb-42f9-9526-7d0f0758b8be.png)


### Live Metric

事象発生中であれば Live Metric を見てみるのもいいかもしれません。

https://learn.microsoft.com/ja-jp/azure/azure-monitor/app/live-stream?tabs=dotnet6

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4914/2246458c-5e65-1289-ba11-5a10ebcabffe.png)

# 問題の診断と解決をみる

## Availability and Performance > Web アプリが遅い

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4914/f80e8f1b-0d93-2ea7-8c51-f5b21103025c.png)

## Availability and Performance > 要求の実行が遅い

AppInsights ので Dependency で遅かった例がでてますが、ここは今回関係なさそうなので無視

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4914/7d2f711a-96c1-0c59-6379-1aeade73878c.png)

## Diagnostic Tools >Collect .NET Profiler Trace

「要求の実行が遅い」でも提案されている1つ目の方法としてプロファイラートレースをとってみます。
取得は問題の診断と解決から可能。説明にあるようにトレースを開始してから60秒以内に状況をリプロさせます。
今回のように問題が発生するURLが特定できていて、容易にリプロできる場合には有効そうです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4914/54e6745f-b27c-c97f-9270-960a12d65b19.png)

結果の見方については深堀が必要ですが、だいたいのことは下記のブログに書いてあります。

https://azure.github.io/AppService/2018/06/06/App-Service-Diagnostics-Profiling-an-ASP.NET-Web-App-on-Azure-App-Service.html

https://azure.github.io/jpazpaas/2023/06/28/Get-CLR-Profiler-in-AppService.html

### Slowest Request

アプリコードが遅いって教えてくれます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4914/c9557bb4-b540-af94-7b86-8acb86fc0daa.png)

### .NET Core Slow Requets

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4914/7819697e-0e3c-b6aa-f710-72e0e81ec018.png)

### Thread Callstacks

コントローラーのスタックで `Thread.Sleep` が呼ばれていることがわかります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4914/351ed4f2-11ab-dc2c-833d-84b946f1a46b.png)

### Application Insights を利用したプロファイラーの取得

プロファイラーについては Application Insights 側でも同様の機能が提供されています。

https://learn.microsoft.com/ja-jp/azure/azure-monitor/profiler/profiler

https://learn.microsoft.com/ja-jp/azure/azure-monitor/profiler/profiler-data

UI 的にはこっちのほうがわかりやすいかもしれないですね。どこで時間がかかったのかが一目瞭然です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4914/ef8f848b-f34c-3656-d6fd-f8e34e59b473.png)

ダウンロードしたものを PerfView でも確認できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4914/9e30fc91-72db-4367-ffff-10a489bd258c.png)

# まとめ

処理遅延系はプロファイラートレースが有効そうです。
思考の順序としては以下の流れ

- メトリックからどの程度遅延が起きているのか確認
- `AppServiceHTTPLogs`から問題が発生しているURLの特定
- アプリのログから何か得られる情報がないか確認
- 再現可能かどうかの確認
- プロファイラトレースでの分析


その他の遅延のパターンについては別記事で書く予定。