0

SQLをAzureに移行しています。私たちのDALはEntityFramework4.xベースです。一時的な障害処理ブロックを使用して、SQLAzureの再試行ロジックを追加したいと考えています。

全体として、私たちは最高の80/20ルール(または95/5以上かもしれませんが、ポイントは得られます)を探しています-コードのリファクタリング/書き換えに何週間も費やすことはありません(たくさんあります)。私はDALのフレームワークを正常に再実装していますが、これは少数のケースに対処するためだけにすでにここにあるため、必要以上にDALに対して記述および生成されたコードのすべてではありません。緩和策>>>このエッジケースの排除。

ここMSDNで説明されている可能なオプションを見ると、ケース#3は実装するのに「最も速い」ものがあるようですが、一見しただけです。このソリューションについて少し考えてみると、接続を管理する(つまり、常に接続を閉じる)ためのこの回避策のEntity Frameworkの組み込みプロセスのために、接続管理に問題がある可能性があることに気付きました。「解決策」は、インスタンス化するコンテキストの100%がブロックを使用して使用することを確認することであるように思われますが、アーキテクチャでは、これは困難です。

だから私の質問:そのリンクからケース#3に行く、接続をぶら下げているのは問題ですか、それとも私が知らないどこかで起こっている魔法がありますか?

4

2 に答える 2

1

いくつかの実験を行ったところ、これにより、以前から使用していた古い「接続の管理」の状況に戻ることがわかりました。今回は、接続が少し抽象化され、今は「管理」する必要があります。コンテキスト」も同様です。

OnContextCreated次の実装があるとしましょう。

private void OnContextCreated()
{
    const int maxRetries = 4;
    const int initialDelayInMilliseconds = 100;
    const int maxDelayInMilliseconds = 5000;
    const int deltaBackoffInMilliseconds = initialDelayInMilliseconds;

    var policy = new RetryPolicy<SqlAzureTransientErrorDetectionStrategy>(maxRetries,
                                                                            TimeSpan.FromMilliseconds(initialDelayInMilliseconds),
                                                                            TimeSpan.FromMilliseconds(maxDelayInMilliseconds),
                                                                            TimeSpan.FromMilliseconds(deltaBackoffInMilliseconds));
    policy.ExecuteAction(() =>
            {
                try
                {
                    Connection.Open();
                    var storeConnection = (SqlConnection) ((EntityConnection) Connection).StoreConnection;
                    new SqlCommand("declare @i int", storeConnection).ExecuteNonQuery();
                    //Connection.Close();
                    // throw new ApplicationException("Test only");
                }
                catch (Exception e)
                {
                    Connection.Close();

                    Trace.TraceWarning("Attempted to open connection but failed: " + e.Message);

                    throw;
                }
            }
        );
}

このシナリオでは、接続を強制的に開きます(これがここでの目標でした)。このため、コンテキストは多くの呼び出しにわたってそれを開いたままにします。そのため、接続を閉じるタイミングをコンテキストに通知する必要があります。そのための主要なメカニズムは、コンテキストでDisposeメソッドを呼び出すことです。したがって、ガベージコレクションでコンテキストをクリーンアップするだけの場合は、接続を開いたままにしておくことができます。

Connection.Close()ブロック内のコメントを切り替えて、tryデータベースに対して一連の単体テストを実行することで、これをテストしました。を呼び出さずCloseに、(SQL Serverの観点から)最大275〜300のアクティブな接続にジャンプしました。を呼び出すことによりClose、その番号は〜12でホバリングしました。次に、コンテキストのブロックがある場合とない場合の両方で少数の単体テストを使用してusing再現し、同じ結果を再現しました(異なる数値-それらが何であったかを忘れています)。

次のクエリを使用して接続をカウントしていました。

SELECT s.session_id, s.login_name, e.connection_id,
      s.last_request_end_time, s.cpu_time, 
      e.connect_time
FROM sys.dm_exec_sessions AS s
INNER JOIN sys.dm_exec_connections AS e
ON s.session_id = e.session_id
WHERE login_name='myuser'
ORDER BY s.login_name

結論:Connection.Open()この回避策を呼び出して一時的な障害処理ブロックを有効にする場合は、使用するすべてのコンテキストにusingブロックを使用する必要があります。そうしないと、問題が発生します(SQL Azureでは、データベースが「スロットル」される原因になります)。そして最終的には何時間もオフラインになります!)。

于 2013-01-18T14:26:48.340 に答える
1

このアプローチの問題は、接続の再試行のみを処理し、コマンドの再試行は処理しないことです。

Entity Framework 6(現在はアルファ版)を使用している場合は、Azure SQL Databaseを使用した一時的な再試行の新しい組み込みサポートがあります(少し構成が必要です):http ://entityframework.codeplex.com/wikipage?title = Connection%20Resiliency%20Spec

すべてのデータベース呼び出しを変更することなく、FaultHandlingブロックを使用して再試行するようにEntityFrameworkを構成できるライブラリを作成しました。通常は、構成ファイルと場合によっては1行または2行のコードを変更するだけで済みます。

これにより、EntityFrameworkまたはLinqToSqlに使用できます。

https://github.com/robdmoore/ReliableDbProvider

于 2013-06-17T16:37:36.550 に答える