Passa al contenuto principale

La cattura del backlog TCP è un effetto che impedisce a un'applicazione server sul Stratus in ascolto sulla porta X di creare correttamente una connessione con qualsiasi client che tenti di connettersi alla porta X. Le connessioni ad altre porte, anche dagli stessi client, funzionano correttamente. La soluzione tipica consiste nello spegnere e riavviare l'applicazione server. Questo post spiegherà perché si verifica la cattura del backlog e altre soluzioni meno drastiche.

Il backlog TCP è la coda delle connessioni in sospeso, ovvero delle richieste di connessione che sono state ricevute ma non ancora accettate. Nelle applicazioni compilate su versioni precedenti a OpenVOS 17.1 e in quelle compilate su OpenVOS 17.1 ma senza le librerie POSIX, le richieste di connessione non ricevono un riconoscimento fino a quando non vengono accettate dall'applicazione. Il client invierà nuovamente il pacchetto di richiesta di connessione da 3 a 10 volte a intervalli crescenti. I dettagli esatti dipenderanno dal sistema operativo del client e dalla sua configurazione. A un certo punto l'applicazione server accetta la richiesta di connessione e lo stack STCP invia un riconoscimento. Se tale riconoscimento viene ricevuto prima che il client abbia rinunciato, la connessione verrà completata e la comunicazione potrà iniziare.

Lo scenario di acquisizione degli ordini arretrati richiede diverse condizioni

  1. Si è verificato un guasto temporaneo della rete tra server e client (ma non tra client e server). Ciò consente al server di ricevere le richieste di connessione del client, ma impedisce al client di ricevere le conferme di connessione del server.
    o

    L'applicazione server ritarda la chiamata alla funzione accept per qualche motivo.

  2. Il client continua a inviare richieste di connessione; ciò significa che quando la richiesta corrente va in timeout, il client ne invia una nuova. Il valore di timeout del client deve essere inferiore al valore di timeout del server.
  3. Un firewall stateful o un altro dispositivo situato tra il client e il server interrompe le richieste di connessione del client e scarta le conferme di connessione del server senza inviare una risposta al server. Il valore di timeout deve essere inferiore al valore di timeout del server.

Purtroppo questa combinazione di condizioni non è così improbabile come potrebbe sembrare a prima vista.

In genere inizia con un'interruzione della rete che impedisce ai pacchetti provenienti dal server di raggiungere il client, ma consente ai pacchetti provenienti dal client di raggiungere il server. Quando il pacchetto di richiesta di connessione del client raggiunge il server, viene inserito nella coda di backlog. Quando l'applicazione server effettua una chiamata al codice di accettazione, il codice estrae la richiesta di connessione dalla coda di backlog e invia un riconoscimento di connessione. Poiché il server non riceve un riconoscimento per il suo pacchetto, a causa dell'interruzione della rete, ritrasmette il riconoscimento di connessione. Anche lo stack TCP del client ritrasmette la richiesta di connessione perché non ha ricevuto un riconoscimento. Dopo un po' di tempo, lo stack TCP del client rinuncia e l'applicazione client invia una nuova richiesta. Il server continua a rispondere alla prima richiesta. Dopo circa un minuto e mezzo (per impostazione predefinita), il server va in timeout e preleva la richiesta successiva dalla coda di backlog. Nel frattempo, il client ha inviato nuovamente la seconda richiesta e potrebbe essere alla terza. Anche queste richieste si trovano nella coda di backlog. È possibile che un altro client riceva una richiesta di connessione inserita nella coda di backlog, ma affinché questa venga completata con successo, il client avrebbe bisogno di un timeout superiore al timeout del server moltiplicato per la posizione della richiesta di connessione nella coda di backlog. Una volta risolto il problema di interruzione della rete, il firewall stateful perpetua l'interruzione eliminando silenziosamente i riconoscimenti di connessione per i quali non ha più uno stato, poiché mantiene lo stato solo per un tempo inferiore al timeout del server.

Come lo riconosci?

Innanzitutto, il backlog è pieno o almeno si sta riempiendo. È possibile visualizzare la coda del backlog per una connessione con questo comando.

analyze_system -request_line (string match backlog -or syncnt (byte 3Bx) dump_st + 
cbq -full -lport 7654 -faddr 0x) -quit 
OpenVOS Release 17.0.2au, analyze_system Release 17.0.2au 
Il processo corrente è 154, ptep 91CC7100, Noah_Davids.CAC 
syncnt                        6 
backlog                       5 
ready  11:41:19

Il valore lport è il numero della porta locale, in questo caso 7654. Il valore dell'indirizzo esterno (faddr) pari a 0 limita l'output al solo socket LISTENING. Se il valore backlog più 1 è uguale al valore syncnt, il backlog è pieno. Se syncnt è maggiore di 0 e aumenta, la coda del backlog si sta riempiendo. La dimensione della coda del backlog viene impostata dall'applicazione quando chiama la funzione listen.

In secondo luogo, è necessario esaminare una traccia del protocollo di rete. La traccia mostrerà che l'ultima richiesta di connessione non viene riconosciuta, mentre ci sono riconoscimenti di connessione per una richiesta di connessione precedente e tali riconoscimenti non ricevono alcun tipo di risposta.

La traccia nella figura 1 mostra questo. Ogni connessione è etichettata con un indice di flusso e anche codificata a colori. La prima richiesta di connessione dal client è nel frame 1 al tempo 0. Il riconoscimento viene inviato nel frame 2 e poi ritrasmesso nel frame 3. Il frame 4 è il client che ritrasmette la richiesta di connessione. Poiché STCP sta già inviando i riconoscimenti di connessione, il frame 4 attiva solo un riconoscimento TCP nel frame 5. I frame 6 e 7 sono conferme di connessione ritrasmesse. Il frame 8 è una richiesta di connessione ritrasmessa dal client. Il frame 9 è la conferma TCP attivata dalla richiesta di connessione ritrasmessa e il frame 10 è un'altra conferma di connessione ritrasmessa. Il frame 11 è un'altra richiesta di connessione dal client, ma per una nuova seconda connessione. Si noti che non c'è risposta e il frame 12 mostra una richiesta di connessione ritrasmessa. Il frame 13 mostra un riconoscimento di connessione, ma è ancora per la prima connessione. Il frame 14 è una ritrasmissione della seconda richiesta di connessione. Il frame 14 è un'altra ritrasmissione della seconda richiesta di connessione. Il frame 15 mostra una nuova, terza richiesta di connessione dal client e i frame 16 e 17 sono ritrasmissioni. Il frame 18 è un'altra ritrasmissione del riconoscimento di connessione alla prima connessione. Il frame 19 è un'altra richiesta di connessione con i frame 20 e 21 che sono le ritrasmissioni e il frame 22 è la quarta nuova richiesta di connessione. Infine, nel frame 23, STCP rinuncia alla prima richiesta di connessione e invia un reset seguito nel frame 24 da un riconoscimento di connessione alla seconda richiesta di connessione con una ritrasmissione nel frame 25. A questo punto penso che abbiate capito il concetto.

STCP ha impiegato dal frame 0 al frame 23 per andare in timeout, per un totale di 106,9 secondi. Sebbene il client non invii un reset al timeout, il tempo tra l'inizio della seconda e della terza richiesta di connessione (dal frame 11 al frame 15) è di 29,152 secondi e tra la terza e la quarta (frame 15 e 19) è di 25,8 secondi, molto più veloce rispetto a STCP.

Cosa puoi fare per evitare che ciò accada?

La soluzione migliore è eseguire l'aggiornamento a OpenVOS 17.1 e ricompilare l'applicazione con le librerie POSIX. In questo modo si eviterà il verificarsi del problema, poiché STCP invierà immediatamente una conferma di connessione, senza attendere che l'applicazione chiami accept. Tuttavia, ciò potrebbe modificare altri comportamenti dell'applicazione, pertanto è necessario eseguire test accurati dell'applicazione. Se l'aggiornamento e la ricompilazione non sono possibili, è possibile

  1. Riconfigurare il dispositivo di rete stateful che sta eliminando i confermi di connessione in modo che risponda con un reset. Quando STCP riceve il reset, passerà alla richiesta di connessione successiva nella coda di backlog. Il risultato è che le richieste di connessione scadute dal dispositivo stateful verranno rapidamente eliminate dalla coda. Eventuali ulteriori confermi di connessione saranno gestiti dal client, che invierà il proprio reset o li confermerà.
  2. Impedisci al client di inviare richieste di connessione finché la coda di backlog del server non è vuota.
  3. Chiudi il socket di ascolto dell'applicazione server e riaprilo. In genere, l'applicazione non è progettata per eseguire questa operazione, quindi è necessario arrestare e riavviare l'applicazione server.
  4. Configurare il valore syn_rcvd_abort su un valore inferiore al valore di timeout del client. Il valore viene modificato con la richiesta analyze_system set_stcp_param.
    analyze_system -request_line 'set_stcp_param syn_rcvd_abort 15' -quit
    OpenVOS Release 17.0.2au, analyze_system Release 17.0.2au
    Il processo corrente è 151, ptep 91530AC0, Noah_Davids.CAC 
    Modifica del timeout SYN_RCVD (syn_rcvd_abort) di tcp da off a 15 
    pronto  11:07:44

    Nell'esempio sopra riportato, il timeout è impostato su 15 secondi. I valori validi sono compresi tra 1 e 180, dove il valore 0 indica l'utilizzo dell'impostazione predefinita (circa 100 secondi).

    Ciò impedirà a un singolo client di creare un accumulo eccessivo nella coda di backlog. Il valore minimo dipenderà dal numero di client che potrebbero accedere al server contemporaneamente. Il problema di questo approccio è che influisce su tutti i client e tutte le porte del server, non è possibile avere un valore per un set di porte e un altro per un altro set di porte. Inoltre, un valore troppo basso potrebbe causare il fallimento di alcune connessioni che passano attraverso collegamenti ad alta latenza, mentre potrebbero avere successo se il timer fosse più lungo. La scelta di un valore ottimale è più un'arte che una scienza.