しばやん雑記

Azure とメイドさんが大好きなフリーランスのプログラマーのブログ

Application Insights SDK でのパフォーマンスカウンターの収集をオフにする

最近は Log Analytics のコストが高いと言う相談をよく頂くので、本番環境のようにログが多くなるような環境向けにはログレベルの調整やサンプリング、そもそも送信するテレメトリをアプリケーションレベルで減らすと言う対応を提案するのですが、内部で使っているアプリケーションの Log Analytics の利用量とコストを確認すると AppPerformanceCounters が大半を消費していることがわかりました。

以下は App Service 上で動かしている ASP.NET Core アプリケーションの Application Insights の利用量ですが、半分以上が AppPerformanceCounters が消費していることが確認出来ます。

一般的なアプリケーションでは AppTracesAppDependencies が多くなりがちですが、今回の例では Log Analytics の料金の半分以上をパフォーマンスカウンターが消費していました。パフォーマンスカウンターは 1 分毎に送信されており、当然ながら一定の量は送信されるためこのような結果になりました。

ちなみに App Service や Azure Functions はサンドボックスの関係上、パフォーマンスカウンターを直接読むことは出来ないのですが環境変数経由で渡されているので、その値を Application Insights の Performance Collector が読み取って送信しています。

ちなみにパフォーマンスカウンターは Windows の App Service / Azure Functions でしか利用できませんが、Application Insights が CPU とメモリについては Linux でも送信するようになっています。正直なところ Windows の ASP.NET 向け以外では、どのくらい信頼性のある値なのかは不明です。

パフォーマンスカウンターの値は Metrics の中にある Performance Counters カテゴリーから確認出来ますが、この値を Application Insights から確認出来ることを知っている人は少なそうです。

個人的には App Service の Metrics に同じ項目があるので、わざわざ Application Insights 側で収集しなくても良いのではないかと考えています。なので、今回はオフにする方法を一通り確認しました。

ASP.NET (.NET Framework)

一番使いそうな ASP.NET (.NET Framework) 向けですが、標準で収集されるパフォーマンスカウンターは ASP.NET や CLR が含まれていて、App Service のようなサンドボックス以外の環境であれば収集するパフォーマンスカウンターを簡単に追加出来ます。

App Service の場合は組み込みの Application Insights 設定から、以下のように Recommend を選択するとパフォーマンスカウンターの収集が開始されます。通常は Recommend を選択すると思うので、パフォーマンスカウンターは意図せず収集されているケースが多いはずです。

ASP.NET (.NET Framework) の場合は 1 分毎に以下のようなデータが自動的に Application Insights に送信されています。ASP.NET の場合は便利そうな値も含まれているので、収集する価値はあるかもしれません。

App Service の組み込み Application Insights 設定から有効化した場合は細かい制御が出来ないのですが、ASP.NET アプリケーションに Application Insights SDK をインストールする方法の場合は、モジュール単位で機能のオンオフが可能です。

以下のドキュメントにもあるように ApplicationInsights.config から PerformanceCollectorModule を削除すれば、パフォーマンスカウンターの収集だけオフに出来ます。

パフォーマンスカウンターの収集をオフにすると Application Insights 上からは該当メトリックが見えなくなりますが、同じようなものは App Service や App Service Plan 側で確認出来るので問題にはならないはずです。

ASP.NET Core

ASP.NET Core 向けの Application Insights でもパフォーマンスカウンターの収集する機能がデフォルトでオンになっているので、ASP.NET よりは項目は少ないですが毎分送信される状態になっています。Linux ではサポートされていないとドキュメントには書かれていますが、実際には Linux でも CPU やメモリ使用量については収集されるようになっています。

明示的にパフォーマンスカウンターの収集をオフにするには、以下のドキュメントにもあるように EnablePerformanceCounterCollectionModulefalse にする必要がありますので、DI への追加時に設定しておくと良いです。

あるいは appsettings.json に対して以下のようにキーを設定することでもオフに出来ます。

{
  "ApplicationInsights": {
    "EnablePerformanceCounterCollectionModule": false
  }
}

App Service の場合は環境変数で上記のキーの設定をオーバーライドすることでもオフに出来るはずですが、環境によって設定を変える必要もないと思うので appsettings.json に書いておく形で問題ないでしょう。

Node.js

パフォーマンスカウンターは Windows 固有の機能ですが、Application Insights SDK 側で CPU とメモリ使用量については送信されるようになっているため、Node.js アプリケーション向けでもデフォルトで送信されています。前述したようにこの値が何処まで信頼できるものかは謎ですし、ほとんどのケースでは存在を意識していないはずなので、無駄に Log Analytics の容量を消費しているだけの可能性が高いです。

SDK をアプリケーションに導入している場合には、初期化時に setAutoCollectPerformance を呼び出して false を渡せばオフに出来るので簡単です。

App Service 組み込みの Application Insights を有効化している場合にはこの方法は使えないため、以下のドキュメントにもあるように App Settings に APPLICATIONINSIGHTS_CONFIGURATION_CONTENT というキーを追加してオフにする必要があります。

このキーには JSON で設定を書くことが出来るので、今回の場合は以下のような JSON を設定しておけばパフォーマンスカウンターの収集をオフに出来ます。

{"enableAutoCollectPerformance": false}

JSON ファイルをアプリケーションに含めておき、そのパスを設定する方法もありますが、このくらいの量なら直接書いてしまった方が分かりやすいと思います。

Azure Functions

パフォーマンスカウンターの収集は Azure Functions を使っている場合には、ランタイムレベルでデフォルト有効化されているため言語に関係なく行われています。

オフにするためには host.jsonenablePerformanceCountersCollection を追加するだけなので簡単ですが、Azure Functions の実装側に Application Insights SDK をインストールしていなくても収集されているため、気が付いていないケースが大半だと思います。

具体的な設定は以下のように host.jsonapplicationInsights セクションに設定を追加するだけです。これで Azure Functions Runtime 側のパフォーマンスカウンター収集がオフになります。

{
  "version": "2.0",
  "logging": {
    "applicationInsights": {
      "samplingSettings": {
        "isEnabled": true,
        "excludedTypes": "Request"
      },
      "enableLiveMetricsFilters": true,
      "enablePerformanceCountersCollection": false
    }
  }
}

言語や OS に関係なくデフォルトで収集されているのはあまり嬉しくないですが、コード側の対応なく host.json の修正だけで簡単にオフに出来るのは救いですね。

.NET Isolated の場合

殆どのケースは host.json の修正だけでパフォーマンスカウンターの収集をオフに出来るのですが、例外として .NET Isolated で Application Insights SDK を組み込んでいるケースが存在します。

.NET Isolated から Application Insights へ直接ログ送信を行っている場合には、Azure Functions Runtime が送信する分と .NET Isolated に組み込まれた SDK が送信する分が重複する問題があります。以下のクエリは .NET Isolated の場合はパフォーマンスカウンターの収集が 2 回行われていることを示しています。

単純に今でも無駄になっているパフォーマンスカウンター分のストレージを、.NET Isolated の場合は重複したデータで更に消費していることになるため最低でも片方は止めるべきでしょう。Azure Functions Runtime 側の収集は前述した通り host.json の修正でオフに出来ますが、.NET Isolated 側は ASP.NET Core の時のようにコードで対応する必要があります。

具体的には以下のどちらかの対応を入れることで .NET Isolated 側のパフォーマンスカウンターの収集をオフに出来ます。既に appsettings.json を使っている場合は前者の方が楽です。

using Microsoft.Azure.Functions.Worker;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

var host = new HostBuilder()
    .ConfigureFunctionsWebApplication()
    .ConfigureAppConfiguration((hostContext, config) =>
    {
        // ASP.NET Core と同じように appsettings.json に設定を書く場合
        config.AddJsonFile("appsettings.json", optional: true);
    })
    .ConfigureServices(services =>
    {
        services.AddApplicationInsightsTelemetryWorkerService(options =>
        {
            // 初期化時に明示的に無効化する場合
            options.EnablePerformanceCounterCollectionModule = false;
        });
        services.ConfigureFunctionsApplicationInsights();
    })
    .Build();

host.Run();

これで .NET Isolated の場合もパフォーマンスカウンターの収集をオフにすることが出来ました。ちなみに Java の Azure Functions についても、Application Insights への直接送信がサポートされているため、同じような状況の可能性があります。

ここまでの対応を入れることで、Log Analytics で確認出来るストレージ消費量は、意図した通りパフォーマンスカウンターのテーブルで 0 になりました。

パフォーマンスカウンターの収集をオフにしてもコストに対して劇的に効いてくるものではないですが、大量の App Service / Azure Functions を利用している場合には地味にストレージを圧迫している可能性があるため、コスト最適化の一環で見直しを行うのが良いと思います。