TCP的keepalive
前端
keepalive是設置在操做系統級別,做用於到本機的鏈接。在必定時間內對遠程主機發送TCP探測報文用於探測對方是否存活。
後端
上圖2個場景是最多見的,可是針對於keepalive的問題是同樣的。無非就是客戶端和最終的WEB服務器直接多了中間設備。這會怎麼樣呢?正常狀況下不會有問題,可是客戶端把請求發送給Nginx,Nginx的後端Tomcat須要必定時間才能返回結果,超過90秒就會有問題,若是使用LVS作負載均衡看到的現象就是90秒內沒有返回則LVS會把客戶端到Nginx的鏈接斷開。由於LVS默認保持的TCP會話爲90秒。超過90秒沒有TCP傳輸,LVS就會給客戶端和Nginx發送RESET報文斷開鏈接。這樣作的緣由其實就是節省資源關閉空閒鏈接和保護後端。遇到這種請求你只須要在LVS上開啓keepalive就好,固然你的Nginx上也要設置,由於真正的後端服務器是Tomcat等應用程序。瀏覽器
keepalive是什麼:bash
鏈接創建之後,若是應用程序或上層協議一直不發數據或者間隔好久才發一次,那麼如何肯定創建鏈接的雙方還存在呢?在TCP協議的設計中,在一段時間以後,TCP自動發送一個空數據報文給對方,若是對方迴應了這個報文說明還在線,那麼繼續保持鏈接,若是對方沒有迴應而且通過屢次重試發送以後依然沒有迴應,則認爲對方不在線能夠關閉鏈接。服務器
如何開啓keepalive:網絡
keepalive在Linux系統上沒有一個全局開關來開啓或關閉這個功能覺得它是TCP的一個特性,因此不能簡單的說默認是否是開啓。由於開啓這個功能是須要應用程序在註冊使用socket時單獨設置的,Linux上關於TCP的內核參數只是會影響keepalive的行爲。注意:啓動Nginx或者LVS等任何網絡服務都會使用socket。併發
sysctl -a | grep net.ipv4.tcp_keepalive
參數 |
含義 |
net.ipv4.tcp_keepalive_intvl |
表示發送前一個探測報文和後一個探測報文的間隔時間 |
net.ipv4.tcp_keepalive_probes | 表示探測次數,超過這個次數仍是探測失敗則關閉鏈接 |
net.ipv4.tcp_keepalive_time | 表示TCP鏈接多少秒以後沒有數據報文傳輸就啓動探測報文 |
代碼體現負載均衡
setsockopt函數是設置與套接字有關的選項,它裏面的選項有不少,下面的SO_KEEPALIVE表示長鏈接。
socket
//使用長鏈接 if(setsockopt(s,SOL_SOCKET,SO_KEEPALIVE,(void*)&keepAlive,sizeof(keepAlive)) == -1) { //if error } //設置選項 if(setsockopt(s,SOL_TCP,TCP_KEEPIDLE,(void *)&keepIdle,sizeof(keepIdle)) == -1) { //if error } if(setsockopt(s,SOL_TCP,TCP_KEEPINTVL,(void *)&keepInterval,sizeof(keepInterval)) == -1) { //if error } if(setsockopt(s,SOL_TCP,TCP_KEEPCNT,(void *)&keepCount,sizeof(keepCount)) == -1) { //if error }
socket選項 |
對應的內核參數 |
TCP_KEEPCNT |
net.ipv4.tcp_keepalive_probes |
TCP_KEEPIDLE |
net.ipv4.tcp_keepalive_time |
TCP_KEEPINTVL |
net.ipv4.tcp_keepalive_intvl |
Linux系統對這三個參數有默認設置,你的應用程序能夠覆蓋自行設置須要的值。tcp
HTTP的keep-alive
HTTP的keep-alive和TCP的不是一個概念,一個頁面上有幾百個元素一個元素其實就是一個HTTP請求,若是每一個請求都打開和關閉一次TCP鏈接那至關消耗資源,對於HTTP的Keep-Alive來講就是TCP鏈接的複用,一個請求完畢後服務器不關閉鏈接而是等待一段時間接收瀏覽器可能發來的以後的請求。一般瀏覽器在完成第一個請求以後會立刻發送第二個請求,因此這樣會節省不少資源消耗。
Nginx如何開啓TCP層的KeepAlive呢?
從TCP層面上Nginx要關係和client和後端upstream的KeepAlive,同時從HTTP層面Nginx還須要關係client和upstream的keep-alive。
參數 |
說明 |
so_keepalive |
用於設置監聽套接字的TCP KeepAlive行爲,若是隻是設置on而不設置具體參數則使用操做系統默認設置 on|off|[keepidle]:[keepintvl]:[keepcnt] on表示開啓 off表示關閉 keepidle表示等待時間 keepintvl表示探測報文發送間隔時間 keepcnt表示探測報文發送次數 以上參數只能用一個。該參數屬於listen的輔助參數,在server端中,配置完監聽端口可使用這個參數。 listen 80 so_keepalive=on,若是要設置時間能夠這樣設置 listen 80 so_keepalive=30::10 在Nginx中針對TCP層的keepalive只有這一個。 |
Nginx如何開啓針對前端客戶端的HTTP層的keep-alive?
參數 |
說明 |
keepalive_timeout |
0表示關閉keepalive,設置大於0的值表示保持連接多少秒,這個值不能解決TCP層面的KeepAlive問題 |
keepalive_requests |
一個長鏈接創建以後,Nginx會給客戶端計數,達到數值時則強制關閉鏈接,致使Nginx服務器出現TIME_WAIT。默認100,對於QPS比較高的場景這個值能夠設置大一點。 |
Nginx如何開啓針對後端服務器的HTTP層的keep-alive?
參數 |
說明 |
keepalive |
這個是在upstream中設置的。設置upstream到後端服務器的最大空閒長鏈接數量,當達到數量時則收回,它並不影響到後端的併發數量。若是設置的值比較小對於不一樣時段的請求和響應數量均衡的場景沒有影響,可是對於不一樣時段請求數量不一樣就有影響。因此建議設置大一點。這個的計算要和QPS和RT來計算出須要多少長鏈接數量,好比10000QPS,每一個請求0.1秒。1/0.1=10, 10000/10=1000,也就是須要1000個長鏈接,不過一般能夠設置到10%-30%。 |
總結
HTTP的keep-alive是爲了讓TCP鏈接存活久一點以便複用鏈接完成更多HTTP請求,提升鏈接利用率。
TCP的Keepalive是一種TCP鏈接的探測機制,使其一直保持可用。