Ho uno strano problema con un server che accetta connessioni TCP. Anche se normalmente ci sono alcuni processi in attesa, a un certo volume di connessioni si blocca.Perché il mio script del server Perl TCP si blocca con molte connessioni TCP?
Versione lunga:
Il server è scritto in Perl e si lega una presa $srv
con la bandiera riutilizzo e ascoltare == 5. In seguito, si biforca in 10 processi con un ciclo di $clt=$srv->accept(); do_processing($clt); $clt->shutdown(2);
Il cliente scritto in C è anche molto semplice - invia alcune linee, quindi riceve tutte le linee disponibili e fa un shutdown(sockfd, 2);
Non c'è nulla di asincrono in corso e alla fine entrambe le code di invio e di ricezione sono vuote (come riportato da netstat
).
Le connessioni durano solo ~ 20 ms. Tutti i client si comportano allo stesso modo, sono la stessa implementazione, ecc. Ora supponiamo che accetti le connessioni X
dal client 1 e un altro X
dal client 2. I processi continuano a segnalare che sono inattivi tutto il tempo. Se aggiungo altre connessioni X
dal client 3, improvvisamente i processi del server si bloccano appena dopo averli accettati. La prima cosa che bloccano dopo accept();
è while (<$clt>) ...
- ma non ricevono alcun dato (al primo tentativo già). All'improvviso tutti e 10 i processi sono in questo stato e non smettono di aspettare. Su strace
, i processi del server sembrano bloccarsi su read()
, il che ha senso.
Ci sono molti collegamenti nello stato TIME_WAIT
che appartengono a quel server (~ 100 quando il problema inizia a manifestare), ma questa potrebbe essere una falsa pista.
Cosa potrebbe accadere qui?
Dopo un'ulteriore analisi: si è scoperto che il cliente era in errore, non chiudendo correttamente le connessioni precedenti prima di provare il successivo. I server all'inizio dell'elenco di bilanciamento del carico sono rimaste connessioni stantie.
Hai disabilitato il buffering su tutte le tue prese? Potrebbe essere necessario pubblicare un altro codice di esempio. –
Non so cosa posso fornire qui come codice - è molto semplice. Il server funziona su righe, quindi le letture sono bufferizzate in linea e gestite con '<...>' a meno che non intenda qualcos'altro qui? Il codice C client esegue uno standard 'connect (...);' e 'write (sockfd, request, ...);' - Proverò a disabilitare il buffering qui e a riferire. – viraptor
@Eric Strom: Sono confuso ora - cosa volevi dire disabilitando il buffering? Sto usando un semplice 'write (...)' dal lato client - ovviamente c'è nagle, ma questo garantisce il trasferimento nei prossimi 0,2 secondi (più o meno). Quindi che tipo di buffering hai in mente? – viraptor