SQL Azureでのコネクションプール起因のエラー発生を軽減させるバージョンアップ

バージョンアップ内容

2011年8月9日にマイクロソフトがリリースした.NET Framework4の信頼性に関する更新1(http://support.microsoft.com/kb/2533523)で、本問題の改善が図られています。

基本的に、SqlClientがアプリケーションにプールを返す前に、プールのコネクションが無効化されていないかを確認します。もしコネクションが無効の場合、SqlClientは単純にアプリケーションにコネクションを返す前に再接続処理をします。

この修正は、サーバのラウンドトリップを増やしません。代わりに、TCPレイヤでソケット状態を確認するので、速く効果的です。しかし、この修正は再接続処理の代わりになるわけではありません。特にSQL Azureに接続する場合、再接続処理の実装は、まだ必要なプラクティスとして推奨します。この改善により、SQL ServerとSQL Azureへの接続時に、節奥に失敗する機会を減らしました。

導入背景

SQL Azureに接続した時に、よく遭遇するエラーの一つが、「A transport-level error has occurred when sending the request to the server. (provider: TCP Provider, error: 0 – An established connection was aborted by the software in your host machine.)」です。このエラーは、SqlClientがプールから無効なコネクションを取得したときに発生し、アプリケーションに返されます。。プール上のコネクションは、ネットワークやSQL Azureで制限されて無効化されます。結果的に、たとえば実行コマンドなどでSqlException例外が発生します。

以下のようなコードを検討しましょう。

try

{

    // Let’s assume the connection string uses default connection pool set to true

    // and the connection pool was already previously created for this same

    // connection string

    using (SqlConnection connection = new SqlConnection("…"))

    {

        // If the connection pool in not empty,

        // even if the connection returned above is dead,

        // the SqlConnection.Open command below executes succesfully.

        connection.Open();

 

        SqlCommand command = new SqlCommand("select product_name from products");

        command.Connection = connection;

        command.CommandTimeout = 3;

 

        // The Sqlexception gets thrown here,

        // when it tries to send the command to SQL Server.

        SqlDataReader reader = command.ExecuteReader();

 

        while (reader.Read())

        {

            …

        }

    }

}

catch (SqlException ex)

{

    MessageBox.Show(ex.Message);

}

この例では、Openメソッドがいつでも成功します。アプリケーションからSQL Azureに接続する旅に、再接続処理を追加しています。

情報源

MSDNのBlogに掲載されたMinimizing Connection Pool errors in SQL Azureをざっくり意訳した投稿です。