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.
- Los Angeles (100 Mbps) para Londres (100 Mbps): taxa de transferência de ~ 96 Mbps
- Los Angeles (100 Mbps) para Londres (1 Gbps): ~ 96 Mbps
- Los Angeles (1Gbps) para Londres (100Mbps): taxa de transferência de 10-40Mbps (volátil)
- Los Angeles (1Gbps) para Londres (1Gbps): taxa de transferência de 10-40Mbps (volátil)
- 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!
- Los Angeles (100 Mbps) para Londres (100 Mbps): taxa de transferência de ~ 96 Mbps
- Los Angeles (100 Mbps) para Londres (1 Gbps): ~ 96 Mbps
- Los Angeles (1Gbps) para Londres (100Mbps): taxa de transferência de ~ 96Mbps
- 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!
fonte
tcp_*mem = 4096 1048576 33554432
Você 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.Respostas:
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
fonte
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.
fonte
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?
fonte