SQL Server - Possibili cause del "General Network Error"

In questo post vorrei parlare di alcuni scenari tipici in cui un’applicazione riceve l’errore “General Network Error”. Ciascuna delle cause rappresenta uno scenario piuttosto complesso, vorrei riassumere i punti chiave per ogni scenario:

  • Come?
  • Quando?
  • Come risolvere?

e fornirvi i link degli articoli dove potete trovare maggiori dettagli o spiegazioni.

Le cause descritte sotto sono solo una parte delle cause che potrebbero provocare "General Network Error", ho cercato di specificare le più comuni.

Sintomi

Consideriamo uno scenario come il seguente:

  • Un’applicazione si connette ad una database di SQL remota. L'applicazione potrebbe essere di diversi tipi: desktop, web.

  • Quando l'applicazione si connette a SQL Server, randomicamente si verifica uno dei seguenti messaggi d’errore:

    System.Data.SqlClient.SqlException: A transport-level error has occurred when sending the request to the server. (provider: TCP Provider, error: 0 - An existing connection was forcibly closed by the remote host.)

    ERROR [08S01] [Microsoft][SQL Native Client]Communication link failure

    [Microsoft][ODBC SQL Server Driver][DBNETLIB] General Network error. Check your network documentation

Primi controlli

  • Prima bisogna capire se l’errore è collegato all’applicazione, oppure è un problema generale di comunicazione tra i server. Per determinare questo si può provare ad aprire una connessione dal server dove gira l'applicazione allo stesso database di SQL Server nel momento in qui si verifica il problema usando un altro client, per esempio un file udl (http://support.microsoft.com/kb/244659). Per avere una buona prova bisogna fare un test della connessione immediatamente quando l'errore si presenta in applicazione. A volte è molte difficile prevedere quando succede l'errore, ma in alcuni casi potrebbe essere fattibile. Se, per esempio, tutte le connessioni dell'applicazione falliscono con "General Network Error" e allo stesso tempo tutti i test da un file udl si completano con successo bisogna cominciare le verifiche dalla review dell'applicazione.
  • Hardware di rete
    • Se ci sono firewall, verificate se le impostazioni di timeout sono configurate correttamente. Il problema della connettività potrebbe succedere quando scatta un Timeout di firewall prima che il client e SQL hanno completato l’attività sulla connessione.
    • Se usate teaming adapter fate una prova disattivandolo e verificate se il problema si presenta lo stesso. (Teaming significa che tutte le schede di rete sono tenute insieme e appaiono come un IP / indirizzo fisico)
    • Sarebbe anche utile fare le seguente prove e verificare se il problema si presenta lo stesso o no:
      • Disattivare teaming adapters della rete.
      • Escludere routers o firewalls, se è possibile, semplificate il percorso tra il client e il server.
      • Spostare il server e il client sulla stessa subnet.
      • Verificare se i drivers della scheda di rete sono aggiornati.

Possibili cause

Scalable Networking Pack (SNP) è abilitato e incompatibile con l’hardware di rete

Scalable Networking Pack include il supporto per le seguente funzionalità:

  • TCP Chimney Offload,
  • Receive-Side Scaling
  • NetDMA

Scalable Networking Pack(SNP) è incluso nel Service Pack 2 di Windows Server 2003 e come un pacchetto stand-alone.

  • Come verificare il problema:
    • SQL Server è installato sul  Windows Server 2003 dove SNP è abilitato
    • Applicazione si connette a questo SQL Server remoto tramite protocollo TCP/IP
    • In modo randomico nell’applicazione si verifica un problema descritto nella sezione Sintomi sopra riportata
    • Il problema si verifica solo quando la connessione è aperta tramite il protocollo TCP/IP
  • Come confermare il problema:
    • Se l’applicazione esplicitamente si connette a SQL Server usando il protocollo Named Pipes il problema non si verifica. Per esempio, nella stringa della connessione il nome del server viene specificato come np:ServerName forzando il protocollo Named Pipes.
    • Potete prendere le trace di rete simultanee dal server dell'applicazione e dal server di database. Dovete vedere un pacchetto con RESET nell'entrambe trace. Ma nella trace di database si vede che RESET è inviato dal client invece nel trace di client si vede che RESET è inviato dal server di database. Lo scenario è molto simile allo scenario descritto nel punto 2 “Firewall or router interrompe le connessioni”, dove potete vedere anche un esempio dei pacchetti
  • Come risolvere il problema:
    • Disabilitate manualmente le funzionalità di SNP come è descritto nell’articolo http://support.microsoft.com/kb/948496 (Metodo 3). Se dopo la disattivazione delle funzionalità di SNP il problema si verifica ancora, la causa del problema è diverso; cancellate le modifiche, fatte per disabilitare SNP.

Firewall o Router interrompe le connessioni

  • Come verificare il problema:
    • Intermittente
    • Può essere causato da malfunzionamenti hardware o impostazioni che possono interrompere i pacchetti.
  • Come confermare il problema:
    • Create una trace di rete simultanea sul computer client e sul server del database quando si verifica il problema ( si può utilizzare Microsoft Network Monitor 3.2 per catturare le trace) contrassegnando esattamente il momento in cui si verifica l’errore.
    • Poi analizzate le conversazioni nelle trace del client e del server nel momento dell’errore. Le conversazioni dovrebbero essere simili alle seguenti (SQL Server ascolta sulla porta TCP 1433, l'applicazione – sulla porta 1556):
      1. Il client invia una query:
        1032 08:36:10.322 CISCO 07AC01 TCP Control Bits: .AP..., len: 220, seq:2924440638-2924440858, ack:3256828393, src: 1556 dst: 1433 select * from dbo.test_table
      2. SQL server risponde con data:
        1079 08:36:10.489 CISCO 07AC01 TCP Control Bits: .AP..., len: 136, seq:3256828393-3256828529, ack:2924440858, src: 1433 dst: 1556
      3. Il client conferma:
        1034 08:36:10.540 CISCO 07AC01 TCP Control Bits: .A...., len: 0, seq:2924440858-2924440858, ack:3256828529, src: 1556 dst: 1433
      4. Il server di database conferma.
      5. Alcuni secondi dopo, un AckReset si vede nella trace del server di database, ma questo AckReset non è mai uscito dal client:
        1081 08:36:17.317TCP Control Bits: .A.R.., len: 0, seq:2924440858-2924440858, ack:3256828529, src: 1556 dst: 1433
      6. Qui è dove le cose vanno storte. Dal lato client non vediamo nessuna indicazione che questo pacchetto è stato inviato dal client. In realtà, il client sta preparando ad inviare a distanza di circa 10 – 15 secondi di nuovo la stessa query. Il collegamento è già stato interrotto, per questo non riesce ad inviarlo e riceve l’errore della connettività. Per qualche motivo il Reset è stato inviato da  un hardware tra il client e il server di database.
  • Come risolvere il problema:
    • Procedete con la verifica dello stato di rete con la revisione delle impostazioni hardware di rete tra il client e il server di database.

Applicazione non usa connection pooling e apre le connessioni tramite protocollo TCP/IP

Le tre cause seguenti sono molto simili e per questo suggerisco di rivederle insieme.

1 - Le porte anonime si esauriscono sul client

Le porte anonime sono utilizzate dal lato client al livello di protocollo dell’applicazione. Queste porte sono assegnate dinamicamente. In Windows 2003 le porte sono assegnate nell’intervallo 1024 – 5000.

  • Come verificare il problema:
    • L'applicazione apre la connessione al database di SQL Server utilizzando il provider che permette di disattivare il connection pooling, per esempio, SQL Server OLEDB provider or System.Data.SqlClient provider.
    • Se l'applicazione si connette al database di SQL Server utilizzando il protocollo TCP / IP, connection pooling è disattivato e l'applicazione apre e chiude le connessioni molto spesso, lo stress sulla sottostante libreria di rete SQL Server può essere aumentato e come risultato la connessione potrebbe essere interrotta con l’errore "General Network Error".
    • Ogni volta quando si apre e si chiude un socket tramite una libreria di rete di SQL sul lato client, il socket entra in stato TIME_WAIT per quattro minuti. Se si aprono e si chiudono rapidamente i 4000 sockets in meno di quattro minuti, si raggiunge la massima impostazione di default per le porte anonime, e i nuovi tentativi di aprire una nuova connessione falliranno fino a quando il set esistente delle socket in TIME_WAIT non va in timeout.
  • Come confermare il problema:
    • Appena si verifica l’errore “General network error” dovete aprire la riga del comando ed eseguire il commando sotto riportato.
      netstat -ano
    • Analizzate il risultato. Dovete vedere circa 4000 connessioni nello stato TIME_WAIT verso l’indirizzo IP del computer, dove gira SQL Server.

      Protocol

      Local Address

      Foreign Address

      State

      PID

      TCP

      web:3098

      sql:ms-sql-s

      TIME_WAIT

      1520

      TCP

      web:3100

      sql:ms-sql-s

      TIME_WAIT

      2256

      TCP

      web:3110

      sql:ms-sql-s

      TIME_WAIT

      1140

      TCP

      web:3111

      sql:ms-sql-s

      TIME_WAIT

      1096

      TCP

      web:3115

      sql:ms-sql-s

      TIME_WAIT

      2292

      TCP

      web:3118

      sql:ms-sql-s

      TIME_WAIT

      2456

    • Potete confrontare il risultato dello strumento TCPView (http://technet.microsoft.com/it-it/sysinternals/bb897437(en-us).aspx) al risultato ottenuto dalla query sulla tabella sysprocesses in SQL Server.
      • Nel momento, in cui si presenta il problema, eseguite il comando in SQL Server.
        SELECT * FROM sysprocesses
      • Lanciate lo strumento TCPView e confrontate il risultato con il risultato ottenuto nel passo precedente.
      • Per esempio, se vedete che ci sono 1000 porte aperte per connettersi al SQL server, ma SQL Server dimostra solo 100 connessioni in sysprocesses, questo potrebbe indicare che molte porte TCP sono nello stato inattivo (per impostazione predefinita si aspetta 4 minuti prima di essere chiuso) e questo può impedire ai nuovi clienti di ottenere una porta dal sistema operativo.
  • Come risolvere il problema:
    • Se pooling è abilitato, non dovete aggiustare l’impostazione dei parametri MaxUserPort and TcpTimedWaitDelay.
    • Altrimenti regolate le impostazioni di MaxUserPort e TcpTimedWaitDelay sul computer client dove gira l'applicazione. Per esempio, su un Internet Information Services (IIS) in cui un server web si connette a un computer remoto di SQL Server database utilizzando il protocollo TCP / IP con pooling disabilitato.
      • HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters:
        Value Name: MaxUserPort
        Data Type: REG_DWORD
        Valid Range: 5000 – 65534(decimal)
        Default: 0x1388 (5000 decimal)
      • HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters:
        Value Name: TcpTimedWaitDelay
        Data Type: REG_DWORD
        Valid Range: 30 – 300(decimal)
        Default: 0xF0 (240 decimal)
  • Ulteriori informazioni e articoli:
2 – L’Applicazione apre connessioni multiple non in pool
  • Come verificare il problema:
    • L’applicazione non usa pooling. Il problema è molto simile al problema descritto nel punto 4 “Esaurimento delle porte anonime sul client”.
    • Potete determinare se questa è la causa del problema usando gli approcci descritti nel punto 4.
    • La differenza è che il codice dell’applicazione è scritto in maniera tale che può produrre gli scenari quando si creano le connessioni aggiuntive.
  • Come risolvere il problema:
    • Bisogna revisionare il codice dell’applicazione e risolvere il problema cambiando l’implementazione in modo tale che non si generano le connessioni aggiuntive non in pool
    • Usate il pooling e ricuperate il risultato della query iniziale prima di eseguire una seconda query.
    • Una connessione aggiuntiva verrà generata quando:
      • Viene utilizzata una connessione che è in attesa di un risultato da un cursore ‘firehose’
      • Viene utilizzata una connessione che ha una operazione asincrona in corso.
  • Ulteriori informazioni e articoli:
3 - Si supera l’impostazione predefinita di WINSOCKLISTENBACKLOG nel computer con SQL Server
  • Come verificare il problema:
    • L’impostazione backlog è la massima lunghezza della coda di connessioni in attesa per listener. I sintomi sono molto simili allo scenario con le porte anonime e il codice dove si aprono multiple connessioni non in pool.
    • Bisogna tener conto che solo in rarissimi casi, potrebbe essere necessario modificare questa impostazione, anche se pooling è attivato sul computer client. Per esempio, se molti computer client comunicano con un computer singolo dove gira SQL server, un gran numero di tentativi di connessioni simultanee in entrata possono verificarsi in qualsiasi momento anche se pooling è abilitato.
  • Come confermare il problema:
    • Per determinare se si presenta questo problema potete catturare una trace di rete sul computer del client oppure sul computer dove gira SQL Server e verificare le richieste di connessione che sono immediatamente respinte con ACK+RESET
    • Esaminando i pacchetti TCP/IP nella trace di rete è possibile vedere un pacchetto come il seguente quando il problema si è verificato.
    • Nell’esempio sotto riportato SQL Server ascolta sulla porta 1433.
      • Frame:
        + Ethernet: Etype = Internet IP (IPv4)
        + Ipv4: Next Protocol = TCP, Packet ID = 17897, Total IP Length = 40
        + Tcp: Flags=....A..R., SrcPort=1433, DstPort=4046, Len=0, Seq=0-0, Ack=2305526653, Win=0
  • Come risolvere il problema:
    • Revisionate il codice e usate il pool delle connessioni.
    • Se questo non risolve il problema e avete verificato che le connessioni vanno in pool, in questo caso potete provare ad aumentare la dimensione della coda backlog. In questo caso sarà aumentato il numero delle richieste delle connessioni socket in attesa che il livello socket di TCP/IP mette in coda.
  • Ulteriori informazioni e articoli:

Uso improprio delle connessioni SqlConnection in codice gestito.

  • Come verificare il problema:
    • Quando gli oggetti SqlConnection non sono gestiti correttamente nel codice dell’applicazione, questo potrebbe portare alla situazione in cui i 2 thread possono tentare di utilizzare contemporaneamente lo stesso oggetto SqlConnection, In questo caso l’invio dei TDS invalidi a SQL Server fa scattare l’errore 17805 provocando SQL Server di chiudere la connessione bruscamente.
  • Come risolvere il problema:
    • Bisogna assicurarsi che le connessioni SqlClient siano chiuse correttamente. Se ci sono i DataReaders restituiti, dovrebbe essere usata la modalità  CommandBehavior.CloseConnection alla creazione di DataReader
    • Non bisogna mai chiamare Close() or Dispose() dell’oggetto di SqlClient nel metodo Finalize di una classe.
    • Non usate un oggetto SqlConnection statico e sempre utilizzate gli oggetti di SqlConnection con scopo locale al metodo dove vengono usati. In questo modo potete garantire che non ci sono i 2 thread che utilizzano una connessione di SqlConnetion allo stesso tempo.
    • "Invalid Buffer Received from Client” error message in SQL Server log when you use SQL Server .NET provider classes
      • Questo articolo parla di una specifica causa dell’errore 17805. In generale, l'errore può verificarsi in qualsiasi scenario che potrebbe consentire il simultaneo accesso multi - threaded ad un oggetto SqlConnection. In quasi tutti i casi in cui si verifica l’errore 17805 in modo casuale, si consiglia un cambiamento nel codice e l’utilizzo degli oggetti SqlConnection che sono locali a un metodo, in modo tale da garantire che gli oggetti SqlConnection non possono essere accessibile da più di un thread.
  • Ulteriori informazioni e articoli:

Applicazione client usa SqlClient con crittografia SSL (.NET Framework 1.0 / 1.1)

Descrizione dettagliata di questo problema, si può trovare nell’articolo sotto riportato:

KB 821289
FIX: "General Network Error" when you use SqlClient with SSL encryption
http://support.microsoft.com/kb/821289

  • Come verificare il problema:
    • Applicazione è basata su .Net Framework 1.0 o .Net Framework 1.1
    • Secure Socket Layer (SSL) si usa con Microsoft SQL Server 2000. Se SQL Server trova sul computer locale un certificato valido che è stato rilasciato sul FQDN ( Fully- Qualified-Domain-Name) e l’applicazione usa SqlClient, si può verificare  l’errore “General Network Error”.
    • Quando il problema si verifica viene visualizzato il seguente call stack:
      • exception in TraceLogProcess:General network error.  Check your network documentation.:  
        at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, TdsParserState state)  at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, TdsParserState state)
        at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning()
        at System.Data.SqlClient.TdsParser.ReadNetlib(Int32 bytesExpected)
        at System.Data.SqlClient.TdsParser.ReadBuffer()
        at System.Data.SqlClient.TdsParser.ReadByteArray(Byte[] buff, Int32 offset, Int32 len)
        at System.Data.SqlClient.TdsParser.ReadSqlValue(_SqlMetaData md, Int32 length)
        at System.Data.SqlClient.TdsParser.ProcessRow(_SqlMetaData[] columns, Object[] buffer, Int32[] map, Boolean useSQLTypes)
        at System.Data.SqlClient.SqlDataReader.PrepareSQLRecord(Int32 i)
        at System.Data.SqlClient.SqlDataReader.GetSqlInt32(Int32 i)
        at System.Data.SqlClient.SqlDataReader.GetInt32(Int32 i
  • Come risolvere il problema:

SqlCommand.CommandTimeout è impostato a 0 (.NET Framework 1.0/ 1.1)

  • Come verificare il problema:
    • Se la proprietà di SqlCommand.CommandTimeout è impostata a 0 (cioè infinito) e una risposta da parte di SQL è divisa in più di un pacchetto di rete, la connessione può essere chiusa incorrettamente e come conseguenza si verifica l’errore “General Network Error”
    • Questo problema può apparire come un problema intermittente, a seconda di come spesso l’applicazione riceve le risposte che sono più grandi di un pacchetto.
  • Come confermare il problema:
    • Questo problema può essere individuato in una trace di rete. Se risulta presente una query, seguita da un completo pacchetto di dati trasmessi (per default la dimensione di un pacchetto SqlClient è di 8K, anche se nella trace di rete può apparire come pacchetti multipli con la dimensione totale di 8K ), quindi dopo il primo pacchetto, la connessione sembra essere chiusa correttamente con il pacchetto ACK+FIN. Dopodiché SQL Server continua l’invio dei dati che risultano in un reset TCP/IP con l’errore.
    • Comunque non dovrebbe essere necessario di catturare una trace di rete se avete già individuato che CommandTimeout è impostato a zero e potenzialmente potrebbe essere ricevuto più di un pacchetto di dati per volta.
  • Come risolvere il problema:
    • Potete evitare questo problema impostando un valore alto per CommandTimeout, per esempio, 7200 oppure installando una hotfix dall’articolo sotto riportato.

Olga Guzheva
Senior Support Engineer
Microsoft Enterprise SQL Support