2009-04-24 2 views
9

Ho un'applicazione web e un client, entrambi scritti in Java. Per quello che vale, il client e il server sono entrambi su Windows. Il client rilascia HTTP GET tramite Apache HttpClient. Il server blocca fino a un minuto e se non sono arrivati ​​messaggi per il client entro quel minuto, il server restituisce HTTP 204 Nessun contenuto. Altrimenti, non appena un messaggio è pronto per il client, viene restituito con il corpo di un HTTP 200 OK.Cosa può causare il blocco del pacchetto TCP/IP senza interrompere la connessione?

Ecco ciò che mi ha perplesso: intermittente per uno specifico sottoinsieme di clienti - sempre i clienti con connessioni di rete in modo dimostrabile a fiocchi - il client invia un GET, il server riceve ed elabora il GET, ma il cliente si siede per sempre . Abilitando i log di debug per il client, vedo che HttpClient è ancora in attesa della prima riga della risposta.

Non c'è nessuna eccezione lanciata sul server, almeno nulla è stato registrato da nessuna parte, non da Tomcat, non dalla mia webapp. In base ai registri di debug, è presente ogni segno che il server ha risposto correttamente al client. Tuttavia, il cliente non mostra alcun segno di aver ricevuto nulla. Il client si blocca indefinitamente in HttpClient.executeMethod. Ciò diventa ovvio dopo il timeout della sessione e il client esegue un'azione che fa in modo che un altro thread emetta un POST HTTP. Ovviamente, il POST fallisce perché la sessione è scaduta. In alcuni casi, sono trascorse le ore ore tra la sessione in scadenza e il client che ha emesso un POST e scoperto questo fatto. Per tutto questo tempo, executeMethod è ancora in attesa della linea di risposta HTTP.

Quando utilizzo WireShark per vedere cosa sta realmente accadendo a livello del filo, questo errore non si verifica. Cioè, questo errore si verificherà entro poche ore per client specifici, ma quando WireShark è in esecuzione su entrambe le estremità, questi stessi client verranno eseguiti durante la notte, 14 ore, senza errori.

Qualcun altro ha riscontrato qualcosa di simile? Cosa nel mondo può causarlo? Pensavo che il TCP/IP garantisse la consegna dei pacchetti anche attraverso i problemi di rete a breve termine. Se imposto un SO_TIMEOUT e ritento immediatamente la richiesta al timeout, il tentativo ha sempre esito positivo. (Ovviamente, per prima cosa, la richiesta di timeout è abort e rilascio la connessione per garantire che venga utilizzato un nuovo socket.)

Pensieri? Idee? C'è qualche impostazione TCP/IP disponibile per Java o un'impostazione di registro in Windows che abiliterà tentativi di TCP/IP più aggressivi sui pacchetti persi?

+0

Suoni come l'osservazione sta cambiando il risultato -> Heisenbug -> qualcosa di sbagliato con il threading. In questo caso sembra che qualcuno stia andando troppo veloce (metterei i miei soldi su HttpClient) e semplicemente deadlock per questo. È possibile che tu abbia riscontrato un bug in HttpClient, sperando che altri possano essere più utili e aiutarti a risolvere questo problema. – Esko

risposta

8

Sei assolutamente sicuro che il server abbia inviato correttamente la risposta ai client che sembrano fallire? Con questo voglio dire che il server ha inviato la risposta e il client ha risposto di nuovo al server. Dovresti vederlo usando wireshark sul lato server. Se si è certi che ciò si è verificato sul lato server e il client continua a non vedere nulla, è necessario cercare la catena dal server. Ci sono server proxy/reverse proxy o NAT coinvolti?

Il trasporto TCP è considerato un protocollo affidabile, ma non garantisce la consegna. Lo stack TCP/IP del sistema operativo tenterà piuttosto di ottenere pacchetti dall'altra parte utilizzando le ritrasmissioni TCP. Dovresti vedere questi in wireshark sul lato server se questo sta accadendo. Se si vedono ritrasmissioni TCP eccessive, di solito si tratta di un problema di infrastruttura di rete, ovvero hardware/interfacce errate o mal configurate. Le ritrasmissioni TCP funzionano in modo ottimale per brevi interruzioni di rete, ma funzionano male su una rete con un'interruzione più lunga. Questo perché lo stack TCP/IP invierà solo ritrasmissioni dopo la scadenza di un timer. Questo timer tipicamente raddoppia dopo ogni ritrasmissione non riuscita. Questo è stato progettato per evitare di inondare una rete già problematica con ritrasmissioni. Come puoi immaginare, questo di solito causa problemi di timeout di ogni tipo.

A seconda della topologia della rete, potrebbe essere necessario posizionare sonde/wireshark/tcpdump in altri punti intermedi della rete. Probabilmente ci vorrà del tempo per scoprire dove sono finiti i pacchetti.

Se fossi in te, continuerei a monitorare con wireshark su tutte le estremità fino a quando il problema non si ripresenta. Probabilmente lo farà. Ma sembra che quello che alla fine troverai sia quello che hai già menzionato: l'hardware sfatto. Se la riparazione dell'hardware instabile è fuori questione, potrebbe essere necessario semplicemente aggiungere timeout e tentativi a livello di applicazione aggiuntivi per tentare di risolvere il problema nel software. Sembra che tu abbia iniziato a percorrere questa strada.

+0

Tutto ciò che posso dire dal debug in atto quando si è verificato è che la mia app Web crede di aver risposto. Non ho abilitato alcun debug in Tomcat (6.x) per vedere se credeva di aver completato la risposta. Non ci sono stati reclami nel log di Tomcat, né il log di Apache HTTPD, né il registro di mod_jk. L'hardware instabile è completamente fuori dalle mie mani ... in alcuni casi le persone attraversano la rete pubblica. – Eddie

+0

Non c'è alcun sostituto per le informazioni rigide. Wireshark ti dirà chi sta parlando e chi no. –

0

Questi computer potrebbero avere un virus/malware installato? L'uso di wireshark installa winpcap (http://www.winpcap.org/) che potrebbe ignorare le modifiche apportate dal malware (o il malware potrebbe semplicemente rilevare che viene monitorato e non tentare nulla di pericoloso).

+0

Non ci avevo pensato, ma è possibile a distanza, ovviamente. Dal momento che vedo solo questo sui client con una connessione di rete traballante, ho finora assunto che la debolezza stessa sia in qualche modo la causa. – Eddie

+1

Il malware è remoto, ma molto improbabile. Vai con quello che già sai: sfogo. – Gary

1

Non ho visto questo di per sé, ma ho visto problemi simili con i datagrammi UDP di grandi dimensioni che causano la frammentazione IP che portano alla congestione e alla fine ha gettato frame Ethernet. Poiché questo è TCP/IP, non mi aspetto che la frammentazione IP sia un problema di grandi dimensioni in quanto si tratta di un protocollo basato sul flusso.

Una cosa che noterò è che il protocollo TCP non garantisce la consegna! Non può. Ciò che fa la garanzia è che se si invia byte A seguita da byte B, allora non riceverete mai byte B prima di aver ricevuto byte A.

Con ciò detto, collegherei la macchina client e una macchina di monitoraggio a un hub.Esegui Wireshark sul dispositivo di monitoraggio e dovresti essere in grado di vedere cosa sta succedendo. Ho incontrato problemi relativi alla gestione dello spazio bianco tra richieste HTTP e dimensioni del blocco HTTP errate. Entrambi i problemi erano dovuti a uno stack HTTP scritto a mano, quindi questo è solo un problema se si utilizza uno stack traballante.

2

Dimenticare di chiudere o chiudere lo zoccolo sul lato host può avere questo effetto in modo intermittente per brevi risposte a seconda dei tempi che potrebbero essere influenzati dalla presenza di qualsiasi meccanismo di monitoraggio.

Soprattutto dimenticare di chiudere lascerà penzolare la presa fino a quando GC si aggira per riprenderlo e chiama finalize().

0

Se si perdono dati, è molto probabile a causa di un bug del software, nella libreria di lettura o scrittura.

2

Se si utilizzano GET a esecuzione prolungata, è necessario timeout sul lato client al doppio del timeout del server, come è stato rilevato.

Su un TCP in cui il client invia un messaggio e si aspetta una risposta, se il server si blocca e si riavvia (diciamo per il punto di esempio), il client attende ancora sul socket per ottenere una risposta dal server, il server non è più in ascolto su quel socket.

Il client scopre che il socket è chiuso sul server una volta che invia più dati su quel socket e il server rifiuta questi nuovi dati e chiude il socket.

Ecco perché è necessario disporre di timeout lato client per le richieste.

Ma poiché il server non si arresta in modo anomalo, se il server era multi-thread e il socket thread per quel client è chiuso, ma in quel momento (durata minuti) il client ha un'interruzione di connettività, quindi il socket finale mi scuote essere perso, e dato che non invii più dati al server dal client, il tuo client è di nuovo sospeso. Questo si collegherebbe alla tua osservazione di connessione scrostata.