Baixa taxa de transferência TCP do servidor de 1 Gbps do que do servidor de 100 Mbps por 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 > 150 ms.

Recentemente, atualizamos todos os servidores para usar links de 1 Gbps (de 100 Mbps). Fizemos alguns testes baseados em TCP entre servidores em diferentes locais e observamos alguns resultados surpreendentes. Estes resultados são completamente repetíveis.

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

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

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

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

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

Isso aponta diretamente para algum problema de configuração 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 8MB de envio TCP máximo & receber janelas e ter registros de data e hora TCP e reconhecimentos seletivos ativados. 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 dos gráficos de I / O do wireshark de alguns casos de teste (desculpe, não posso postar imagens diretamente ainda):

Caso de teste 1 (100Mbps - > 100Mbps) - boa transferência suave. Nenhuma perda na captura. - link

Caso de teste 3 (1Gbps - > 100Mbps) - a transferência de vota, leva muito tempo para chegar a qualquer velocidade - nunca se aproxima de 100Mbps. Ainda não há perdas / retransmissões na captura! - link

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 especialistas em TCP por aí!

Obrigado!

UPDATE (2013-05-29):

Solucionamos 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 ~ 970Mbps dentro de alguns segundos após o início da transferência. O problema aparece como um switch usado com o provedor de hospedagem. Mudar para um diferente resolveu isso.

No entanto, o caso de teste nº 3 continua a ser problemático. Se tivermos um receptor rodando a 100Mbps e o remetente a 1Gbps, veremos uma espera de aproximadamente 2-3 minutos para o receptor atingir 100Mbps (mas agora atinge a taxa total, diferente de antes). Assim que derrubarmos o remetente para 100Mbps ou aumentarmos o receptor para 1Gbps, o problema desaparece e podemos aumentar a velocidade máxima em um segundo ou dois.

O motivo subjacente é que estamos vendo perdas, é claro, logo após o início da transferência. No entanto, isso não concorda com minha compreensão de como o slow-start funciona; a velocidade da interface não deve ter qualquer influência nisso, já que deve ser governada pelos ACKs do receptor.

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

    
por Sam 17.05.2013 / 15:51

3 respostas

1

Resolvido! Para detalhes completos, consulte o link

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

1) Entre em contato com cada operador de rede intermediário e faça com que eles configurem buffers apropriados para permitir minha largura de banda e 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 100Mbps simplesmente porque eu sabia que o caminho anterior poderia lidar com 100Mbps e eu não precisava de mais nenhum para um fluxo individual .

Espero que isso ajude alguém no futuro.

    
por 12.07.2013 / 22:35
1

A principal questão é um grande atraso na WAN. Será muito pior se também tiver um pacote aleatório perdido.

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

2, você pode capturar os pacotes através do wireshark / tcpdump por alguns minutos e depois analisar se perdeu pacotes aleatórios. Você também pode enviar o arquivo de pacotes, se quiser.

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

    
por 20.05.2013 / 16:42
0

Repeating the same tests over UDP using iperf, the problem disappears!

Los Angeles (1Gbps) to London (1Gbps): >250Mbps throughput

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

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

    
por 24.05.2013 / 15:28