TIME_WAIT conexões não sendo limpas após o período de tempo limite expirar

7

Eu estou testando um dos meus servidores pressionando um fluxo constante de novas conexões de rede, o tcp_fin_timeout está configurado para 60, então se eu enviar um fluxo constante de algo como 100 solicitações por segundo, eu esperaria para ver uma média móvel de 6000 (60 * 100) conexões em um estado TIME_WAIT , isso está acontecendo, mas procurando em netstat (usando -o) para ver os timers, vejo conexões como:

TIME_WAIT   timewait (0.00/0/0)

onde o tempo limite expirou, mas a conexão ainda está por aí, acabo ficando sem conexões. Alguém sabe por que essas conexões não são limpas? Se eu parar de criar novas conexões, elas eventualmente desaparecerão, mas enquanto eu estou constantemente criando novas conexões que elas não acabam, parece que o kernel não está tendo chance de limpá-las? Existem outras opções de configuração que preciso definir para remover as conexões assim que elas expirarem?

O servidor está executando o Ubuntu e meu servidor web é o nginx. Também tem iptables com rastreamento de conexão, não tenho certeza se isso faria com que essas TIME_WAIT conexões vivessem.

Obrigado Mark.

    
por Mark Dawson 22.08.2011 / 07:54

3 respostas

3

Esse problema foi interessante, já que muitas vezes me perguntei. Fiz alguns testes e encontrei alguns resultados interessantes. Se eu abrir uma conexão para um servidor e esperar 60 segundos, ele seria invariavelmente limpo (nunca chegaria a 0.00 / 0/0). Se eu abri 100 conexões, elas também foram limpas após 60 segundos. Se eu abrisse 101 conexões, começaria a ver conexões no estado que você considerou (que eu também já vi antes). E eles parecem durar aproximadamente 120s ou 2xMSL (que é 60), independentemente do que fin_timeout está definido. Fiz algumas pesquisas no código-fonte do kernel e descobri o que acredito ser a "razão". Parece haver algum código que tenta limitar a quantidade de coleta de soquete que acontece por 'ciclo'. A frequência do ciclo em si é definida em uma escala baseada em HZ:

linux-source-2.6.38/include/net/inet_timewait_sock.h:
     35 #define INET_TWDR_RECYCLE_SLOTS_LOG     5
     36 #define INET_TWDR_RECYCLE_SLOTS         (1 << INET_TWDR_RECYCLE_SLOTS_LOG)
     37 
     38 /*
     39  * If time > 4sec, it is "slow" path, no recycling is required,
     40  * so that we select tick to get range about 4 seconds.
     41  */
     42 #if HZ <= 16 || HZ > 4096
     43 # error Unsupported: HZ <= 16 or HZ > 4096
     44 #elif HZ <= 32
     45 # define INET_TWDR_RECYCLE_TICK (5 + 2 - INET_TWDR_RECYCLE_SLOTS_LOG)
     46 #elif HZ <= 64
     47 # define INET_TWDR_RECYCLE_TICK (6 + 2 - INET_TWDR_RECYCLE_SLOTS_LOG)
     48 #elif HZ <= 128
     49 # define INET_TWDR_RECYCLE_TICK (7 + 2 - INET_TWDR_RECYCLE_SLOTS_LOG)
     50 #elif HZ <= 256
     51 # define INET_TWDR_RECYCLE_TICK (8 + 2 - INET_TWDR_RECYCLE_SLOTS_LOG)
     52 #elif HZ <= 512
     53 # define INET_TWDR_RECYCLE_TICK (9 + 2 - INET_TWDR_RECYCLE_SLOTS_LOG)
     54 #elif HZ <= 1024
     55 # define INET_TWDR_RECYCLE_TICK (10 + 2 - INET_TWDR_RECYCLE_SLOTS_LOG)
     56 #elif HZ <= 2048
     57 # define INET_TWDR_RECYCLE_TICK (11 + 2 - INET_TWDR_RECYCLE_SLOTS_LOG)
     58 #else
     59 # define INET_TWDR_RECYCLE_TICK (12 + 2 - INET_TWDR_RECYCLE_SLOTS_LOG)
     60 #endif
     61 
     62 /* TIME_WAIT reaping mechanism. */
     63 #define INET_TWDR_TWKILL_SLOTS  8 /* Please keep this a power of 2. */
The number of slots is also set here:
     65 #define INET_TWDR_TWKILL_QUOTA 100

No código do tempo real, você pode ver onde ele usa a citação para parar de matar as conexões TIME_WAIT se já tiver feito muitas:

linux-source-2.6.38/net/ipv4/inet_timewait_sock.c:
    213 static int inet_twdr_do_twkill_work(struct inet_timewait_death_row *twdr,
    214                                     const int slot)
    215 {
...
    240                 if (killed > INET_TWDR_TWKILL_QUOTA) {
    241                         ret = 1;
    242                         break;
    243                 }

Há mais informações aqui sobre o motivo pelo qual o HZ é definido como: link Mas não é incomum aumentá-lo. No entanto, acho que é mais comum ativar tw_reuse / recycling para contornar esse mecanismo de bucket / quota (o que me parece confuso agora que li sobre isso, aumentar o HZ seria uma solução muito mais segura e mais limpa). Eu postei isso como uma resposta, mas acho que poderia haver mais discussão aqui sobre qual é o "caminho certo" para consertar isso. Obrigado pela pergunta interessante!

    
por 28.08.2011 / 05:35
2

Em vez de usar tcp_tw_recycle = 1 , use o seguinte:

tcp_tw_reuse = 1

Recrie relatórios para serem quebrados e, em alguns casos, não funciona quando você estiver usando NAT ou balanceamento de carga.

    
por 24.09.2012 / 05:05
0

net.ipv4.tcp_fin_timeout é padronizado para 60s. Nunca ficou claro para mim por que os soquetes tendem a permanecer em TIME_WAIT mais tempo do que esse limite.

tcp_tw_recycle está quebrado, não sei como não uso. Você provavelmente precisará definir tcp_tw_reuse como 1, mas supostamente isso causará problemas com o NAT.

    
por 22.08.2011 / 11:28