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!
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.