Taxa de transferência TCP mais baixa no servidor de 1 Gbps que no servidor de 100 Mbps em RTT grande

9

Temos infraestrutura distribuída em alguns dos principais locais do mundo - Cingapura, Londres e Los Angeles. O RTT entre dois locais está acima de 150ms.

Atualizamos recentemente todos os servidores para usar links de 1 Gbps (de 100 Mbps). Realizamos alguns testes baseados em TCP entre servidores em diferentes locais e vimos resultados surpreendentes. Estes resultados são completamente repetíveis.

  1. Los Angeles (100 Mbps) para Londres (100 Mbps): taxa de transferência de ~ 96 Mbps
  2. Los Angeles (100 Mbps) para Londres (1 Gbps): ~ 96 Mbps
  3. Los Angeles (1Gbps) para Londres (100Mbps): taxa de transferência de 10-40Mbps (volátil)
  4. Los Angeles (1Gbps) para Londres (1Gbps): taxa de transferência de 10-40Mbps (volátil)
  5. Los Angeles (1Gbps) para Los Angeles (1Gbps):> 900Mbps throughput

Parece que sempre que o remetente está executando a 1 Gbps, nossa taxa de transferência sofre muito significativamente em links longos.

A abordagem de teste anterior é extremamente simples - estou apenas usando o cURL para baixar um binário de 1 GB do servidor de destino (no caso acima, o cliente cURL é executado no servidor de Londres e é baixado de LA, para que LA seja o remetente) . Isso está usando uma única conexão TCP, é claro.

Repetindo os mesmos testes em UDP usando o iperf, o problema desaparece!

  1. Los Angeles (100 Mbps) para Londres (100 Mbps): taxa de transferência de ~ 96 Mbps
  2. Los Angeles (100 Mbps) para Londres (1 Gbps): ~ 96 Mbps
  3. Los Angeles (1Gbps) para Londres (100Mbps): taxa de transferência de ~ 96Mbps
  4. Los Angeles (1Gbps) para Londres (1Gbps):> 250Mbps throughput

Isso aponta diretamente para algum problema de configuração de TCP ou NIC / porta aos meus olhos.

Ambos os servidores estão executando o CentOS 6.x, com o TCP cúbico. Ambos têm 8 MB no máximo de janelas de envio e recebimento de TCP e têm registros de data e hora do TCP e reconhecimentos seletivos habilitados. A mesma configuração TCP é usada em todos os casos de teste. A configuração completa do TCP está abaixo:

net.core.somaxconn = 128
net.core.xfrm_aevent_etime = 10
net.core.xfrm_aevent_rseqth = 2
net.core.xfrm_larval_drop = 1
net.core.xfrm_acq_expires = 30
net.core.wmem_max = 8388608
net.core.rmem_max = 8388608
net.core.wmem_default = 131072
net.core.rmem_default = 131072
net.core.dev_weight = 64
net.core.netdev_max_backlog = 1000
net.core.message_cost = 5
net.core.message_burst = 10
net.core.optmem_max = 20480
net.core.rps_sock_flow_entries = 0
net.core.netdev_budget = 300
net.core.warnings = 1
net.ipv4.tcp_timestamps = 1
net.ipv4.tcp_window_scaling = 1
net.ipv4.tcp_sack = 1
net.ipv4.tcp_retrans_collapse = 1
net.ipv4.tcp_syn_retries = 5
net.ipv4.tcp_synack_retries = 5
net.ipv4.tcp_max_orphans = 262144
net.ipv4.tcp_max_tw_buckets = 262144
net.ipv4.tcp_keepalive_time = 7200
net.ipv4.tcp_keepalive_probes = 9
net.ipv4.tcp_keepalive_intvl = 75
net.ipv4.tcp_retries1 = 3
net.ipv4.tcp_retries2 = 15
net.ipv4.tcp_fin_timeout = 60
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_tw_recycle = 0
net.ipv4.tcp_abort_on_overflow = 0
net.ipv4.tcp_stdurg = 0
net.ipv4.tcp_rfc1337 = 0
net.ipv4.tcp_max_syn_backlog = 2048
net.ipv4.tcp_orphan_retries = 0
net.ipv4.tcp_fack = 1
net.ipv4.tcp_reordering = 3
net.ipv4.tcp_ecn = 2
net.ipv4.tcp_dsack = 1
net.ipv4.tcp_mem = 1528512      2038016 3057024
net.ipv4.tcp_wmem = 4096        131072  8388608
net.ipv4.tcp_rmem = 4096        131072  8388608
net.ipv4.tcp_app_win = 31
net.ipv4.tcp_adv_win_scale = 2
net.ipv4.tcp_tw_reuse = 0
net.ipv4.tcp_frto = 2
net.ipv4.tcp_frto_response = 0
net.ipv4.tcp_low_latency = 0
net.ipv4.tcp_no_metrics_save = 0
net.ipv4.tcp_moderate_rcvbuf = 1
net.ipv4.tcp_tso_win_divisor = 3
net.ipv4.tcp_congestion_control = cubic
net.ipv4.tcp_abc = 0
net.ipv4.tcp_mtu_probing = 0
net.ipv4.tcp_base_mss = 512
net.ipv4.tcp_workaround_signed_windows = 0
net.ipv4.tcp_dma_copybreak = 4096
net.ipv4.tcp_slow_start_after_idle = 1
net.ipv4.tcp_available_congestion_control = cubic reno
net.ipv4.tcp_allowed_congestion_control = cubic reno
net.ipv4.tcp_max_ssthresh = 0
net.ipv4.tcp_thin_linear_timeouts = 0
net.ipv4.tcp_thin_dupack = 0

Em anexo estão algumas imagens de gráficos do wireshark IO de alguns casos de teste (desculpe, ainda não posso postar imagens diretamente):

Caso de teste 1 (100Mbps -> 100Mbps) - transferência suave e agradável. Sem perdas na captura. - http://103.imagebam.com/download/dyNftIGh-1iCFbjfMFvBQw/25498/254976014/100m.png

O caso de teste 3 (1Gbps -> 100Mbps) - transferência automática, leva muito tempo para atingir qualquer velocidade - nunca se aproxima de 100Mbps. No entanto, não há perdas / retransmissões na captura! - http://101.imagebam.com/download/KMYXHrLmN6l0Z4KbUYEZnA/25498/254976007/1g.png

Portanto, em resumo, quando um link longo é usado com uma conexão de 1 Gbps, obtemos uma taxa de transferência TCP muito menor do que quando usamos uma conexão de 100 Mbps.

Eu aprecio muito algumas dicas de qualquer especialista em TCP por aí!

Obrigado!

ATUALIZAÇÃO (29-05-2013):

Resolvemos o problema com o caso de teste nº 4 acima (remetente de 1 Gbps, receptor de 1 Gbps, em um RTT grande). Agora podemos atingir ~ 970 Mbps alguns segundos após o início da transferência. O problema parece ter sido um comutador usado com o provedor de hospedagem. Mudar para outro diferente resolveu isso.

No entanto, o caso de teste nº 3 permanece principalmente problemático. Se temos um receptor rodando a 100 Mbps e o remetente a 1 Gbps, vemos aproximadamente uma espera de 2 a 3 minutos para que o receptor atinja 100 Mbps (mas agora atinge a taxa máxima, ao contrário de antes). Assim que baixamos o remetente para 100 Mbps ou aumentamos o receptor para 1 Gbps, o problema desaparece e podemos acelerar até a velocidade máxima em um ou dois segundos.

A razão subjacente é que estamos vendo perdas, é claro, logo após o início da transferência. No entanto, isso não corresponde à minha compreensão de como o início lento funciona; a velocidade da interface não deve ter relação com isso, pois deve ser regida pelos ACKs do receptor.

Sugestões recebidas com gratidão, por favor! Se eu pudesse oferecer uma recompensa aqui, eu o faria!

Sam
fonte
1
Você está usando a transferência TCP na NIC de ambos os lados? Seu uso de descarregamento de TCP está variando entre os 100M e os 1G NIC? Se isso estiver em uso em qualquer um dos casos de teste, pode valer a pena repetir os testes com esse recurso desativado apenas para verificar se o mecanismo de descarregamento TCP na NIC 100M pode estar atrapalhando o desempenho da comunicação 1G (esse comentário é intencionalmente mão-wavey apenas para abrir o TOE)
FliesLikeABrick
Boa pergunta! A transferência de segmentação TCP está desativada nas duas extremidades. A transferência de segmentação genérica é ativada nas duas extremidades. Também o repeti com o TSO ativado e não fez nenhuma diferença perceptível.
Sam
Tente desativar o descarregamento de segmentação genérica, pelo menos no lado do 100M, e repetir os testes
FliesLikeABrick
Obrigado pela sugestão, mas não há alegria - os mesmos resultados com o gso ativado ou desativado nos dois lados.
Sam
1Gbps a 150ms + fornece um produto de atraso de largura de banda muito grande, acima de 18Mb. O que acontece se você aumentar o buffer do soquete? tcp_*mem = 4096 1048576 33554432Você não ativou o Jumbo Frames nos links de 1 Gbps, não é? Isso pode estar causando uma sobrecarga de fragmentação em algum lugar.
Suprjami

Respostas:

1

O principal problema é o grande atraso na WAN. Será muito pior se também houver perda de pacotes aleatórios.

1, o tcp_mem também precisa ser grande para alocar mais memória. Por exemplo, configure-o como net.ipv4.tcp_mem = 4643328 6191104 9286656

2, você pode capturar os pacotes através do wireshark / tcpdump por vários minutos e analisar se há pacotes aleatórios perdidos. Você também pode fazer o upload do arquivo de pacotes, se desejar.

3, você pode tentar ajustar os outros parâmetros TCP, por exemplo. defina tcp_westwood = 1 e tcp_bic = 1

HarryREN
fonte
Obrigado, mas tentamos tudo isso. O atraso da WAN não é o problema - podemos atingir 100 Mbps quase imediatamente se usarmos portas de 100 Mbps, mas assim que alguém muda para 1 Gbps, estamos brindando.
29513 Sam
1

Resolvido! Para detalhes completos, consulte http://comments.gmane.org/gmane.linux.drivers.e1000.devel/11813

Em resumo, parece que o servidor conectado de 1 Gbps enviaria rajadas de tráfego durante a fase de crescimento exponencial do TCP que inundaria buffers em algum dispositivo intermediário (quem sabe o que). Isso deixa duas opções:

1) Entre em contato com cada operadora de rede intermediária e faça com que eles configurem buffers apropriados para permitir a largura de banda e o RTT desejados. Muito improvável! 2) Limite as rajadas.

Eu escolhi limitar cada fluxo TCP para operar a 100Mbps no máximo. O número aqui é bastante arbitrário - eu escolhi 100 Mbps apenas porque sabia que o caminho anterior poderia lidar com 100 Mbps e não precisava mais de um fluxo individual .

Espero que isso ajude alguém no futuro.

Sam
fonte
0

Repetindo os mesmos testes em UDP usando o iperf, o problema desaparece!

Los Angeles (1Gbps) para Londres (1Gbps):> 250Mbps throughput

O problema não parece ter desaparecido, 75% dos seus pacotes estão sendo descartados? Se o TCP iniciar lentamente o tempo todo, sua largura de banda média poderá ser bastante baixa.

Btw, você tem referências de Londres para Los Angeles e Londres para Londres?

Jens Timmerman
fonte
Esqueci de mencionar que o cliente é lento ... Se repetirmos com dois clientes rápidos, atingimos ~ 970Mbps bidirecionalmente.
29513 Sam