2010-04-19 3 views
7

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.

+1

Hai disabilitato il buffering su tutte le tue prese? Potrebbe essere necessario pubblicare un altro codice di esempio. –

+0

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

+0

@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

risposta

0

Si attiva e quindi si interrompe per un lungo periodo di tempo (circa due minuti circa) e poi aumenta di nuovo? Se è così, potresti non avere il limite massimo di file aperti del tuo sistema abbastanza alto.

+0

I file aperti ulimit sono in 1024. Il server non supera mai le connessioni ~ 100 dead (time_wait) e mai oltre 10 (1 per processo forked) con connessioni live. Quando iniziano le connessioni bloccate, avvengono su circa 1/4 di connessioni (3 passeranno attraverso, una si bloccherà per ~ 5 secondi, fino a quando la protezione di timeout si attiva e respawn il processo). – viraptor

1

Questa probabilmente non è la soluzione al tuo problema, ma potrebbe risolvere un problema che sperimenterai in futuro: non dimenticare di chiudere() le prese quando hai finito! shutdown() disconnetterà lo stream, ma manterrà comunque un descrittore di file.

Poiché hai detto che strace mostra processi bloccati in read(), il problema sembra essere che il client non stia inviando i dati che ci si aspetta che invii. È necessario correggere il client o aggiungere un allarme() ai processi del server in modo che possano sopravvivere ai client morti.