2009-04-24 8 views
9

J'ai une application Web et un client, écrits en Java. Pour ce que ça vaut, le client et le serveur sont tous les deux sur Windows. Le client émet des requêtes GET HTTP via Apache HttpClient. Le serveur bloque pendant une minute et si aucun message n'est arrivé pour le client dans cette minute, le serveur renvoie HTTP 204 No Content. Sinon, dès qu'un message est prêt pour le client, il est renvoyé avec le corps d'un HTTP 200 OK.Qu'est-ce qui peut faire que TCP/IP abandonne les paquets sans abandonner la connexion?

Voici ce qui me laisse perplexe: pour un sous-ensemble par intermittence spécifique de clients - toujours les clients avec des connexions réseau manifestement feuilletés - le client émet une requête GET, le serveur reçoit et traite l'EEG, mais le client est assis pour toujours . En activant les journaux de débogage pour le client, je vois que HttpClient attend toujours la toute première ligne de la réponse.

Il n'y a pas d'exception lancée sur le serveur, au moins, rien n'est enregistré, pas par Tomcat, ni par ma webapp. Selon les journaux de débogage, il y a tous les signes que le serveur a répondu avec succès au client. Cependant, le client ne montre aucun signe d'avoir reçu quoi que ce soit. Le client se bloque indéfiniment dans HttpClient.executeMethod. Cela devient évident une fois la session expirée et le client prend une action qui provoque l'exécution d'un POST HTTP par un autre thread. Bien sûr, le test POST échoue car la session a expiré. Dans certains cas, heures se sont écoulées entre la session expirant et le client émettant un POST et découvrant ce fait. Pendant tout ce temps, executeMethod attend toujours la ligne de réponse HTTP.

Lorsque j'utilise WireShark pour voir ce qui se passe réellement au niveau du câblage, cette défaillance ne se produit pas. C'est-à-dire que cet échec se produira dans quelques heures pour des clients spécifiques, mais lorsque WireShark est en cours d'exécution aux deux extrémités, ces mêmes clients s'exécuteront pendant une nuit, 14 heures, sans échec.

Est-ce que quelqu'un d'autre a rencontré quelque chose comme ça? Qu'est-ce qui peut le provoquer dans le monde? Je pensais que le protocole TCP/IP garantissait la livraison des paquets même à travers les problèmes de réseau à court terme. Si je définis un SO_TIMEOUT et que j'essaye immédiatement la demande au moment de l'expiration, la nouvelle tentative réussit toujours. (Bien sûr, je commence par abort la demande expiré et libère la connexion pour m'assurer qu'une nouvelle socket sera utilisée.)

Réflexions? Des idées? Existe-t-il un paramètre TCP/IP disponible pour Java ou un paramètre de registre dans Windows qui activera des tentatives TCP/IP plus agressives sur les paquets perdus?

+0

Des sons comme l'observation changent le résultat -> Heisenbug -> quelque chose ne va pas avec le filetage. Dans ce cas, il semble que quelqu'un va trop _fast_ (je mettrais mon argent sur HttpClient) et simplement des blocages à cause de cela. Il est possible que vous ayez rencontré un bogue dans HttpClient lui-même, j'espère que d'autres pourront vous aider et vous aider à résoudre ce problème. – Esko

Répondre

8

Etes-vous absolument sûr que le serveur a envoyé avec succès la réponse aux clients qui semblent échouer? Je veux dire par là que le serveur a envoyé la réponse et que le client a répondu au serveur. Vous devriez voir ceci using wireshark du côté de serveur. Si vous êtes sûr que cela s'est produit du côté du serveur et que le client ne voit toujours rien, vous devez chercher plus loin dans la chaîne depuis le serveur. Existe-t-il des serveurs proxy/reverse proxy ou NAT impliqués?

Le transport TCP est considéré comme un protocole fiable, mais il ne garantit pas la livraison. La pile TCP/IP de votre système d'exploitation essaiera d'obtenir des paquets à l'autre extrémité en utilisant des retransmissions TCP. Vous devriez les voir dans wireshark du côté serveur si cela se produit. Si vous constatez des retransmissions TCP excessives, il s'agit généralement d'un problème d'infrastructure réseau, c'est-à-dire de matériel ou d'interfaces défectueux ou mal configurés. Les retransmissions TCP fonctionnent très bien pour les interruptions de réseau courtes, mais fonctionnent mal sur un réseau avec une interruption plus longue. En effet, la pile TCP/IP n'enverra des retransmissions qu'après l'expiration d'une temporisation. Cette minuterie double généralement après chaque retransmission infructueuse. C'est par nature pour éviter d'inonder un réseau déjà problématique avec des retransmissions. Comme vous pouvez l'imaginer, cela provoque généralement des problèmes de timeout. En fonction de la topologie de votre réseau, vous devrez peut-être placer des sondes/wireshark/tcpdump à d'autres emplacements intermédiaires du réseau. Cela prendra probablement du temps pour savoir où sont passés les paquets.

Si j'étais vous, je continuerais à surveiller avec wireshark à toutes les extrémités jusqu'à ce que le problème se reproduise. Cela sera probablement le cas. Mais, il semble que ce que vous trouverez finalement est ce que vous avez déjà mentionné - matériel floconneux. Si la fixation du matériel squameuse est hors de question, vous devrez peut-être tout simplement construire dans les délais d'attente au niveau des applications supplémentaires et pour tenter de tentatives traiter la question dans le logiciel. Il semble que vous ayez commencé à suivre ce chemin.

+0

Tout ce que je peux dire à partir du débogage en place quand il s'est produit est que mon application web croit qu'il a répondu. Je n'ai pas activé le débogage dans Tomcat (6.x) lui-même pour voir s'il croyait avoir terminé la réponse. Il n'y avait pas de plaintes dans le journal de Tomcat, ni dans le journal d'Apache HTTPD, ni dans le journal de mod_jk. Le matériel floconneux est complètement hors de mes mains ... dans certains cas, les gens traversent l'Internet public. – Eddie

+0

Il n'y a pas de substitut pour des informations difficiles. Wireshark vous dira qui parle et qui ne l'est pas. –

0

Est-ce que ces ordinateurs peuvent avoir un virus/programme malveillant installé? L'utilisation de wireshark installe winpcap (http://www.winpcap.org/) qui peut être en train de remplacer les modifications apportées par le logiciel malveillant (ou le logiciel malveillant peut simplement détecter qu'il est surveillé et ne tente rien de louche).

+0

Je n'avais pas considéré cela, mais c'est possible à distance, bien sûr. Puisque je ne vois que cela sur les clients avec une connexion réseau floconneuse, j'ai jusqu'ici supposé que le flakiness lui-même est en quelque sorte la cause. – Eddie

+1

Malware est possible à distance, mais très improbable. Allez avec ce que vous savez déjà - la desquamation. – Gary

1

Je n'ai pas vu celui-ci en soi, mais j'ai rencontré des problèmes similaires avec de grands datagrammes UDP provoquant une fragmentation IP qui conduisait à l'encombrement et finalement à l'abandon des trames Ethernet. Comme il s'agit de TCP/IP, je ne m'attendrais pas à ce que la fragmentation IP soit un problème important, car il s'agit d'un protocole basé sur les flux.

Une chose que je vais noter est que TCP ne garantit pas la livraison! Ça ne peut pas. Ce qu'il fait est garantie que si vous envoyez octet A suivi par octet B, alors vous ne recevrez jamais octet B avant d'avoir reçu octet A. Cela dit, je voudrais connecter la machine client et une machine de surveillance à un concentrateur.Exécutez Wireshark sur la machine de surveillance et vous devriez être capable de voir ce qui se passe. J'ai rencontré des problèmes liés à la gestion des espaces entre les requêtes HTTP et les tailles de blocs HTTP incorrectes. Les deux problèmes étaient dus à une pile HTTP écrite à la main, c'est donc un problème si vous utilisez une pile flaky.

2

Oublier de rincer ou de fermer la prise du côté hôte peut avoir cet effet par intermittence pour des réponses courtes en fonction du temps qui pourrait être affecté par la présence de tout mécanisme de surveillance.

Surtout si vous oubliez de fermer, le socket reste suspendu jusqu'à ce que GC le récupère et appelle finalize().

0

Si vous perdez des données, c'est probablement dû à un bogue logiciel, soit dans la bibliothèque de lecture ou d'écriture.

2

Si vous utilisez course longue GETS, vous devez dépassement de délai du côté client à deux fois le délai d'attente du serveur, que vous avez découvert.

Sur un TCP où le client envoie un message et s'attend à une réponse, si le serveur plante, et redémarre (disons pour le point des exemples) alors le client attendrait encore sur le socket pour obtenir une réponse à partir du serveur, mais le serveur n'écoute plus sur ce socket.

Le client ne retouverez la socket est fermée à l'extrémité du serveur une fois qu'il envoie plus de données sur la socket et le serveur rejette ces nouvelles données, et ferme la prise.

C'est pourquoi vous devriez avoir temporisations côté client sur demande.Mais comme votre serveur ne plante pas, si le serveur était multi-thread, et le socket thread pour ce client fermé, mais à ce moment-là (durée minutes) le client a une panne de connectivité, puis la socket fin secouant mon être perdu, et comme vous n'envoyez pas plus de données au serveur du client, votre client est de nouveau laissé en suspens. Cela se rattacherait à votre observation de connexion d'écaillage.

Questions connexes