web-dev-qa-db-ja.com

データベース接続の問題に対処する適切な方法

データベースに接続しようとすると、以下のエラーが発生します:

SQL Serverへの接続の確立中に、ネットワーク関連またはインスタンス固有のエラーが発生しました。サーバーが見つからないか、アクセスできませんでした。インスタンス名が正しいこと、およびSQLServerがリモート接続を許可するように構成されていることを確認してください。 (プロバイダー:名前付きパイププロバイダー、エラー:40-SQL Serverへの接続を開くことができませんでした)

今度はこのエラーが発生することもあれば、発生しないこともあります。たとえば、プログラムを初めて実行すると接続が正常に開かれ、2回目に実行するとこのエラーが発生し、次の瞬間にプログラムを再度実行します。その後、エラーは発生しません。

SSMSを介して同じデータベースサーバーに接続しようとすると、正常に接続できますが、このネットワークの問題はプログラムでのみ発生します。

データベースが私の中にありません[〜#〜] local [〜#〜]。Its on Azure

ローカルデータベースでこのエラーが発生しません。

コード:

public class AddOperation
{
    public void Start()
    {
          using (var processor = new MyProcessor())
          {
              for (int i = 0; i < 2; i++)
              {
                  if(i==0)
                  {
                     var connection = new SqlConnection("Connection string 1");
                     processor.Process(connection);
                  }
                  else
                  {
                      var connection = new SqlConnection("Connection string 2");
                      processor.Process(connection);
                  }   
              }
          }
    }       
}

public class MyProcessor : IDisposable
{
    public void Process(DbConnection cn)
        {
            using (var cmd = cn.CreateCommand())
            {
                cmd.CommandText = "query";
                cmd.CommandTimeout = 1800;
                cn.Open();//Sometimes work sometimes dont
                using (var reader = cmd.ExecuteReader(CommandBehavior.CloseConnection))
                { 
                   //code
                }
            }
        }
}

だから私は2つのことと混同しています:

1)ConnectionTimeout: connectiontimeoutを増やす必要があるかどうか。これにより、異常な接続の問題が解決されますか?

2)再試行試行ポリシー:以下のような再試行接続メカニズムを実装する必要があります:

public static void OpenConnection(DbConnection cn, int maxAttempts = 1)
        {
            int attempts = 0;
            while (true)
            {
                try
                {
                    cn.Open();
                    return;
                }
                catch
                {
                    attempts++;
                    if (attempts >= maxAttempts) throw;
                }
            }
        }

上記の2つのオプションと混同しています。

誰かがこの問題に対処するためのより良い方法を私に提案できますか?

13

ご覧のとおり、 ここ AzureにインストールされているSQLServerの場合でも再試行ロジックをお勧めしますVM(IaaS)。

障害処理:アプリケーションコードには、再試行ロジックと一時的な障害処理が含まれていますか?適切な再試行ロジックと一時的な障害処理の修正をコードに含めることは、オンプレミスとクラウド(IaaSまたはPaaS)の両方での普遍的なベストプラクティスである必要があります。この特性が欠落している場合、AzureVMのAzureSQLDBとSQLServerの両方でアプリケーションの問題が発生する可能性がありますが、このシナリオでは、前者よりも後者をお勧めします。

インクリメンタルリトライロジックをお勧めします。

アプリケーションが必要とするアプリケーションブロックからオブジェクトをインスタンス化するには、2つの基本的なアプローチがあります。最初のアプローチでは、次のコードスニペットに示すように、コード内のすべてのオブジェクトを明示的にインスタンス化できます。

var retryStrategy = new Incremental(5, TimeSpan.FromSeconds(1), 
  TimeSpan.FromSeconds(2));

var retryPolicy =
  new RetryPolicy<SqlDatabaseTransientErrorDetectionStrategy>(retryStrategy);

2番目のアプローチでは、次のコードスニペットに示すように、構成データからオブジェクトをインスタンス化して構成できます。

// Load policies from the configuration file.
// SystemConfigurationSource is defined in 
// Microsoft.Practices.EnterpriseLibrary.Common.
using (var config = new SystemConfigurationSource())
{
  var settings = RetryPolicyConfigurationSettings.GetRetryPolicySettings(config);

  // Initialize the RetryPolicyFactory with a RetryManager built from the 
  // settings in the configuration file.
  RetryPolicyFactory.SetRetryManager(settings.BuildRetryManager());

  var retryPolicy = RetryPolicyFactory.GetRetryPolicy
  <SqlDatabaseTransientErrorDetectionStrategy>("Incremental Retry Strategy");   
   ... 
   // Use the policy to handle the retries of an operation.

}

詳細については、 this ドキュメントをご覧ください。

5
Alberto Morillo

新しいバージョンの.NET(4.6.1以降)を使用してから、組み込みの復元機能を利用します。

ConnectRetryCount、ConnectRetryInterval、および接続タイムアウト。

詳細については、を参照してください: https://docs.Microsoft.com/en-us/Azure/sql-database/sql-database-connectivity-issues#net-sqlconnection-parameters-for-connection-retry

3
ErikEJ

リモートサービスと通信するすべてのアプリケーションは、一時的な障害に敏感です。

他の回答で述べたように、クライアントプログラムが.NET FrameworkクラスSystem.Data.SqlClient.SqlConnectionを使用してSQLデータベースに接続する場合は、.NET 4.6.1以降(または.NET Core)を使用して、その接続を使用できるようにします。機能を再試行します。

SqlConnectionオブジェクトの接続文字列を作成するときは、次のパラメーター間で値を調整します。

ConnectRetryCount:デフォルトは1です。範囲は0〜255です。

ConnectRetryInterval:デフォルトは1秒です。範囲は1〜60です。

接続タイムアウト:デフォルトは15秒です。範囲は0〜2147483647です。

具体的には、選択した値によって、次の等式が真になるはずです。

Connection Timeout = ConnectRetryCount * ConnectionRetryInterval

ここで、オプション2に来ると、アプリにカスタム再試行ロジックがある場合、合計再試行時間が増加します。カスタム再試行ごとに、ConnectRetryCount回試行します。例えばConnectRetryCount = 3およびカスタム再試行= 5の場合、15回の試行が試行されます。それほど多くの再試行は必要ないかもしれません。

カスタム再試行と接続タイムアウトのみを検討する場合:

接続タイムアウトは通常、損失の多いネットワーク(パケット損失が高いネットワーク(セルラーまたは弱いWiFiなど)またはトラフィック負荷が高いネットワーク)が原因で発生します。それらの中から使用する最良の戦略を選択するのはあなた次第です。

以下のガイドラインは、一時的なエラーのトラブルシューティングに役立ちます。

  1. https://docs.Microsoft.com/en-us/Azure/sql-database/sql-database-connectivity-issues

  2. https://docs.Microsoft.com/en-in/Azure/architecture/best-practices/transient-faults

2
Chirag Rupani

SQLExpressまたはWorkgroupEditionを使用していますか?その場合、サーバーがビジー状態で応答できない可能性があります。

ネットワークの問題を除外するには、コマンドプロンプトからPING -t SqlServernameを実行します。すべてのpingが返されますか、それとも一部が失われますか?これは、スイッチの障害など、このエラーを引き起こす可能性のあるネットワークの中断を示している可能性があります。それらがall失われた場合(データベース接続が時々機能する場合)、pingがどこかのファイアウォールによってブロックされている可能性があります。そのブロックを見つけて一時的にブロックを解除すると、診断に役立つ場合があります。

エラーメッセージは、名前付きパイプを使用していることを示しています。名前付きパイプをわざと使用していますか?ほとんどのシナリオ(Azureデータベースを含む)では、SQLServer構成マネージャーでTCP/IPを有効にし、名前付きパイプを無効にすることをお勧めします。

Azureデータベースがどれだけ「離れている」かによっては、ルーターやファイアウォールによる遅延により、Kerberosや関連するタイミングが混乱することがあります。これを克服するには、接続文字列のポートを使用して、インスタンスを列挙するためのポート1434へのラウンドトリップを回避します。すでにFQDNを使用していると思います。例:server\instance、port

1
Richardissimo

接続が切断される可能性は完全にあります。 「分散コンピューティングの落とし穴」:)。ネットワーク接続の問題である可能性があります。いずれかの終わりである可能性があります。

私はお勧めします:(Azure上のマシンでファイアウォールが有効になっていると仮定します)

  1. サーバーにpingを実行し、損失がないかどうかを確認します。

ping(server).database.windows.net

  1. tracert
  2. telnetもあなたの友達になることができます。

上記の3つは、問題がどこにあるかを特定するのに役立ちます。

再試行ロジックは問題ないと思います。

質問に関して

タイムアウトの増加クエリに時間がかかることが確実な場合のみ。単純な挿入の場合、タイムアウトを増やす必要がある場合、問題はネットワーク接続である可能性があります。

Retry Logicすでに投稿されているように、これは利用できるフレームワークの一部であるか、作成したフレームワークで問題ないはずです。理想的には、接続性と速度に確信がある場合でも、再試行ロジックを用意することをお勧めします。念のため :)

1
r2018

Polly の使用を検討してください。

次のような単純なコードを使用できます-

RetryPolicy retryPolicy = Policy.Handle<Exception>()
            .WaitAndRetry(3, retryAttempt => 
TimeSpan.FromSeconds(retryAttempt));

var result = retryPolicy.Execute(() => someClass.DoSomething());

これにより、リクエストが最大3回再試行されます。

1
Bryan

SQLサーバーへの接続を確立するのにかかる時間には多くのステップがあるため、タイムアウトを増やす必要があります。したがって、最初に接続を確立するのに時間がかかります。接続の確立後、接続はメモリにプールされ、後続のクエリで再利用されます。

接続プールの詳細については、以下のリンクを参照してください。 https://docs.Microsoft.com/en-us/dotnet/framework/data/adonet/sql-server-connection-pooling

あなたが言ったように、このエラーは時々、そして常にではないので、それのためにいくつかのネットワークと接続性の要因があるかもしれません。 SQL接続のデフォルトのタイムアウトは15秒です。 30秒に変更すればうまくいくと思います。

1
Amit Shahani