SqlConnection(ADO.NET)によるSQL Server接続のアイドルタイムアウトについての検証

この記事は公開から4年以上経過しています。

.NET開発でSqlConnection(ADO.NET)を使用してMicrosoft® SQL Serverに接続する場合に、接続プールがタイムアウトするのかどうか気になり調査してみたので、その備忘録。

疑問

SqlConnectionでDB(接続プール)に接続を行なった場合、

  • アイドルタイムアウトにより自動的に切断されるのか。
  • 接続文字列でConnection Lifetimeを明示した場合、指定時間でアイドルタイムアウトして自動的に切断されるのか。

Microsoft Docsから抜粋した以下の説明

接続の削除
接続プール機能は、アイドル状態の時間が約 4-8 分になったか、サーバーとの接続が切断されたことをプール機能が検出した場合に、プールからの接続を削除します。 サーバーとの通信を試みた後にのみ、切断されたサーバー接続が検出可能になることに注意してください。 接続がサーバーに接続していないことがわかると、その接続は無効としてマークされます。 無効な接続は、閉じられるか、または再利用された場合のみ、接続プールから削除されます。

および

Connection Lifetime
接続がプールに返された時点で、その接続の作成時刻と現在の時刻を比較し、その時間の長さ (秒) が Connection Lifetime で指定した値を超えている場合は、その接続が破棄されます。 これは、クラスター構成を採用している状況で、実行中のサーバーと、オンラインになったばかりのサーバーの間での、負荷を強制的に分散するのに便利です。値ゼロ (0) を指定した場合は、プールされている接続に、最大のタイムアウトが割り当てられます。

から、接続プールに接続した状態で4〜8分、または指定したConnection Lifetimeを超過した場合はタイムアウトして自動的に切断されるようにも見える。

検証

実際にタイムアウトで接続が切断されるかどうか、以下のような条件とプログラムで検証。

前提条件:

  • 開発環境は Visual Studio 2017/.NET4.5/C#
  • SQLサーバーは Microsoft SQL Server 2019(Developer)
  • SQLサーバー側の設定は互換レベルをSQLServer2012に設定、その他はインストール時のデフォルト設定(互換レベルを指定しているのは個人的な都合)
  • 接続数の確認はパフォーマンスモニター(SQLServer:General Statistics\User Connections) + SQL Server Profiler(補助)

確認手順:

  • 検証プログラムで接続プールの最大接続数を接続した状態で10分以上放置する。

確認方法:

  • 検証プログラムのステータス変更イベントの監視、および接続直後と10分以上経過した前後でサーバー接続数が変化するかを確認する。

検証ソースコード

using System;
using System.Data.SqlClient;

namespace SQLServerTest201030
{
    internal class Program
    {
        private static void Main(string[] args)
        {
            var sb = new SqlConnectionStringBuilder()
            {
                DataSource = "localhost",
                UserID = "user",
                Password = "password",
                MaxPoolSize = 5,
                //Pooling = false,
            };
            // 接続プールへの接続数確認用ループ
            for (var i = 1; ;)
            {
                // ループ毎に新しい接続を作成
                var con = new SqlConnection(sb.ConnectionString + ";Connection Lifetime=60");
                Console.WriteLine($"Connection {i}");
                con.StateChange += (o, e) =>
                {
                    switch (e.CurrentState)
                    {
                        case System.Data.ConnectionState.Open:
                            ++i;
                            break;

                        case System.Data.ConnectionState.Closed:
                            --i;
                            break;
                    }
                    Console.WriteLine($"Status = {e.CurrentState}");
                };
                con.InfoMessage += (o, e) =>
                {
                    Console.WriteLine($"Info = {e.Message}");
                };
                try
                {
                    con.Open();
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"Error = {ex.Message}");
                }
                // 接続を明示的に閉じない
                //con.Close();
                Console.ReadLine();
            }
        }
    }
}

結果

10分以上待機させてみた結果は、下図のとおり。

検証プログラム実行画面
file
→接続1〜5で切断イベントは発生していない。 ※最大接続プール数が5なので、6接続目はエラーとなっている

パフォーマンスモニターのSQL Serverユーザー接続数
file
→接続1〜5全ての接続が維持されている。

結論

SqlConnectionの接続は4〜8分Connection Lifetimeの超過によりアイドルタイムアウトで自動的に切断されることはない模様。

Microsoft Docsから抜粋した以下の説明のとおり、使い終わった接続は必ず明示的に閉じる必要がある。

注意事項
接続がプールに返されるようにするために、接続を使い終えたら必ず接続を終了することを強くお勧めします。 この操作は、Connection オブジェクトの Close または Dispose メソッドを使用して、あるいは C# の using ステートメントまたは Visual Basic の Using ステートメントの内部ですべての接続を開くことによって、行うことができます。 明示的に終了されていない接続は、プールに追加したり返したりすることができないことがあります。 詳しくは、「using ステートメント」または「方法: システム リソースを破棄する」 (Visual Basic の場合) をご覧ください。

参考ウェブサイトなど

以上です。

シェアする

  • このエントリーをはてなブックマークに追加

フォローする