7

私の前の質問で説明したアプリケーション自体。私が使用するDAL側で

Oracle.ManagedDataAccess, Version=4.121.1.0, Culture=neutral, PublicKeyToken=89b483f429c47342

接続文字列は次のとおりです。

User id=usr;Password=pwd;Data Source=database1;Validate connection=True;Connection timeout=8;Pooling=false

奇妙なことに、ODP は次の例外を発生させることがあります。

Oracle.ManagedDataAccess.Client.OracleException (0xFFFFFC18): Connection request timed out
   in OracleInternal.ConnectionPool.PoolManager`3.CreateNewPR(Int32 reqCount, Boolean bForPoolPopulation, ConnectionString csWithDiffOrNewPwd, String instanceName)
   in OracleInternal.ConnectionPool.PoolManager`3.Get(ConnectionString csWithDiffOrNewPwd, Boolean bGetForApp, String affinityInstanceName, Boolean bForceMatch)
   in OracleInternal.ConnectionPool.OraclePoolManager.Get(ConnectionString csWithNewPassword, Boolean bGetForApp, String affinityInstanceName, Boolean bForceMatch)
   in OracleInternal.ConnectionPool.OracleConnectionDispenser`3.Get(ConnectionString cs, PM conPM, ConnectionString pmCS, SecureString securedPassword, SecureString securedProxyPassword)
   in Oracle.ManagedDataAccess.Client.OracleConnection.Open()
   in MySyncApp.DBRepository.GetChangedDataDB(DateTime startPeriod) in D:\MySyncApp\MySyncApp\DB.cs:line 23
   in MySyncApp.Program.<>c__DisplayClass30.<>c__DisplayClass32.<Synchronize>b__2f(ID id) in D:\MySyncApp\MySyncApp\Program.cs:line 441

しかし、この例外の後、Oracle のセッションを見ると、実際には接続が有効INACTIVEで、 !としてマークされていることがわかります。そのため、このような接続はサーバー側でハングし続け、使用可能なセッションの数を徐々に使い果たします。

私のコードには特別なことは何もありません。

public List<DataObj> GetChangedDataDB(DateTime startPeriod)
{
    List<DataObj> list = new List<DataObj>();
    using (OracleConnection conn = new OracleConnection(this._connstr))
    {
        conn.Open();

        using (OracleCommand comm = new OracleCommand("select data from table(usr.syncpackage.GetChanged(:pStart))", conn))
        {
            comm.CommandTimeout = 10;
            comm.Parameters.Add(":pStart", startPeriod);

            using (OracleDataReader reader = comm.ExecuteReader())
            {
                // ..omitted
            }
        }

    }
    return list;
}

このコードはParallel.ForEach、多数のデータベースから同時にデータを引き出すためにループで実行されます。同じデータベースへの 3 つの並列接続の場合もあります (たとえば、企業の 3 つの異なる部門から、スキーマの異なる部分からデータを引き出します)。

オラクルは

Oracle Database 11g Enterprise Edition リリース 11.2.0.3.0 - 64 ビット製品

同期プロセス自体は、10 秒間隔でタイマーで起動します。すでに実行中のタスクがある場合、次のタスクは停止されています。

    public static void Synchronize(object obj)
    {            
        // ... omitted
        log.Info("ITERATION_COMMON_START");

        if (Program.State == "Running")
        {
            log.Info("ITERATION_COMMON_END_BY_EXISTING");
            return;
        }

        lock (Program.StateLock)
        {
            Program.State = "Running";
        }                   

        Parallel.ForEach(Global.config.dbs, new ParallelOptions { MaxDegreeOfParallelism = -1 }, (l) =>
        {
            Console.WriteLine("Started synchronization for {0}", l.key);
            DBRepository db = new DBRepository(l.connectionString);

            Parallel.ForEach(l.departments, new ParallelOptions { MaxDegreeOfParallelism = -1 }, (department) =>
            {                       
                DateTime ChangesFromTS = GetPreviousIterationTS;
                List<DataObj> cdata = db.GetChangedDataDB(ChangesFromTS);
                // ... doing the work here
            }

        }

        // Finishing work

        GC.Collect();            

        lock (Program.StateLock)
        {
            Program.State = "";
        }

    }

同期タスクを定期的に呼び出すためのタイマーは次のとおりです。

Program.getModifiedDataTimer = new Timer(Program.Synchronize, null, (int)Global.config.syncModifiedInterval * 1000, (int)Global.config.syncModifiedInterval * 1000);

Global.config.syncModifiedInterval秒単位です

プーリングをオンにすると、ODP は同じように動作します。Max pool size同じ例外で、接続文字列のディレクティブで許可されているよりも多くの接続が作成されました。

その点について、あなたの考えや経験を教えてください。


アップデート

例外が発生したときの Oracle トレースの一部を次に示します。

(PUB) (ERR) OracleConnection.Open() (txnid=n/a) Oracle.ManagedDataAccess.Client.OracleException (0xFFFFFC18): Connection request timed out
   in OracleInternal.ConnectionPool.PoolManager`3.CreateNewPR(Int32 reqCount, Boolean bForPoolPopulation, ConnectionString csWithDiffOrNewPwd, String instanceName)
   in OracleInternal.ConnectionPool.PoolManager`3.Get(ConnectionString csWithDiffOrNewPwd, Boolean bGetForApp, String affinityInstanceName, Boolean bForceMatch)
   in OracleInternal.ConnectionPool.OraclePoolManager.Get(ConnectionString csWithNewPassword, Boolean bGetForApp, String affinityInstanceName, Boolean bForceMatch)
   in OracleInternal.ConnectionPool.OracleConnectionDispenser`3.Get(ConnectionString cs, PM conPM, ConnectionString pmCS, SecureString securedPassword, SecureString securedProxyPassword)
   in Oracle.ManagedDataAccess.Client.OracleConnection.Open()

更新 #2

Oracle接続を確立するためのリクエストが送信されたが、その応答が無視されたように、ラグ接続のためにこの接続が表示されるようです。または、サーバーとの間で送受信されるデータが宛先に送信される間に破損しています。

アプリケーションをシャットダウンしても、接続がサーバーのセッション リストでハングし続けます。セッションを強制終了すると、「KILLED」ラベルの付いたリストにぶら下がったままになります。


更新 #3

これは、同じ問題を起こすデモアプリケーションです。前述したように、接続不良で表示されますが、WANemエミュレーターを使用してそのような接続をシミュレートすることができます。これは、データベース接続に使用するのと同じコンポーネントです。あなたの助けを願っています。

4

3 に答える 3

2

F# コードでも同じ問題が発生しました。同時に多くの接続を生成し、タスク並列ライブラリを使用しません。に同意します。問題はflindebergMotomoto PinkOracle からの接続確認応答が接続要求タイムアウト例外の後に来ることであるというあなた自身の結論に同意します。

他の人として、接続要求のタイムアウトを増やすことをお勧めします。ただし、さらに、接続Min Pool Sizeを開く並列生成スレッドの数にパラメーターを設定して接続プールを使用することを検討できます。部門の数が多い場合、接続プールを使用すると、クライアント側とサーバー側の両方でパフォーマンスが大幅に向上する可能性があります。

于 2014-02-06T07:16:47.783 に答える
0

コマンドのタイムアウトを増やしてみましたか (メソッド GetChangedDataDB のコード行)? このようなもの

 comm.CommandTimeout = 360;

私は巨大なデータを管理するプロジェクトを作成しましたが、あなたのようにエラー メッセージも表示されたので、CommandTimeout 値をどんどん追加すると機能しますが、あなたが私と同じケースに遭遇したかどうかはわかりません。

逆に、Parallel.ForEach スコープに Parallel.ForEach スコープがあることがわかりました。Task Parallel Libraryを使用して 2 番目のスコープを変更してみてください。ここで詳細を学ぶことができますhttp://msdn.microsoft.com/en-us/library/dd537609.aspx

次に、2番目の Parallel.ForEach スコープは次のようになります

Task task = new Task(() =>
Parallel.ForEach(l.departments, new ParallelOptions { MaxDegreeOfParallelism = -1 }, (department) =>
{
    // Now local to the executing thread.
    DBRepository db = new DBRepository(l.connectionString);

    DateTime ChangesFromTS = GetPreviousIterationTS;
    List<DataObj> cdata = db.GetChangedDataDB(ChangesFromTS);
    // ... doing the work here
}
)); //close lambda expression

task.Start();
于 2013-11-10T04:44:20.853 に答える