內核TCP優化的相關參數

內核TCP相關的參數均在/proc/sys/net/ipv4下,有以下選項:

 

tcp_abort_on_overflow
tcp_adv_win_scale
tcp_allowed_congestion_control
tcp_app_win
tcp_autocorking
tcp_available_congestion_control
tcp_base_mss
tcp_challenge_ack_limit
tcp_congestion_control
tcp_dsack
tcp_early_retrans
tcp_ecn
tcp_fack
tcp_fastopen
tcp_fastopen_key
tcp_fin_timeout
tcp_frto
tcp_invalid_ratelimit
tcp_keepalive_intvl
tcp_keepalive_probes
tcp_keepalive_time
tcp_limit_output_bytes
tcp_low_latency
tcp_max_orphans
tcp_max_ssthresh
tcp_max_syn_backlog
tcp_max_tw_buckets
tcp_mem
tcp_min_tso_segs
tcp_moderate_rcvbuf
tcp_mtu_probing
tcp_no_metrics_save
tcp_notsent_lowat
tcp_orphan_retries
tcp_reordering
tcp_retrans_collapse
tcp_retries1
tcp_retries2
tcp_rfc1337
tcp_rmem
tcp_sack
tcp_slow_start_after_idle
tcp_stdurg
tcp_synack_retries
tcp_syncookies
tcp_syn_retries
tcp_thin_dupack
tcp_thin_linear_timeouts
tcp_timestamps
tcp_tso_win_divisor
tcp_tw_recycle
tcp_tw_reuse
tcp_window_scaling
tcp_wmem
tcp_workaround_signed_windows

ARP相關的內核參數,ARP緩存限制:

 

net.ipv4.neigh.default.gc_thresh1  在該值以下不gc,常駐緩存
net.ipv4.neigh.default.gc_thresh2  soft limit,可以臨時超過該值,但只能保留5秒,之後會被gc掉
net.ipv4.neigh.default.gc_thresh3  hard limit,超過該值,就立即gc掉

在openstack網絡節點中此參數很重要。

TCP相關的
連接數:
socket接收的所有連接都是存放在隊列類型的數據結構中,有兩類對列,可以自定義。

分別是下面兩個內核參數:

 

/proc/sys/net/ipv4/tcp_max_syn_backlog
/proc/sys/net/core/somaxconn

其中:
tcp_max_syn_backlog: 半連接隊列,是指定所能接受SYN同步包的最大客戶端數量,即半連接上限;
somaxconn: 全連接隊列,指服務端所能accept即處理數據的最大客戶端數量,即完成連接上限。
tcp_max_syn_backlog:默認值爲256
somaxconn:默認值爲128,對應socket編程中的backlog,min{somaxconn,backlog}爲實際值; 可以使用 ss -lnt中Recv-Q查看對列是否滿

TCP三次握手過程

三次握手

 

狀態轉移圖

上述是三次握手協議的過程,上述是協議流程。socket編程流程如下:

socket編程

  1. client發送syn(SYN_SENT狀態),初始化一條連接,server收到syn之後進入SYN_RCVD的狀態,並且此連接進入半連接隊列(參數tcp_max_syn_backlog);同時回覆syn+ack給client(第一次握手)。半連接隊列滿,新的連接請求就會被忽略。半連接攻擊就是針對此資源的佔用攻擊;

  2. client收到server端發送的syn+ack後,進入ESTABLISHED狀態,第二次握手完成,表示連接已建立(此時三次握手還未完成,server端狀態未變)。同時回覆ACK給server;

  3. server接收到ack後,進入ESTABLISHED的狀態,第三次握手完成。同時建立的連接會放入全連接隊列中,涉及參數(somaxconn);全連接隊列滿時,連接的處理取決於tcp_abort_on_overflow,爲0: 丟棄ack,過一段時間重新發送syn+ack,tcp_synack_retries表示重試次數;1:發送 reset client 廢棄此次連接;

  • somaxconn:全連接隊列大小
  • tcp_abort_on_overflow: 隊列滿,ack的處理方式;
  • tcp_synack_retries: tcp_abort_on_overflow=0時,重發syn+ack的次數;受到半連接攻擊時,可降低此值;
  • tcp_syncookies: 受到半連接攻擊時,開啓此參數

建立連接相關的參數

  • tcp_syn_retries(Default: 5): 發起syn連接,傳輸失敗時重試的次數;重傳間隔爲2的次方,基礎時間爲3s

半連接相關參數

  • tcp_syncookies: 在Tcp服務器收到Tcp Syn包並返回Tcp Syn+ack包時,不專門分配一個數據區,而是根據這個Syn包計算出一個cookie值。在收到Tcp ack包時,Tcp服務器在根據那個cookie值檢查這個Tcp ack包的合法性。如果合法,再分配專門的數據區進行處理未來的TCP連接。
    默認爲0,1表示開啓
  • tcp_synack_retries: 減少重試次數

連接維護階段

  • tcp_keepalive_time: 如果在該參數指定的秒數內連接始終處於空閒狀態,則內核向客戶端發起對該主機的探測
  • tcp_keepalive_intvl: 探測包的間隔時間
  • tcp_keepalive_probes: 發送探測包的最大個數,如果發送完仍未迴應,則釋放連接
  • tcp_retries2: 已建立連接,未回覆ACK 的數據包,最大嘗試次數,嘗試次數用盡後,釋放連接
  • tcp_retries: 已建立的連接,未回覆包的嘗試次數,在嘗試此次數之後,需要檢查路由表
  • tcp_max_orphans: 系統所能處理不屬於任何進程的TCP sockets最大數量。假如超過這個數量,那麼不屬於任何進程的連接會被立即reset
  • tcp_orphan_retries: 清理孤兒socket嘗試次數

查看tcp連接各個狀態的個數
netstat -n | grep "^tcp" | awk '{print $6}' | sort | uniq -c | sort -n

連接清理階段

  1. 主動A的一方發送Fin,進入Fin_WAIT_1,接收到Fin端的P進入CLOSE_WAIT狀態,P同時發送ack確認Fin;
  2. A接收到P發送的ack後進入Fin_WAIT_2半連接的狀態;等待P側的Fin消息;
  3. P側發送Fin消息後,進入Last_ACK狀態,同時A側收到Fin後,發送ACK,同時進入TIME_WAIT狀態;

注:
TIME_WAIT存在的原因:
1.可靠的終止TCP連接(確保另一側能夠收到ACK)。
2.保證讓遲來的TCP報文段有足夠的時間被識別並丟棄。
time_wait持續的時間: 2MSL,保證舊的數據能夠丟棄。網絡中的數據最大生命週期MSL(maxinum segment lifetime)

涉及參數:

  • tcp_max_tw_buckets(Default: 32768): 表示系統同時保持TIME_WAIT套接字的最大數量,如果超過這個數字,TIME_WAIT套接字將立刻被清除並打印警告信息
  • tcp_tw_recycle(Default: 0): 表示開啓TCP連接中TIME-WAITsockets的快速回收,默認爲0,表示關閉
  • tcp_tw_reuse(Default: 0): 表示開啓重用。允許將TIME-WAITsockets重新用於新的TCP連接,默認爲0,表示關閉
  • tcp_no_metrics_save(Default: 0): 一個tcp連接關閉後,把這個連接曾經有的參數比如慢啓動門限snd_sthresh,擁塞窗口snd_cwnd 還有srtt等信息保存到dst_entry中, 只要dst_entry 沒有失效,下次新建立相同連接的時候就可以使用保存的參數來初始化這個連接.。 默認爲0,表示關閉
  • tcp_fin_timeout(Default: 60): TCP保持在FIN_WAIT_2狀態的時間,超過這個時間,則tcp釋放

擁塞控制及緩存管理
TCP支持多種擁塞處理機制:

  • tcp_allowed_congestion_control(cubic,reno): 系統允許的擁塞算法
  • tcp_available_congestion_control(cubic,reno): 系統可用的擁塞算法,是allowed子集
  • tcp_congestion_control(cubic): 建立tcp連接,默認的擁塞算法,socket編程時,設置TCP_CONGESTION指定擁塞算法

TCP的擁塞算法主要關注:“慢啓動”/“擁塞避免”/“快速重傳”/"快速恢復"等階段。

  1. 滑動窗口協議

窗口大小決定了發送數據的長度,以提高TCP數據吞吐率,在此窗口的數據無需確認應答而可以繼續發送直至窗口上限,再收到應答後將窗口滑動到確認應答序列號的位置,此時就可以繼續發送。
窗口分爲發送窗口和接收窗口,發送窗口表示可以發送的的數據量;接收窗口大小表示可以接收的數據。

以下是關於窗口大小的設置:

TCP發送方,發送緩存內的數據可以分爲4類:

  • 已經發送並得到對端ACK
  • 已經發送但還未得到對端ACK
  • 未發送但對端允許發送的數據
  • 未發送且對端不允許發送的數據

其中"已經發送但還未得到對端ACK"和"未發送但對端允許發送的數據"稱爲發送窗口。
計算可以繼續發送的數據,如已確認的序號爲n,已發送到x字節,窗口大小爲m,則可繼續發送的數據量爲:m-(n-x)

TCP接收方的緩存數據,分爲3類:

  • 已接收
  • 未接收準備接收
  • 未接收未準備接收

其中,"未接收準備接收"稱之爲接收窗口。

窗口大小與接收端主機通知的窗口大小作比較,選擇較小的值爲發送窗口。

內核中涉及影響窗口大小的參數:

  • net.core.rmem_default = 212992: 每一個TCP socket默認的用於TCP接收的數據緩存大小,字節
  • net.core.rmem_max = 212992:每一個TCP socket最大的接收數據緩的最大存,字節;socket設置SO_RCVBUF不能超過此值。計算方式:max(87380, min(4MB, tcp_mem[1]*PAGE_SIZE/128))
  • net.core.wmem_default = 212992:每一個TCP socket默認的用於TCP發送數據的緩存大小,字節
  • net.core.wmem_max = 212992:每一個TCP socket最大的用於數據發送的緩存,字節;socket設置SO_SNDBUF不能超過此值。計算方式:max(65536, min(4MB, tcp_mem[1]*PAGE_SIZE/128))
    佔用緩存的數據類型:
    接收緩存: 1. TCP緩存的無序的數據; 2. 已確認待應用讀取的數據,剩下的是接收窗口最大可用大小。具體應用緩存所佔比例參見:tcp_adv_win_scale。
    如何正確設置最大讀緩存大小:
  • 若配置了tcp_adv_win_scale,讀緩存的上限應當由最大的TCP接收窗口決定;
  • 網絡帶寬的大小,也影響能夠接收的數據。因此,最大接收窗口也會依賴BDP設置(帶寬延時積),如帶寬爲1Gbps,延時爲2ms,則BDP:1*0.002=0.002Gb,最大接收窗口爲0.002gb;
  • 根據tcp_adv_win_scale及最大接收窗口,設置合適的最大讀緩存。

實際發送窗口都爲接收窗口的大小。

由於每一個連接都會佔用部分緩存,在長肥網絡中BDP很大,導致最大緩存也會很大。連接數較多時,內存有限無法滿足,此時就需要系統調整緩存大小,此功能需要顯示的配置:
net.ipv4.tcp_moderate_rcvbuf = 1
默認tcp_moderate_rcvbuf配置爲1,表示打開了TCP內存自動調整功能。若配置爲0,則功能禁用。若設置了SO_SNDBUF、SO_RCVBUF,linux內核則不再對這樣的連接執行自動調整功能。

內核在調整緩存時,涉及以下參數,單位都是頁(4KB):

  • net.ipv4.tcp_mem = 378783 505045 757566
  • net.ipv4.tcp_rmem = 4096 87380 6291456
  • net.ipv4.tcp_wmem = 4096 16384 4194304

tcp_rmem

表示任何一個tcp連接的讀緩存的上限值,分別表示:最小上限、初始上限(覆蓋rmem_default)、最大上限。

tcp_wmem

參見tcp_rmem.

tcp_mem

其中,tcp_mem設定tcp內存的整天使用情況,定義了整體內存的無壓力值、壓力模式開啓閥值、最大使用值。

  • 當整體內存小於tcp_mem[0]時,表示處於非壓力模式下,每個tcp socket的最大緩存可增加至tcp_r/wmem[2];且新分配的內存一定會成功。
  • 當整體內存介於tcp_mem[0]和tcp_mem[1]之間,可能處於內存壓力模式。每個tcp socket的緩存上限會減少。若tcp socket的內存小於tcp_rmem[0]/tcp_wmem[0],則內存分配會成功
  • 當整體內存介於tcp_mem[1]和tcp_mem[2]之間,一定處於內存壓力模式下,行爲如上
  • 當整體內存大於tcp_mem[2],則所有內存分配都會失敗
  1. 慢啓動

當主機開始發送數據時,如果發送大量數據可能會引起網絡擁塞。因此引入一個慢啓動的方法,在連接建立以後,設置窗口大小。

初始窗口大小設置規則:

  • mss > 1460*3: 設置爲2MSS
  • mss > 1460: 設置爲3MSS
  • 設置爲4MSS,目前linux中默認爲10MSS。

隨着包的每次往返,發送窗口(cwnd)會以1、2、4指數函數的增長。如果發生擁塞,會導致擁塞加劇,因此引入慢啓動閾值(ssthresh)的概念。當發生擁塞時,慢啓動閾值會設置爲cwnd/2(不小於2MSS)。這時tcp
由慢啓動階段轉移至擁塞避免階段。

ssthresh = max(在外的數據值/2, 2MSS)

丟包發生,重設ssthresh值,同時設置cwnd窗口大小:

  • Tahoe: 設置爲1MSS,但是對於BDP較大的鏈路來說,鏈路利用率低。對於重複ACK引起的丟包,cwnd=ssthresh;
  1. 擁塞避免

慢啓動閾值(ssthresh)初始值爲很大。才傳輸初始階段,首先會進入慢啓動,發生擁塞之後,會確定新的ssthresh。進入擁塞避免階段,cwnd設置爲,以cwnd=cwnd+MSS*MSS/cwnd的方式增長,直至擁塞,在重新設置cwnd,進入慢啓動。

  • cwnd < ssthresh: 慢啓動階段
  • cwnd > ssthresh: 擁塞避免階段
  • cwnd = ssthresh;兩個算法均可使用

TCP Reno引入了快速恢復和快速重傳的算法:

  1. 快速重傳

快速重傳觸發條件:收到三個相同的ACK。接收到收到亂序的數據包,如到達1、2、4、5序號的數據,可以判斷丟失序號爲3的數據,此時,接收端利用3個相同的ACK發給發送端,觸發發送端快速重傳。
快速重傳:

  • ssthresh設置爲cwnd的一半
  • cwnd設置爲ssthresh+3MSS
  • 進入快速恢復階段
  1. 快速恢復

由快速重傳階段進入快速恢復階段,前兩步與快速重傳相同:

  • ssthresh設置爲cwnd的一半
  • cwnd設置爲ssthresh+3MSS
  • 每接收一個重複的ACK,cwnd值暫時增加1MSS
  • 每接收一個好的ACK,將cwnd重設爲ssthresh,快速恢復過程結束

緩存相關參數:

  • tcp_adv_win_scale(Default: 1/centos): 表示應用緩存及TCP接受窗口的比列
    應用緩存: bytes/2^tcp_adv_win_scale 當tcp_adv_win_scale
    應用緩存: bytes-bytes/2^(-tcp_adv_win_scale)
    如上1, TCP接受窗口及應用緩存爲接受緩存的各一半。
  • tcp_app_win: 表示預留maximum (window/2^tcp_app_win, mss) 字節給應用緩存。0表示不預留。

數據傳輸階段

  • netdev_max_backlog(Default: 1000): 設備隊列最大深度
  • tcp_base_mss(Default: 512): 一般是根據MTU值減去IP及tcp頭部大小(共40字節)
  • tcp_mtu_probing(Default: 0): 是否開啓MTU探測,默認關閉

MTU: Path MTU Discovery (PMTUD),發送DF置位的IP報文,如果中間設備迴應ICMP分片不可達的消息,就逐漸減MTU,直到可以部分片到達目的地。如果中間設備不迴應ICMP Type 3就無法使用。

在Centos7.2.1511版本中會經常發生系統crash,查看core dump文件是由於巨頁導致(此版本的bug,7.3已修復),可關閉巨頁:
配置文件位置:
/etc/kernel/mm/transparent_hugepage/enabled:
[always] madvise never:表示使用
always madvise [never]: 關閉
/etc/kernel/mm/transparent_hugepage/defrag:
[always] madvise never:表示使用
always madvise [never]: 關閉



作者:聖地亞哥_SVIP
鏈接:https://www.jianshu.com/p/4ea79f3c39a0
來源:簡書
著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章