A captura de backlog TCP é um efeito que impede que um aplicativo de servidor no módulo Stratus que está escutando na porta X crie uma conexão com qualquer cliente que tente se conectar à porta X. As conexões com outras portas, mesmo dos mesmos clientes, funcionam normalmente. A solução típica é desligar e reiniciar o aplicativo do servidor. Esta publicação explicará por que a captura de backlog ocorre e outras soluções menos drásticas.
O backlog TCP é a fila de conexões pendentes, ou seja, solicitações de conexão que foram recebidas, mas ainda não foram aceitas. Em aplicativos compilados em versões anteriores ao OpenVOS 17.1 e em aplicativos compilados no OpenVOS 17.1, mas sem as bibliotecas POSIX, as solicitações de conexão não recebem uma confirmação até que sejam aceitas pelo aplicativo. O cliente reenviará o pacote de solicitação de conexão entre 3 e 10 vezes em intervalos crescentes. Os detalhes exatos dependerão do sistema operacional do cliente e de como ele está configurado. Em algum momento, o aplicativo servidor aceita a solicitação de conexão e a pilha STCP envia uma confirmação. Desde que essa confirmação seja recebida antes que o cliente desista, a conexão será concluída e a comunicação poderá começar.
O cenário de captura de backlog requer várias condições
- Há uma falha temporária na rede entre o servidor e o cliente (mas não entre o cliente e o servidor). Isso permite que as solicitações de conexão do cliente sejam recebidas pelo servidor, mas impede que as confirmações de conexão do servidor sejam recebidas pelo cliente.
ou
O aplicativo do servidor atrasa a chamada da função aceitar por algum motivo.
- O cliente continua a enviar solicitações de conexão; ou seja, quando a solicitação atual expira, o cliente envia uma nova. O valor de tempo limite do cliente deve ser menor que o valor de tempo limite do servidor.
- Um firewall com estado ou algum outro dispositivo entre o cliente e o servidor expira as solicitações de conexão do cliente e descarta as confirmações de conexão do servidor sem enviar uma resposta de volta ao servidor. Esse valor de tempo limite deve ser menor do que o valor de tempo limite do servidor.
Infelizmente, essa combinação de condições não é tão improvável quanto pode parecer à primeira vista.
Normalmente, começa com uma falha na rede que impede que os pacotes do servidor cheguem ao cliente, mas permite que os pacotes do cliente cheguem ao servidor. Quando o pacote de solicitação de conexão do cliente chega ao servidor, ele é colocado na fila de backlog. Quando o aplicativo do servidor faz uma chamada para o código de aceitação, o código retira a solicitação de conexão da fila de backlog e envia uma confirmação de conexão. Como o servidor não recebe uma confirmação para seu pacote, devido à falha na rede, ele retransmite a confirmação de conexão. A pilha TCP do cliente também retransmite a solicitação de conexão, pois não recebeu uma confirmação. Depois de um tempo, a pilha TCP do cliente desiste e o aplicativo cliente envia uma nova solicitação. O servidor continua respondendo à primeira solicitação. Após cerca de um minuto e meio (por padrão), o servidor expira e retira a próxima solicitação da fila de backlog. Enquanto isso, o cliente reenviou a segunda solicitação e pode estar na terceira. Essas solicitações também estão na fila de backlog. É possível que algum outro cliente receba uma solicitação de conexão colocada na fila de backlog, mas para que ela seja concluída com sucesso, o cliente precisaria de um tempo limite maior do que o tempo limite do servidor multiplicado pela posição da solicitação de conexão na fila de backlog. Uma vez corrigida a interrupção da rede, o firewall com estado perpetua a interrupção, descartando silenciosamente os reconhecimentos de conexão para os quais não tem mais um estado, pois mantém o estado por um tempo menor do que o tempo limite do servidor.
Como você reconhece isso?
Primeiro, a fila de espera está cheia ou, pelo menos, a encher. Pode exibir a fila de espera de uma conexão com este comando.
analyze_system -request_line (string match backlog -ou syncnt (byte 3Bx) dump_st + cbq -full -lport 7654 -faddr 0x) -quit
OpenVOS Versão 17.0.2au, analyze_system Versão 17.0.2au
O processo atual é 154, ptep 91CC7100, Noah_Davids.CAC
syncnt 6
backlog 5
pronto 11:41:19
|
O valor lport é o número da porta local, 7654 neste caso. O valor do endereço externo (faddr) 0 limita a saída apenas ao soquete LISTENING. Se o valor backlog mais 1 for igual ao valor syncnt, o backlog está cheio. Se o syncnt for maior que 0 e estiver aumentando, a fila de backlog está enchendo. O tamanho da fila de backlog é definido pelo aplicativo quando ele chama a função listen.
Em segundo lugar, você precisa examinar um rastreamento do protocolo de rede. O rastreamento mostrará que a última solicitação de conexão não é reconhecida, enquanto há reconhecimentos de conexão para uma solicitação anterior e esses reconhecimentos não estão recebendo nenhum tipo de resposta.
O rastreamento na figura 1 mostra isso. Cada conexão é identificada com um índice de fluxo e também codificada por cores. A primeira solicitação de conexão do cliente está no quadro 1 no momento 0. A confirmação é enviada no quadro 2 e, em seguida, retransmitida no quadro 3. O quadro 4 é o cliente retransmitindo a solicitação de conexão. Como o STCP já está enviando confirmações de conexão, o quadro 4 aciona apenas uma confirmação TCP no quadro 5. Os quadros 6 e 7 são confirmações de conexão retransmitidas. O quadro 8 é uma solicitação de conexão retransmitida do cliente. O quadro 9 é a confirmação TCP acionada pela solicitação de conexão retransmitida e o quadro 10 é outra confirmação de conexão retransmitida. O quadro 11 é outra solicitação de conexão do cliente, mas para uma nova segunda conexão. Observe que não há resposta e o quadro 12 mostra uma solicitação de conexão retransmitida. O quadro 13 mostra um reconhecimento de conexão, mas ainda é para a primeira conexão. O quadro 14 é uma retransmissão da segunda solicitação de conexão. O quadro 14 é outra retransmissão da segunda solicitação de conexão. O quadro 15 mostra uma nova terceira solicitação de conexão do cliente e os quadros 16 e 17 são retransmissões. O quadro 18 é outra retransmissão do reconhecimento de conexão para a primeira conexão. O quadro 19 é mais uma solicitação de conexão, com os quadros 20 e 21 sendo as retransmissões e o quadro 22 sendo a quarta nova solicitação de conexão. Finalmente, no quadro 23, o STCP desiste da primeira solicitação de conexão e envia uma reinicialização, seguida no quadro 24 por uma confirmação de conexão para a segunda solicitação de conexão, com uma retransmissão no quadro 25. A esta altura, acho que você já entendeu a ideia.
O STCP levou do quadro 0 ao quadro 23 para expirar, um total de 106,9 segundos. Embora o cliente não envie um reset quando ocorre o tempo limite, o tempo entre o início da segunda e da terceira solicitações de conexão (quadro 11 ao quadro 15) é de 29,152 segundos e entre a terceira e a quarta (quadros 15 e 19) é de 25,8 segundos; muito mais rápido que o STCP.
O que você pode fazer para evitar isso?
A melhor solução é atualizar para o OpenVOS 17.1 e recompilar o aplicativo com as bibliotecas POSIX. Isso impedirá que o problema ocorra, pois o STCP enviará uma confirmação de conexão imediatamente, sem esperar que o aplicativo chame o accept. No entanto, isso pode alterar outros comportamentos do seu aplicativo, portanto, é necessário testá-lo cuidadosamente. Se não for possível atualizar e recompilar, você pode
- Reconfigure o dispositivo de rede com estado que está descartando as confirmações de conexão para responder com uma reinicialização. Quando o STCP receber a reinicialização, ele passará para a próxima solicitação de conexão na fila de backlog. O resultado é que as solicitações de conexão com tempo limite pelo dispositivo com estado serão rapidamente drenadas da fila. Quaisquer outras confirmações de conexão serão tratadas pelo cliente, que enviará sua própria reinicialização ou as confirmará.
- Impedir que o cliente faça solicitações de conexão até que a fila de backlog do servidor seja esvaziada.
- Feche o soquete de escuta do aplicativo do servidor e reabra-o. Normalmente, o aplicativo não é projetado para fazer isso, então você precisa parar e reiniciar o aplicativo do servidor.
- Configure o valor syn_rcvd_abort para algo menor que o valor de tempo limite do cliente. O valor é alterado com a solicitação analyze_system set_stcp_param.
analyze_system -request_line 'set_stcp_param syn_rcvd_abort 15' -quit OpenVOS versão 17.0.2au, analyze_system versão 17.0.2au O processo atual é 151, ptep 91530AC0, Noah_Davids.CAC Alterando o tempo limite SYN_RCVD do tcp (syn_rcvd_abort) de desativado para 15 pronto 11:07:44No exemplo acima, o tempo limite é definido para 15 segundos. Os valores válidos estão entre 1 e 180, sendo que o valor 0 significa usar o padrão (cerca de 100 segundos).
Isso impedirá que um único cliente crie um grande acúmulo na fila de backlog. O valor mínimo dependerá do número de clientes que podem acessar o servidor ao mesmo tempo. O problema dessa abordagem é que ela afeta todos os clientes e todas as portas do servidor, não sendo possível ter um valor para um conjunto de portas e outro para outro conjunto de portas. Além disso, um valor muito baixo pode fazer com que algumas conexões que passam por links de alta latência falhem, quando poderiam ser bem-sucedidas se o temporizador fosse mais longo. Escolher um valor ideal é mais uma arte do que uma ciência.
