TCP 連線與TCP keep alive 保活檢測機制
生產環境中一臺2核4G的linux伺服器TCP連線數時常保持在5-7w間徘徊,檢視日誌每秒的請求數也就100-200,怎麼會產生這麼大的TCP連線數。檢查了下客戶端上行的HTTP協議,Connection 頭欄位是Keep-Alive,並且客戶端在請求完之後沒有立即關閉連線。而服務端的設計也是根據客戶端來的,客戶端上行如果Connection:Keep-Alive,服務端是不會主動關閉連線的。在客戶端與服務端互動比較頻繁的時候,這樣的設計還是比較合理的,可以減少TCP的重複握手。顯然如果只互動一次,就沒有這個必要了。我們的生產環境就屬於這種情況。客戶端在請求響應完之後就得立即釋放連線,上程式碼:
public static void send(request req){ InputStream input=null; ByteArrayOutputStream out=null; HttpClient client=new DefaultHttpClient(); try{ HttpPost post=new HttpPost("http://ip:port"); post.setHeader("User-Agent", "Mozilla/5.0 (Linux; U; Android 2.2.1; en-us; Nexus One Build/FRG83) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1"); post.setHeader("Expect", "100-continue"); post.setHeader("Client_IP", "ip"); post.addHeader("Connection","close"); HttpEntity entity=new ByteArrayEntity(encoder.encodeXip(req)); post.setEntity(entity); HttpResponse resp=client.execute(post); HttpEntity content = resp.getEntity(); input=content.getContent(); out=new ByteArrayOutputStream(); byte by[]=new byte[1024]; int len=0; while((len=input.read(by))!=-1){ out.write(by, 0, len); } System.out.println(new String(out.toByteArray())); }catch(Exception e){ e.printStackTrace(); return null; }finally{ try { out.close(); input.close(); client.getConnectionManager().shutdown();//主動釋放連線 } catch (IOException e) { e.printStackTrace(); } } }
解決方法好像很簡單。但現實環境是客戶端有很多版本,並且已經執行在客戶手中了,改客戶端來減少伺服器TCP連線數,是一件比較耗時間的活。沒有辦法只能從服務端自身解決,解決方法只能從服務端主動關閉TCP連線。
一開始不要著急從程式層面去看問題,從作業系統角度看能否解決問題,簡單為linux核心增加了一些keep-alive的引數,發現也能降低一些TCP連線數。操作很簡單,往 /etc/sysctl.conf 配置檔案裡增加如下引數:
最後 sysctl -p 使之生效。net.ipv4.tcp_keepalive_intvl = 3 net.ipv4.tcp_keepalive_probes = 2 net.ipv4.tcp_keepalive_time = 6
上面引數的意思是說,客戶端與服務端空閒時間達到6秒之後,服務端每隔3秒檢測下客戶端存活情況,一共檢測兩次,如果在6+3*2=12之內客戶端程序退出了,服務端就會主動關閉該連線。服務端檢測客戶端存活是通過傳送基於TCP的keep alive報文,客戶端程序如果沒有退出,就會發送確認keep alive的響應報文。如圖wireshark中報文:
剛調整引數的那幾天沒有注意,後來才發現這樣的操作會帶來頻寬的嚴重浪費,以前只要1M左右的響應頻寬,現在要5M左右,都是成本啊,雖然是公司出錢。
因為我們的客戶端存活時間比較長,TCP的keep alive保活機制能回收的TCP連線數是比較有限的,但是每隔6秒的報文卻能讓伺服器頻寬翻上好幾倍,得不償失啊。
沒辦法只能從程式設計方面在想想辦法,調整服務端的設計,原先服務端不主動去關閉連線,而是根據客戶端上行Connection的狀態決定是否關閉,新的設計方案就是服務端可以配置連線的狀態,如果服務端配置了Connection:close,服務端優先採用配置資訊,如果沒有配置,則還是由客戶端上行來決定連線狀態。
服務端是java寫的,基於netty的通訊框架。netty裡keep alive相關的引數只有一個選項配置,相關程式碼如下:
this.bootstrap.setPipelineFactory(new ChannelPipelineFactory()
{
public ChannelPipeline getPipeline()
throws Exception
{
ChannelPipeline pipeline = new DefaultChannelPipeline();
pipeline.addLast("codec", new HttpServerCodec());
pipeline.addLast("aggregator", new HttpChunkAggregator(maxContentLength));
pipeline.addLast("handler", new HttpRequestHandler());
return pipeline;
}
});
this.bootstrap.setOption("allIdleTime", Integer.valueOf(this.idleTime));
this.bootstrap.setOption("child.keepAlive", Boolean.valueOf(true));
this.bootstrap.setOption("child.tcpNoDelay", Boolean.valueOf(true));
this.bootstrap.setOption("child.soLinger", Integer.valueOf(-1));
this.bootstrap.setOption("child.sendBufferSize", Integer.valueOf(-1));
this.bootstrap.setOption("child.keepAlive", Boolean.valueOf(true)); 這行程式碼只配置是否啟用TCP保活檢測,如果啟用了,多久檢測一次還是取決於作業系統本身。說白了,還是跟編輯 sysctl.conf檔案的效果一樣,因為它們都是從TCP層的檢測。netty從應用層主動關閉連線的話,可以簡單增加一個監聽器,程式碼如下:
ChannelFuture future = channel.write(response);
if ((!HttpHeaders.isKeepAlive(response)) || (!response.containsHeader("Content-Length"))) {
future.addListener(ChannelFutureListener.CLOSE);
}
當channel write操作完成時,CLOSE監聽器主動close掉channel。問題基本解決,後來發現其實也可以通過增加一層nginx代理解決問題,nginx通過短連線與後端進行互動,與前端保持長連線,不過不是很清楚nginx長連線的檢測機制,但根據生產環境表現出的現象,肯定不是用作業系統引數。
TCP保活機制可以引數這篇文章 http://www.blogjava.net/yongboy/archive/2015/04/14/424413.html
相關推薦
TCP 連線與TCP keep alive 保活檢測機制
生產環境中一臺2核4G的linux伺服器TCP連線數時常保持在5-7w間徘徊,檢視日誌每秒的請求數也就100-200,怎麼會產生這麼大的TCP連線數。檢查了下客戶端上行的HTTP協議,Connection 頭欄位是Keep-Alive,並且客戶端在請求完之後沒有立即關閉連線
HTTTP及TCP的超時以及KEEP-ALIVE機制小結
詳解 int 客戶 博客 abc key html htttp cee 一、HTTP的超時和Keep Alive HTTP Keepalive 機制是http 1.1中增加的一個功能。 在HTTP 1.0中,客戶端每發起一個http 請求,等收到接收方的應答之後就斷開T
TCP keepalive長連接心跳保活
line 成功 https 頻率 之前 bin 發現 nbsp 進入 比如:客戶端與服務端進行握手時,經常無法握手成功,收不到回復; 需要建立保活機制。 1. 服務端Linux服務器新增系統內核參數配置。 在/etc/sysctl.conf文件中再添加如: #允許的持
一種動態跟蹤TCP連線與程序相關性的方法
描述 TCP連線跟蹤是網路流控和防火牆中的一項重要的基礎技術,當運用於主機時,連線必與程序相關聯,要麼是主動發出的,要麼是被動接受的,當後代程序被動態建立時,由於檔案描述符的繼承,一個連線就會被這個程序樹中的所有程序共享;當一個程序發出或接受多個連線時,就擁有了多個連線。本方法可用於網路安
TCP連線與斷開詳解(socket通訊)
一、TCP資料報結構以及三次握手 TCP(Transmission Control Protocol,傳輸控制協議)是一種面向連線的、可靠的、基於位元組流的通訊協議,資料在傳輸前要建立連線,傳輸完畢後還要斷開連線。 客戶端在收發資料前要使用 connect() 函式和伺服
深入理解與使用keep-alive(配合router-view緩存整個路由頁面)
標簽 生命周期 ted 有意 ex18 存在 實例 也會 第一次 在搭建 vue 項目時,有某些組件沒必要多次渲染,所以需要將組件在內存中進行‘持久化‘,此時 <keep-alive> 便可以派上用場了。 <keep-alive> 可以使被包含的組件
TCP/IP(7)-TCP Server與TCP Client(linux套接字)
前面幾篇文章談到的關於TCP/IP應用層以下的協議,這些協議最終是在作業系統核心中實現的,套接字API是unix系統用於網路連線的介面,後來被移植到windows系統中,就有了winsock。 TCP的Client/Server模式 在TCP/IP協議中
當 HTTP 連線池遇上 KeepAlive 時 http的keep-alive和tcp的keepalive區別
https://mp.weixin.qq.com/s?__biz=MzUzMTA2NTU2Ng==&mid=2247485891&idx=2&sn=82dd4786e38e23a10fa9210745c99130&chksm=fa497672cd3eff64fb06873ba9
淺談Http長連線和Keep-Alive以及Tcp的Keepalive
Keep-Alive模式: 我們知道Http協議採用“請求-應答”模式,當使用普通模式,即非Keep-Alive模式時,每個請求/應答,客戶端和伺服器都要新建一個連線,完成之後立即斷開連線;當使用Ke
TCP keep-alive - 判斷TCP鏈路的連接情況
pan 內連接 soc 當前 簡單的 span lose keep 數據傳輸 TCP 是面向連接的 , 在實際應用中通常都需要檢測對端是否還處於連接中。如果已斷開連接,主要分為以下幾種情況: 1. 連接的對端正常關閉,即使用 closesocket 關閉
TCP保活:心跳包/乒乓包/SO_KEEPALIVE
引言: 長連線斷開後一直佔用系統資源,可以通過心跳包判斷連線是否斷開;使用心跳包檢測到連線已經死了,就斷開連線。 總的來說,心跳包主要也就是用於長連線的保活和斷線處理。一般的應用下,判定時間在30-40秒比較不錯。如果實在要求高,那就在6-9秒。 TCP保活機
TCP長連線與短連線、心跳機制
1. TCP連線 當網路通訊時採用TCP協議時,在真正的讀寫操作之前,server與client之間必須建立一個連線,當讀寫操作完成後,雙方不再需要這個連線時它們可以釋放這個連線,連線的建立是需要三次握手的,而釋放則需要4次握手,所以說每個連線的建立都是需要資源消耗和時間消耗的。 經典的三
TCP/IP學習筆記(10)--TCP連線的建立與終止
TCP連線的建立可以簡單的稱為三次握手,而連線的中止則可以叫做四次握手。 TCP是一個面向連線的協議,所以在連線雙方傳送資料之前,都需要首先建立一條連線。這和前面講到的協議完全不同。前面講的所有協議都只是傳送資料而已,大多數都不關心傳送的資料是不是送到,UDP尤其明顯,從
深入理解TCP/IP協議-TCP建立與終止連線
轉載自 深入理解TCP/IP協議-TCP建立與終止連線 一、引言 TCP 是一個面向連線的協議。無論哪一方向另一方傳送資料之前,都必須先在雙方之間建立一條連線。連線建立與終止的狀態變化圖如下: 二、三次握手建立連線
TCP/IP協議--10 TCP 連線的建立與終止
TCP連線的建立可以簡單的稱為三次握手,而連線的中止則可以叫做四次握手。 TCP是一個面向連線的協議,所以在連線雙方傳送資料之前,都需要首先建立一條連線。這和前面講到的協議完全不同。前面講的所有協議都只是傳送資料而已,大多數都不關心傳送的資料是不是送到,UDP尤其明顯,從程式設計的角度來說,UD
(轉)lwip TCP client & FreeRTOS 開啟TCP 的 保活機制 LWIP_TCP_KEEPALIVE==1
參考大神教程:http://blog.sina.com.cn/s/blog_62a85b950101aw8x.html 老衲五木 :http://blog.sina.com.cn/s/blog_62a85b950102vrr4.html
建立與釋放TCP連線的過程
首先給出標準的書上的概念,摘自 謝希仁著《計算機網路第6版》: 三次握手的全過程: 四次揮手的全過程: 以下是經過總結、提取後在筆試題和麵試題的回答: 三次握手: 1.客戶端傳送SYN請求,進入SYN-SEND(同步傳送狀態) 2.服務端收到請求,
TCP/IP學習筆記(10)-tcp連線的建立與終止
TCP連線的建立可以簡單的稱為三次握手,而連線的中止則可以叫做四次握手。 TCP是一個面向連線的協議,所以在連線雙方傳送資料之前,都需要首先建立一條連線。這和前面講到的協議完全不同。前面講的所有協議都只是傳送資料而已,大多數都不關心
Python--長連線與短連結(TCP)
HTTP的長連線和短連線本質上是TCP長連線和短連線 1.短連結 瀏覽器和伺服器每進行一次HTTP操作,就建立一次連線,但任務結束就中斷連線。如果客戶端瀏覽器訪問的某個HTML或其他型別的 Web頁中包含有其他的Web資源,如JavaScript檔案、影象檔案
TCP連線的狀態與關閉方式,及其對Server與Client的影響
1. TCP連線的狀態 首先介紹一下TCP連線建立與關閉過程中的狀態。TCP連線過程是狀態的轉換,促使狀態發生轉換的因素包括使用者呼叫、特定資料包以及超時等,具體狀態如下所示: CLOSED:初始狀態,表示沒有任何連線。 LISTEN:Server端的某個Socket正在監聽來自遠