Abbiamo infrastrutture distribuite in alcune delle principali località del mondo: Singapore, Londra e Los Angeles. La RTT tra due posizioni qualsiasi è superiore a> 150 ms.
Di recente abbiamo aggiornato tutti i server per utilizzare collegamenti da 1 Gbps (da 100 Mbps). Abbiamo eseguito alcuni test basati su TCP tra server in diverse posizioni e abbiamo riscontrato risultati sorprendenti. Questi risultati sono completamente ripetibili.
- Da Los Angeles (100 Mbps) a Londra (100 Mbps): velocità effettiva di ~ 96 Mbps
- Da Los Angeles (100 Mbps) a Londra (1 Gbps): velocità effettiva di ~ 96 Mbps
- Da Los Angeles (1 Gbps) a Londra (100 Mbps): throughput 10-40 Mbps (volatile)
- Da Los Angeles (1 Gbps) a Londra (1 Gbps): throughput 10-40 Mbps (volatile)
- Da Los Angeles (1 Gbps) a Los Angeles (1 Gbps):> 900 Mbps di throughput
Sembra che ogni volta che il mittente è in esecuzione a 1 Gbps, il nostro throughput soffre in modo molto significativo su collegamenti lunghi.
L'approccio di test precedente è estremamente semplice: sto solo usando cURL per scaricare un file binario da 1 GB dal server di destinazione (quindi nel caso sopra, il client cURL viene eseguito sul server di Londra e viene scaricato da LA, in modo che LA sia il mittente) . Questo ovviamente utilizza una singola connessione TCP.
Ripetendo gli stessi test su UDP usando iperf, il problema scompare!
- Da Los Angeles (100 Mbps) a Londra (100 Mbps): velocità effettiva di ~ 96 Mbps
- Da Los Angeles (100 Mbps) a Londra (1 Gbps): velocità effettiva di ~ 96 Mbps
- Da Los Angeles (1 Gbps) a Londra (100 Mbps): velocità effettiva di ~ 96 Mbps
- Da Los Angeles (1 Gbps) a Londra (1 Gbps): velocità effettiva> 250 Mbps
Ciò indica chiaramente alcuni problemi di configurazione TCP o NIC / porta ai miei occhi.
Entrambi i server eseguono CentOS 6.x, con TCP cubico. Entrambi hanno un massimo di 8 MB di finestre di invio e ricezione TCP e hanno timestamp TCP e riconoscimenti selettivi abilitati. La stessa configurazione TCP viene utilizzata in tutti i casi di test. La configurazione TCP completa è di seguito:
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
In allegato un paio di immagini dei grafici IO di WireShark di alcuni casi di test (scusate, non riesco ancora a pubblicare le immagini direttamente):
Caso di prova 1 (100 Mbps -> 100 Mbps) - trasferimento gradevole. Nessuna perdita di cattura. - http://103.imagebam.com/download/dyNftIGh-1iCFbjfMFvBQw/25498/254976014/100m.png
Test case 3 (1Gbps -> 100 Mbps) - trasferimento votaile, impiega molto tempo per raggiungere qualsiasi velocità - non si avvicina mai a 100 Mbps. Eppure nessuna perdita / ritrasmissione nella cattura! - http://101.imagebam.com/download/KMYXHrLmN6l0Z4KbUYEZnA/25498/254976007/1g.png
Quindi, in sintesi, quando viene utilizzato un collegamento lungo con una connessione da 1 Gbps, otteniamo un throughput TCP molto inferiore rispetto a quando utilizziamo una connessione da 100 Mbps.
Apprezzerei molto alcuni suggerimenti di tutti gli esperti TCP là fuori!
Grazie!
AGGIORNAMENTO (29/05/2013):
Abbiamo risolto il problema con il test case n. 4 sopra (mittente 1 Gbps, ricevitore 1 Gbps, su un RTT di grandi dimensioni). Ora possiamo raggiungere ~ 970 Mbps entro un paio di secondi dall'inizio del trasferimento. Il problema sembra essere stato uno switch utilizzato con il provider di hosting. Passare a un altro risolto questo.
Tuttavia, il caso di test n. 3 rimane per lo più problematico. Se abbiamo un ricevitore in esecuzione a 100 Mbps e il mittente a 1 Gbps, vediamo circa 2-3 minuti di attesa affinché il ricevitore raggiunga 100 Mbps (ma ora raggiunge la velocità massima, a differenza di prima). Non appena abbassiamo il mittente a 100 Mbps o aumentiamo il ricevitore a 1 Gbps, il problema scompare e possiamo accelerare alla massima velocità in uno o due secondi.
La ragione di fondo è che stiamo assistendo a perdite, ovviamente, molto presto dopo l'inizio del trasferimento. Tuttavia, ciò non coincide con la mia comprensione di come funziona l'avvio lento; la velocità dell'interfaccia non dovrebbe influire su ciò, poiché dovrebbe essere regolata dagli ACK del ricevitore.
Suggerimenti ricevuti con gratitudine per favore! Se potessi offrire una taglia qui, lo farei!
tcp_*mem = 4096 1048576 33554432
Non hai abilitato Jumbo Frames sui link 1Gbps, vero? Ciò potrebbe causare la frammentazione ambientale da qualche parte.