记一次Socket.IO长链服务的性能压测
網(wǎng)易云信IM系統(tǒng)中的Web版使用了Socket.IO實現(xiàn)瀏覽器環(huán)境下的長鏈服務(wù);區(qū)別于常規(guī)的長鏈服務(wù),為該服務(wù)的壓測提出了一些新的挑戰(zhàn),本文總結(jié)了測試過程中的一些收獲供參考。
Part1 測試工具選項
一、工具選型
Gatling
Node.js
JMeter
Java WebSocket
這些工具都是可以支持WebSocket協(xié)議的工具,主要從以下幾個方面進行對比:
上手難易程度
測試資源開銷
和性能測試平臺結(jié)合的難易程度
二、對比過程
對比場景
(1)5000個用戶,每秒鐘發(fā)送100個登錄請求,并保持連接
(2)5000個用戶,每隔5s發(fā)送一條點對點消息,即發(fā)送消息頻率1000
工具使用過程
1. Gatling
工具簡介:Gatling是一款基于Scala 開發(fā)的高性能服務(wù)器性能測試工具,它主要用于對服務(wù)器進行負(fù)載測試,并分析和測量服務(wù)器的各種性能指標(biāo)。
工具語言:Scala語言
工具官網(wǎng):
http://gatling.io/docs/2.0.0-RC2/index.html#
相關(guān)代碼:
遇到的問題:
(1)scale語言比較陌生,腳本編寫時困難較多,目前暫未實現(xiàn)隔一定時間,即發(fā)心跳又發(fā)消息的場景;
(2)無法和性能測試平臺結(jié)合,系統(tǒng)整合成本比較高;
2. Node.js + Socket.IO
工具簡介:
Node.js是一個基于Chrome V8引擎的JavaScript運行環(huán)境。Node.js使用了一個事件驅(qū)動、非阻塞式I/O的模型,使其輕量又高效;而Socket.IO是一個基于Node.js架構(gòu)體系的且原生支持WebSocket協(xié)議,可用作實時通信的軟件包。Socket.IO為跨瀏覽器構(gòu)建實時應(yīng)用提供了完整的封裝,且完全由JavaScript實現(xiàn),語言更容易理解。
工具語言:JavaScript
工具官網(wǎng):
? http://socket.io/docs/
? http://nodejs.cn/
相關(guān)代碼:
遇到問題:
(1)多節(jié)點并發(fā)分布式控制
(2)整合到現(xiàn)有的性能測試平臺
3. JMeter
工具簡介:
JMeter是比較常見的性能測試開源工具,支持多種協(xié)議并且可以自定義java請求,更加靈活。
工具語言:
(1)Java
(2)JMeter xml腳本文件
工具官網(wǎng):
http://jmeter.apache.org/usermanual/get-started.html
https://blog.flood.io/socket-io-and-websockets-with-gatling/
相關(guān)代碼:
遇到問題:
JMeter的工具本上是同步的,如果建立1萬個連接的話,需要啟動1萬個線程處理,因此不適合測試高并發(fā)長連接的場景。
4. Jetty WebSocket Client
工具簡介:
Jetty提供了功能更強的WebSocket API,使用一個公共的核心API供WebSocket的服務(wù)端和客戶端使用。
工具語言: Java
工具官網(wǎng):
http://www.eclipse.org/jetty/
相關(guān)代碼:
遇到問題:
需要自己寫并發(fā)控制
三、對比結(jié)果總結(jié)
因為用來做性能壓測,所以考慮到壓測客戶端需要實現(xiàn)高并發(fā)請求,選擇Gatling和Socket.IO做了簡單的對比測試。
Part2 長鏈服務(wù)端性能問題的定位
如第一部分所述,我們最終選擇用Socket.IO實現(xiàn)了并發(fā)壓測的長鏈客戶端,下面簡單說明下長鏈服務(wù)器端測試的一些收獲;
首先,簡單描述下被測試服務(wù)器的功能
1. 和前端Socket.IO客戶端保持長連接;
2. 解析前端JSON結(jié)構(gòu)的數(shù)據(jù)包,并作二次封裝后抓發(fā)給后端APP服務(wù),并且將后端APP服務(wù)轉(zhuǎn)發(fā)過來的響應(yīng)包轉(zhuǎn)換成為socketio可以識別的json數(shù)據(jù)包,并發(fā)送給客戶端
為此,我們確定該服務(wù)主要的測試點為
1. 測試服務(wù)器可以支撐的最大連接數(shù):該測試點涉及到了TCP連接,以及我們需要注意哪些參數(shù),才可以保證用戶建立的連接數(shù)目不會因為限制而達不到目標(biāo)。
2. 每秒鐘可以解析的包的數(shù)量:該測試點涉及到了網(wǎng)絡(luò)流量,如果已經(jīng)達到了網(wǎng)絡(luò)流量的峰值時,會出現(xiàn)什么樣的問題。
以下是這次測試過程中遇到的一系列問題:
問題1:最大連接數(shù)只能達到65K+
65535,對于程序員來說,這是一個很敏感的數(shù)字,因為一臺服務(wù)器,限制的最大端口號即為65535,所以出現(xiàn)這個問題后:
第一反應(yīng):端口號不夠用了。 分析認(rèn)為Link服務(wù)作為服務(wù)端,對外提供的服務(wù)端口僅有一個,所以不存在服務(wù)端端口號不夠用的情況;
第二反應(yīng):句柄數(shù)不夠用了。文件句柄數(shù)相當(dāng)于文件的標(biāo)識符,建立一條socket鏈接,同樣會使用一個文件句柄,而系統(tǒng)默認(rèn)的單個進程使用的文件句柄為1024;
對于這種需要保持大量連接的服務(wù)來說,一般情況下都是需要修改文件句柄數(shù)的,文件句柄數(shù)修改的方法如下:
?A)查看單個進程使用的最大文件句柄數(shù)的方法:
B)查看當(dāng)前進程打開了多少個文件句柄呢:
C)修改Linux的最大文件句柄數(shù)限制的方法:
? 1)ulimit -n 65535
在當(dāng)前session有效,用戶退出或者系統(tǒng)重新后恢復(fù)默認(rèn)值
? 2)修改用戶下的.profile文件:在.profile文件中添加:ulimit -n 65535
? 只對當(dāng)前用戶有效
?3)修改文件/etc/security/limits.conf,在文件中添加:
(立即生效-當(dāng)前session中運行ulimit -a命令無法顯示)
4)修改文件/etc/sysctl.conf添加:
運行命令:/sbin/sysctl -p 使配置生效
但是修改文件句柄的限制后,該問題依然沒有得到解決。
這個時候想到可以使用dmesg查看系統(tǒng)日志,dmesg命令可以顯示Linux內(nèi)核的環(huán)形緩沖區(qū)信息,可以從中獲得諸如系統(tǒng)架構(gòu)、CPU和掛載的硬件,RAM等運行級別的大量系統(tǒng)信息,因此dmesg命令在設(shè)備故障的診斷方面是非常重要的。通過dmesg,查看到了如下問題:
從上面的信息可見conntrack表滿了,那么conntrack表是做什么的?
nf_conntrack/ip_conntrack用來跟蹤連接條目,會使用一個哈希表來記錄 established 的記錄
nf_conntrack 在 2.6.15 被引入,而 ip_conntrack 在 2.6.22 被移除,如果該哈希表滿了dmesg命令就會出現(xiàn):
nf_conntrack: table full, dropping packet
如何修改conntrack表的大小
到此為止,這個問題我們算是解決了,總結(jié)下,遇到的網(wǎng)絡(luò)相關(guān)的知識點包括 文件句柄 和conntrack表。
問題2:在某些用例場景下,穩(wěn)定連接只能建立3800+
這個問題的前提是某些時候,也就是說偶現(xiàn)的,這種情況基本上可以排除是應(yīng)用程序內(nèi)部的問題。那對于這個問題我們使用了哪些定位手段呢?
1. watch和netstat 兩個命令
watch -d 定期查看一些信息,默認(rèn)是2s;
netstat -st | grep ignored 查看TCP連接的一些統(tǒng)計信息;
可見有SYNs to LISTEN sockets ignored在不停增加,這表明收到連接建立過程中的三次握手的ACK包,但是因各種原因(包括accept隊列滿) 創(chuàng)建socket失敗;
2. ss -ln : 查看進程對應(yīng)的backlog的使用情況
backlog:簡單理解來說,連接已經(jīng)在TCP層建立成功(完成了三次握手的過程)但是還沒有被應(yīng)用程序所接受,這種情況下,該連接會存放到backlog這樣一個緩沖隊列內(nèi)
通過上面這個命令可以看到應(yīng)用程序的backlog隊列已經(jīng)滿了,但是即便把這個值調(diào)整為1024,該隊列還是會滿的。
到這兒,我們的定位過程陷入了僵局,下一步該怎么定位呢?這期間我們查看了內(nèi)存信息,CPU使用情況等,均沒有找對地方;但是在定位過程中,我們發(fā)現(xiàn),有時候JStack、JProfiler等工具都無法連上該服務(wù)了。
突然想到文件句柄是不是滿了?又執(zhí)行了以下幾條命令:
/proc/{pid}這個目錄下了對應(yīng)了所有在運行的進程的相關(guān)信息,
通過查看/proc/{pid}/fd目錄下的個數(shù)我們可以看到當(dāng)前進程使用的文件句柄數(shù)有多少。
通過查看limits文件里面的值,可以看到系統(tǒng)對該進程的一些限制,不幸的是,出現(xiàn)這個問題的時候,max open files這個值被限制為了4096。
調(diào)整該值之后最終解決了這個問題
問題3:大量的連接建立不成功
當(dāng)我們解決了一個又一個的問題后,突然發(fā)現(xiàn)高壓力下存在大量的連接建立不成功的問題,主要表現(xiàn)在:
原來:每秒鐘500個連接建立的請求時,5w個用戶都可以建立成功;
現(xiàn)在:每秒鐘500個連接建立的請求時,5w個用戶只有4w左右的連接可以建立成功;
這個問題也花費了不短的時間,我們使用了各種命令查看各種網(wǎng)絡(luò)指標(biāo)
通過netstat查看到send-q中有大量的消息堆積;
通過sar查看到有大量的重傳;
總結(jié)起來還是TcpDump抓包比較效果更好,從測試的開始,我們就只抓這一條鏈路上的包,且發(fā)送方和接收方,雙方都抓包:
然后通過Wireshark分析,可以看到
發(fā)送方/客戶端:存在一定時間段發(fā)送出大量的重傳包
接收方/服務(wù)端:客戶端發(fā)送大量重傳包的這個過程中,什么都沒有收到
這基本說明網(wǎng)絡(luò)有問題
然后我們通過netperf測試了下網(wǎng)絡(luò)帶寬的情況,發(fā)現(xiàn)這兩臺機器之間的網(wǎng)絡(luò)上限只有21Mb,而且測試過程中的網(wǎng)絡(luò)請求量是超過這個值的。由于是在云主機環(huán)境上,通過咨詢云網(wǎng)絡(luò)相關(guān)的同事發(fā)現(xiàn),問題原因是因為云主機之間的網(wǎng)絡(luò)QoS開啟限制導(dǎo)致的,限制了每臺云主機之間的網(wǎng)絡(luò)帶寬最高位21Mb,超過這個值則會被丟包。
TCP的鏈接狀態(tài)圖
最后總結(jié)下在定位類似的網(wǎng)絡(luò)問題中一些常規(guī)的命令、工具和關(guān)注的方向
可以使用以下命令
推薦使用以下工具
重點關(guān)注以下指標(biāo)
點擊下方“閱讀原文”,技術(shù)干貨
↓↓
總結(jié)
以上是生活随笔為你收集整理的记一次Socket.IO长链服务的性能压测的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【视频技术解读】编解码的理论和实践
- 下一篇: 视频直播关键技术:流畅、拥塞和延时追赶