/ / Gestione della connettività del database con ADO.NET - .net, ado.net, timeout

Gestione della connettività del database con ADO.NET - .net, ado.net, timeout

Abbiamo un'applicazione che si basa su ADO.NET. Seguiamo alcune semplici best practice che ci consentono di utilizzare il pool di connessioni. Ad esempio, un blocco di codice che utilizza un database potrebbe essere simile al seguente:

using( DbConnection dbConnection = GetDatabaseConnection() ) {
doWork();
}

FWIW, non c'è niente di speciale in GetDatabaseConnection. Stabilisce una connessione con il database che esegue MSSQL Server 2000. In effetti, si legge come segue:

DbConnection GetDatabaseConnection() {
return GetConnection(MyConnectionString);
}

DbConnection GetConnection(String connectionString)
{
try {
SqlConnection dbConnection = new SqlConnection(connectionString);
dbConnection.Open();
return dbConnection;
} catch( InvalidOperationException ex ) {
handleError(ex);
throw;
} catch( DbException ex ) {
handleError(ex);
}
}

Pertanto, i nostri collegamenti vengono eliminati presso ilfine dell'ambito del blocco. Tuttavia, ci siamo imbattuti in un piccolo problema tecnico mentre abbiamo iniziato a testare l'applicazione. Abbiamo scoperto che la nostra applicazione è molto complessa, il che significa che a volte diventa molto loquace e poi rimane in silenzio per un po '. Il risultato è che possiamo avere più thread contemporaneamente tutti in arrivo per ottenere una connessione.

Quindi immagina di avere 10 discussioni. Un batch di lavoro (per favore non tentare di riformulare il batch di lavoro) arriva e viene segmentato su alcuni thread. Ogni thread quindi tenta di ottenere una connessione e un boom, mi colpisce un InvalidOperationException. "Ho regolato ConnectTimeout e tutto ciò che fa è allungare il tempo fino a quando non ho un'esplosione di eccezioni. Una volta superata la fase" wind-up ", l'applicazione va bene. Quindi si interrompe di nuovo, le connessioni" scompaiono "e il processo ricomincia.

Ho anche provato a modificare LoadBalanceTimeout, ma le eccezioni continuano a manifestarsi. Qualcuno di voi ha già visto questo problema in precedenza? Qualche idea ... ne eliminerò un paio.

  • Mantieni continuamente una connessione "calda"
  • Tentare di riaprire la connessione fino a qualche numero di tentativi
  • Implementa il mio pool di connessioni (sì, non sono interessato a reinventare la ruota)

Modificare:

La maggior parte dei forum che ho letto si sono scoraggiati ad aumentarela dimensione del pool di connessioni. Per impostazione predefinita, il pool di connessioni ha un limite superiore di 50 connessioni (che è più che sufficiente - se devo aumentarlo, qualcosa è fondamentalmente sbagliato altrove). Quello che noto è che quando ConnectTimeout è basso, si verifica InvalidOperationException. È come se lo spin-up della connessione fosse troppo lungo e le connessioni in sospeso fossero tutte in timeout.

MARS è certamente un'opzione ... Il testo di InvalidOperationException.Message è:

Timeout scaduto. Il periodo di timeout è trascorso prima di ottenere una connessione dal pool. Ciò potrebbe essersi verificato perché tutte le connessioni del pool erano in uso e la dimensione massima del pool era stata raggiunta.

risposte:

2 per risposta № 1

Da MSDN (http://msdn.microsoft.com/en-us/library/8xx3tyca.aspx):

Quando viene richiesto un oggetto SqlConnection, viene ottenuto dal pool se è disponibile una connessione utilizzabile. Per essere utilizzabile, una connessione deve essere inutilizzata, avere un contesto di transazione corrispondente o non essere associato a nessun contesto di transazionee dispone di un collegamento valido al server.

Il pool di connessioni soddisfa le richieste perconnessioni riallocando le connessioni quando vengono rilasciate nuovamente nel pool. Se è stata raggiunta la dimensione massima del pool e non è disponibile alcuna connessione utilizzabile, la richiesta viene messa in coda. Il pooler quindi tenta di recuperare tutte le connessioni fino al raggiungimento del timeout (il valore predefinito è 15 secondi). Se il pooler non è in grado di soddisfare la richiesta prima del timeout della connessione, viene generata un'eccezione.

Traduzione: Controlla i contesti delle tue transazioni ... se hai una dimensione del pool di 10 connessioni e 10 connessioni sono state create con transazioni diverse, sei fregato.

Si noti che una connessione interrotta può essere rilevata solo dopo aver tentato di comunicare con il server. Se viene rilevata una connessione che non è più connessa al server, viene contrassegnata come non valida. Le connessioni non valide vengono rimosse dal pool di connessioni solo quando vengono chiuse o recuperate.

Se esiste una connessione a un server che è scomparso, questa connessione può essere disegnata dal pool anche se il pool di connessioni non ha rilevato la connessione interrotta e contrassegnato come non valido. Questo è il caso perché il sovraccarico di verificare che la connessione sia ancora valida eliminerebbe i vantaggi di avere un pooler causando un altro round trip al server. In questo caso, il primo tentativo di utilizzare la connessione rileverà che la connessione è stata interrotta e viene generata un'eccezione.</ Em>

Traduzione: Non puoi davvero fare affidamento su una connessione da connettere? L'articolo non spiega davvero come gestirlo ...

Potresti provare a cancellare manualmente il pool di tanto in tanto usando ClearAllPools e ClearPool, ma questo suona ancora come un cerotto per me, mi fa rabbrividire.

L'articolo discute anche i contesti di sicurezza, dicendo:
Dopo che un ruolo dell'applicazione SQL Server è statoattivato chiamando la procedura memorizzata del sistema sp_setapprole, non è possibile ripristinare il contesto di sicurezza di tale connessione. Tuttavia, se il pooling è abilitato, la connessione viene restituita al pool e si verifica un errore quando la connessione in pool viene riutilizzata.

Sto iniziando a chiedermi perché uso il pool di connessioni ...

E infine:
Frammentazione del pool dovuta alla sicurezza integrata
Le connessioni vengono raggruppate in base astringa di connessione più identità utente. Pertanto, se si utilizza l'autenticazione di base o l'autenticazione di Windows sul sito Web e un accesso di sicurezza integrato, si ottiene un pool per utente. Sebbene ciò migliori le prestazioni delle successive richieste di database per un singolo utente, quell'utente non può sfruttare le connessioni effettuate da altri utenti. Risulta inoltre in almeno una connessione per utente al server di database.</ Em>

Pertanto, se si utilizza la sicurezza integrata in un'app Web, è possibile riempire il pool di connessioni se si dispone di un numero sufficiente di utenti.

Senza conoscere ulteriori dettagli sulla tua applicazione, è difficile ingrandire ciò che potrebbe farti inciampare, ma spero che questo ti dia alcune idee su dove cercare.

HTH


0 per risposta № 2

Puoi provare a impostare "Dimensione massima pool" su un valore più alto. Inoltre, potresti provare a chiamare esplicitamente "Chiudi" sulla connessione.


0 per risposta № 3

Domanda 1: Il tuo metodo GetDatabaseConnection () esegue lo spin off di un nuovo thread per generare la connessione al database e restituirlo al thread principale ... o sono più thread che tentano di accedere a questo non è il metodo ... o questo metodo è condiviso / statico? metodo che prende solo una connessione dal pool?

Domanda 2: quale marca e modello è il tuo server DB? Server SQL? Oracolo? PostgreSQL?

Domanda 3: Hai bisogno di tutto il lavoro completato su connessioni diverse, o se potesse essere fatto tutto su una sola, sarebbe sufficiente? Se SQL Server, forse MARS che consente più recordset su una singola connessione potrebbe aiutare, ma potrebbe non essere fattibile per la tua app.

Domanda 4: Qual è il dettaglio nell'eccezione restituita?

Sto solo cercando di avere un quadro chiaro di come funziona l'architettura dell'applicazione ...

(P.S. Qualcuno sa come contrassegnare una "risposta" come "non una risposta, ma una richiesta di ulteriori chiarimenti" ... vale a dire per questa "risposta")


0 per risposta № 4

Secondo MSDN, InvalidOperationException viene generato da SqlConnection.Open se non è stata specificata un'origine dati o un server o se la connessione è già aperta.

Sei sicuro di non avere chiamate a SqlConnection. Apri con il tuo metodo "doWork"?

Anche il codice nel metodo GetConnection ingoia DbException.