2015-09-27 8 views
5

Wir verfügen über einen C# WCF-Webdienst, der auf Windows 2008 SP2/IIS 7 gehostet wird und auf eine Oracle-Datenbank zugreift. Normalerweise Datenzugriff funktioniert gut, aber während des Belastungstests, ist es oft mal aus und Protokolle und Ausnahme sagen:Oracle Data Provider für .NET: Zeitüberschreitung der Verbindungsanforderung

Error occurred when processing XXXXXXXX Web Service 
Oracle.DataAccess.Client.OracleException Connection request timed out at Oracle.DataAccess.Client.OracleException.HandleErrorHelper(Int32 errCode, OracleConnection conn, IntPtr opsErrCtx, OpoSqlValCtx* pOpoSqlValCtx, Object src, String procedure, Boolean bCheck) 
    at Oracle.DataAccess.Client.OracleException.HandleError(Int32 errCode, OracleConnection conn, IntPtr opsErrCtx, Object src) 
    at Oracle.DataAccess.Client.OracleConnection.Open() 
    at MyWorkspace.WorkForceDataAccess.CheckStaffIdInRSW() 
    at MyWorkspace.MyClass.MyFunction(MyDataType MyData) 

die Datenbank abzufragen, verwenden wir so etwas wie dieses:

OracleConnection orConn = new OracleConnection(); 
orConn.ConnectionString = "user id=xxx; password=xxx; Connection Timeout=600; Max Pool Size=150; data source= (DESCRIPTION =(ADDRESS = (PROTOCOL = TCP)(HOST = MYHOST.MYDOMAIN.com)(PORT = 1771)) (CONNECT_DATA =(SERVER = DEDICATED)(SERVICE_NAME = MYSERVICE.MYDOMAIN.com)))"; 
orConn.Open(); 

using (var cmd = new OracleCommand("MY_UTIL.check_StaffIdInRSW", orConn) { CommandType = CommandType.StoredProcedure }) 
{ 
    cmd.Parameters.Add("P_Staff_Id", OracleDbType.Int32); 
    cmd.Parameters["P_Staff_Id"].Direction = ParameterDirection.Input; 
    cmd.Parameters["P_Staff_Id"].Value = Convert.ToInt32(MyDataObject.StaffId); 

    cmd.Parameters.Add("P_retvalue", OracleDbType.Int32); 
    cmd.Parameters["P_retvalue"].Direction = ParameterDirection.Output; 

    cmd.ExecuteNonQuery(); // Execute the function 

    //obtain result 
    returnVal = int.Parse(cmd.Parameters["P_retvalue"].Value.ToString()); 
} 

Ich bin ziemlich zuversichtlich, dass Die gespeicherte Prozedur, die aufgerufen wird, benötigt nicht die ganze Zeit. Es ist eine ziemlich einfache Prozedur, die schnell überprüft, ob die P_Staff_Id in der Tabelle existiert und das Ergebnis zurückgibt.

Zusätzlich tritt dies nur während Belastungstests auf. Während des normalen Betriebs sind die Dinge in Ordnung, aber während schwerer Lasten mit 1 Nachricht pro Sekunde tritt dies auf, nachdem es einige Zeit lang flüssig gelaufen ist.

Als Abhilfe können, ich habe hinzugefügt „Connection Timeout = 600; Max Pool Size = 150“ an die Verbindungszeichenfolge, aber das beheben das Problem nicht

Wir haben die gleiche Anwendung auf einem Entwicklungs-Server ausgeführt wird. und es funktioniert gut. Wir haben dieses Problem nie begegnet.

Irgendwelche Vorschläge, was würde geschätzt, um zu versuchen. es sieht aus wie ich laufe aus Optionen.

+0

Die Stacktrace lassen vermuten, dass das Verfahren nicht das Problem. Die Ausnahme wird vor ihrer Ausführung in Connection.Open ausgelöst. Es sieht daher so aus, als ob der Datenbankcomputer überlastet ist, sodass er nicht innerhalb von Zeitüberschreitungen auf den Client antworten kann. Es sollte nicht mit der Poolgröße oder den Prozesseinschränkungen in Oracle in Verbindung stehen, da diese unterschiedliche Ausnahmen auslösen. Auch würde ich über diese Poolgröße misstrauisch sein, weil es keinen Sinn macht, einen Pool zu haben, der wesentlich größer ist als die Anzahl der Kerne, die die Datenbank verwenden kann. Oder du hast irgendwo einen Verbindungsleck. – Husqvik

+0

Ich habe die Connection Timeout und Max Pool Size zu der Verbindungszeichenfolge hinzugefügt, nachdem dieses Problem aufgetreten ist - aber es hat nicht geholfen. Der Webservice funktionierte ohne diese in der DEV-Umgebung einwandfrei. Würden Sie vorschlagen, das OracleConnection-Objekt nach dem Verbindungsleck explizit zu schließen und zu entfernen, nachdem es verwendet wurde? – DjD

+0

Anzeigenverbindungsverlust - Wenn das Verbindungsobjekt innerhalb einer einzelnen Funktion nur eine kurze Lebensdauer hat, ist die Verwendung von (var connection = ...) {...} definitiv sicherer. Aber ich erwarte nicht, dass dies das Problem ist. Sie würden eine andere Ausnahme erhalten, wenn der Pool vollständig genutzt wird. Adload-Test - Ich erwarte, dass Sie viele Instanzen der Anwendung oder Funktion parallel ausführen. Erwarten Sie außerdem, dass Sie dedizierte Verbindungen und keine gemeinsam genutzten Server als Oracle-Einstellung verwenden. Können Sie überprüfen, wie die Sitzungen während des Tests in der Datenbank aussehen, um zu sehen, wie viele Sitzungen und wie viele aktive Sitzungen tatsächlich dort sind? – Husqvik

Antwort

4

Wir hatten ein ähnliches Problem, und es dauerte eine Weile, um dies zu debuggen und dies zu beheben.Unser Code auf gestresst mit vielen Eingabedateien und viele Threads Verarbeitung, jeder Threa d Verwenden von Entity-Framework und Öffnen der Oracle-Datenbankverbindung und Durchführen einer Reihe von Datenbankabfragen und -einfügungen, die gelegentlich zum Ablegen verwendet werden. Aber funktioniert die meiste Zeit.

Ich habe DbContext-Konstruktor geändert, um die OracleConnection explizit zu öffnen. Ich habe einen Code wie diesen hinzugefügt

Es verbessert, aber immer noch nicht vollständig gelöst. Ich habe den Haken vom Debugger eingebrochen und gesehen, dass viele Threads sich öffnen und nur wenige Threads verarbeiten. Bei Öffnen im Oracle-Stapel führt Oracle für seinen internen Zweck ThreadPool.QueueUserWorkItem aus und wartet auf seinen Abschluss. Ich kann oben auf Stapel seine Wartezeit sehen. Hier sind viele gepoolte Verbindungen verfügbar (Standard ist 100), ich benutze kaum 10, also ist es nicht aus Ressourcen.

Aber das Problem ist in unserem Code auch ThreadPool.QueueUserWorkItem ohne zusätzliche Drosselung verwendet. Ich fand es cool, alle Jobs, die wir tun müssen, einfach in eine Warteschlange zu stellen, und wir werden .NET dafür sorgen. Aber das hat subtile Probleme. Alle unsere Jobs haben die gesamte Anzahl an Warteschlangen verbraucht. Wenn OracleConnection eine Poolverbindung aus dem Pool abrufen möchte, wird auch eine Warteschlange für den Threadpool erstellt. Aber es wird niemals abgeschlossen werden. Unsere Jobs warten alle auf OracleConnection.Open, und sein Queued Thread-Proc befindet sich weiterhin in der Warteschlange. Letztendlich wird die Wartezeit durch Timeout beendet. Es ist schade, dass, obwohl es viele gepoolte Verbindungen gibt, wir alle ThreadPool-Proc verbraucht haben, und Oracle Threadpool hat nicht einmal eine Chance bekommen. Auch hier hilft die Einstellung von ThreadPool.SetMaxThreads nicht. Das Problem ist immer noch das gleiche. Wir speichern alle Thread-Pool-Ressourcen und Orcale wird keine finden und befindet sich weiterhin in der Warteschlange.

Der Fix ist nicht nur auf ThreadPool angewiesen, sondern wir fügen auch unsere eigene Drosselung hinzu. Ich habe BlockingCollection und Sempahores verwendet und nur eine begrenzte Anzahl gleichzeitiger Jobs in ThreadPool hinzugefügt, sagen wir 5. Auf diese Weise wird OracleConnection immer einen ThreadPool-Thread finden, der nicht verfügbar ist.

1

versuchen, am Ende connection.close() hinzufügen. Ich sehe keine Freigabe von Verbindungen in Ihrem Code und die explizite Rückgabe an den Verbindungspool. So wird die Verbindung nur dann zum Verbindungspool zurückgegeben, wenn der GC gestartet wird.

+0

Wir haben so etwas wie diese Verbindung implementiert. close(), um Verbindungen explizit zu schließen, und das schien zu funktionieren. Danke Ihnen allen für Ihre Hilfe. – DjD

1

Auch habe ich häufig mehr um dieses Problem zu bekommen, auch nach dem Einsatz von Connection.Close()

Nach einer langen Analyse ich einige Sache gelernt habe, wie unten

  1. Connection.Close erwähnt () tut die DB-Verbindung
  2. Verbindungszeit heraus tut, diese Frage bedeutet nur mit db Abfrage
  3. Verbindungszeit kann auch durch erschöpfende Verbindungen wird im Verbindungspool (die für mich den Täter war entsorgen, da sie den max erreicht imum Sitzungen der DB-Verbindung)

Fix: - Analyse dauerte lange Zeit, aber fix ist von nur 2 Minuten

using(DbConnection instance) 
{ 

} 

ZB: -

using (DbConnection objDbConnection = new DbConnection()) 
{ 
    ojDbConnection.PersistData(); 
} 

Under PersistData(); Alle db-Operationen wie Öffnen, schließen e.tc. wird

durchgeführt werden, wie wir alles weiß „Verwendung“ Kurzform von

try 
{ 

} 
catch() 
{ 

} 
Finally 
{ 
    Dispose objDbConnection; 
} 

Hoffe, es hilft, wie es mir geholfen

Verwandte Themen