C#環境でのセッションメモリ使用量の可視化手法

システム開発
スポンサーリンク
スポンサーリンク

ASP.NET Core で Web アプリケーションを開発していると、次のような疑問や不安を感じることは少なくありません。

  • セッションにどの程度のデータを入れてよいのか分からない
  • Redis のメモリ使用量が増えているが、原因が特定できない
  • これは「セッション肥大化」なのか、それとも一時的な増加なのか判断できない

セッションは非常に便利な仕組みですが、設計を誤るとパフォーマンス低下やスケーラビリティ問題の原因になります。本記事では、ASP.NET Core におけるセッションの仕組みを整理したうえで、セッションメモリ使用量を「数値として可視化し、判断できる状態」にする方法を、実運用の視点から解説します。

ASP.NET Core におけるセッションの仕組み

ASP.NET Core のセッションは、ステートレスな HTTP 通信においてユーザーの状態を一時的に保持するための仕組みです。このセクションでは、セッションの基本構造と保存方式の選択肢を整理します。

セッションの基本構造と動作

ASP.NET Core のセッションは ISession インターフェースを通じて操作されます。保存できる値は byte[] のみであり、文字列やオブジェクトはシリアライズして格納する設計になっています。

セッションを利用するには、ミドルウェアとして UseSession() を登録する必要があります。各 HTTP リクエストでは、Cookie に含まれるセッション ID をキーとして、セッションストレージからデータが読み書きされます。

// セッション設定の一例
public void ConfigureServices(IServiceCollection services)
{
    services.AddDistributedMemoryCache();
    services.AddSession(options =>
    {
        options.IdleTimeout = TimeSpan.FromMinutes(20);
        options.Cookie.HttpOnly = true;
    });
}

※ .NET 6 以降の Minimal API 環境でも、AddSession / UseSession の考え方は同様です。

選択できるセッションストレージ方式

In-Memory セッション

  • アプリケーションプロセスのメモリ上に保持
  • 高速だが、スケールアウトに不向き
  • 開発・検証環境向け

分散キャッシュ(Redis / SQL Server)

  • 複数インスタンス間でセッションを共有可能
  • 本番環境では事実上の標準構成
  • メモリ使用量の監視が必須

Cookie ベース

  • 小規模データをクライアント側に保持
  • サーバーリソースを消費しないが、サイズ制限とセキュリティに注意

ストレージ方式によって、可視化すべきポイントも変わります。

セッションデータのメモリ使用量を確認する方法

セッション設計において重要なのは、「どれくらい使っているか」を感覚ではなく数値で把握することです。このセクションでは、In-Memory と分散セッションそれぞれの可視化手法を紹介します。

In-Memory セッション使用時の確認方法

In-Memory セッションでは、セッションデータがそのままプロセスのヒープに格納されます。そのため、ランタイムのメモリ指標を観測することで影響を把握できます。

dotnet-counters によるリアルタイム監視

dotnet-counters monitor --process-id <PID>

確認すべき主な指標は以下です。

  • GC Heap Size:アクセス増加に比例して右肩上がりなら要注意
  • Allocated Bytes/sec:セッション操作時のみ増えるなら正常

Visual Studio 診断ツール

  • セッション操作前後でメモリスナップショットを取得
  • DistributedSessionbyte[] を中心にオブジェクト数・サイズを確認

判断の目安

  • リクエスト完了後もヒープが戻らない → セッション保持の疑い
  • 操作のたびにヒープが増え続ける → 設計見直し対象

Redis を使用した分散セッションのサイズ確認

Redis を利用する場合、セッション肥大化は Redis 全体のメモリ逼迫に直結します。キー単位でのサイズ確認が重要です。

コマンドラインでの確認

redis-cli memory usage "Session:<session-id>"

セッション ID は次のように取得できます。

var sessionId = HttpContext.Session.Id;

判断の目安

  • 1 セッション 100KB 超:設計見直し検討
  • 256KB 超:保存しすぎの可能性が高い

GUI ツールによる分析

RedisInsight を使用すると、次の点を視覚的に確認できます。

  • セッションキーごとのサイズ
  • 大きい順でのソート
  • TTL(有効期限)の確認

運用ポイント

  • サイズ閾値を超えたセッションの定期チェック
  • TTL が切れないセッションの存在確認

セッションに保存するオブジェクトの最適化

基本的な保存方法

var userInfo = new UserProfile { Id = 1, Name = "Taro" };
var json = JsonSerializer.Serialize(userInfo);
HttpContext.Session.SetString("UserProfile", json);

読み出し時:

var json = HttpContext.Session.GetString("UserProfile");
if (!string.IsNullOrEmpty(json))
{
    var userInfo = JsonSerializer.Deserialize<UserProfile>(json);
}

サイズの数値化

var sizeInBytes = Encoding.UTF8.GetByteCount(json);

この値が、そのまま Redis やメモリ上の負荷の目安になります。

設計上の注意点

  • 保存するのは ID や状態フラグのみ
  • ネストの深いオブジェクトは避ける
  • Entity や ViewModel をそのまま保存しない
  • 必要に応じて DTO を定義する

やってはいけないセッション設計例

  • Entity Framework のエンティティを丸ごと保存
  • 画面遷移のために ViewModel 全体を保存
  • セッションを一時的なデータベースとして使用
  • 毎リクエストで無条件にセッションを更新

これらはすべて、セッション肥大化とパフォーマンス低下の原因になります。

メモリ肥大化の原因と対策

問題 内容 対策
大量データ保存 リストやバイナリを保存 ID のみ保持し実データは外部へ
IdleTimeout が長すぎる セッションが残り続ける 実利用に基づき短縮
複雑なオブジェクト 想定外のプロパティ混入 DTO 化
更新頻度過多 Redis 通信増加 状態変更時のみ更新

事例:Redis セッション肥大化の解消

EC サイトにおいて、カート情報をすべてセッションに保存していた結果、1 セッション数百 KB となり Redis メモリが逼迫しました。

対応内容

  • セッションにはカート ID のみ保存
  • 実データは DB 管理へ移行
  • セッションサイズ監視を導入

結果として、Redis メモリ使用量とレスポンスが大幅に改善しました。

まとめ

セッション管理で重要なのは、「便利だから入れる」のではなく、「入れる根拠を数値で説明できる」状態にすることです。

チェックリスト

  • セッション 1 件あたりのサイズを把握している
  • 256KB を超えるセッションが存在しない
  • セッションには ID のみ保存している
  • Redis の TTL を定期的に確認している
  • セッション更新は状態変更時のみ

これらを満たしていれば、セッションが原因のメモリ問題は未然に防げます。

システム開発
スポンサーリンク
シェアする
tobotoboをフォローする

コメント

タイトルとURLをコピーしました