很早以前就聽說了c10k,c100k,c1000k等問題,每個問題的解決都是並發編程的一個里程碑。隨着硬件的快速提升,那么10m(千萬)並發連接呢?能否做到?如何做到?會有什么限制?小編對此很好奇,折騰了不少時間,終於有了令人興奮的答案!
下面我們使用https://github.com/yedf/handy庫自帶的例子程序,來跑出一個單機千萬並發連接的實例,先上操作步驟,后面解釋。
准備機器
10m連接,大家的個人電腦肯定無法滿足要求,如果不是在大公司任職,弄個實際的物理機對大家是個奢望。那么怎么辦?我也面臨同樣問題。
現在的雲計算這么發達,還可以按小時計費,一小時的費用也就幾元,那就試試雲計算產品吧。小編先是在阿里雲上測試,但阿里雲的按需付費主機配置不高,費了不少時間,最終只跑到了3m個連接。阿里雲的不行,是主機的配置問題還是程序的問題呢?為了得到最終的結論,我嘗試了其他的雲產品,最終ucloud的雲主機給了我驚喜。
首先創建ucloud主機
ucloud主機(一共需要兩台,一台作為服務器,一台作為客戶端):
. 選擇主機管理的創建主機
. 系統選擇ubuntu14.4 64bit (小編的測試程序是c++11,需要高版本的g++)
. 機型標准版
. 網絡增強一定要選擇開啟 (千萬連接是網絡IO密集型,網絡當然要強大型)
. cpu 16核 內存64G 數據盤0
. 下一步中的網絡類型選擇基礎網絡即可,創建主機之后,需要購買彈性ip,並且綁定到主機
. 價格:小編實驗時(2015年8月),上述的配置,一台僅需7.2元一小時,兩台不到15元
做實驗的時候,大家記得要眼疾手快哦,一小時十幾元,獲得了自己想要的結果就趕緊釋放主機哈
調整系統參數
10m並發連接對系統是個挑戰,需要調整相關的參數
sysctl -w fs.file-max=10485760 #系統允許的文件描述符數量10m
sysctl -w net.ipv4.tcp_rmem=1024 #每個tcp連接的讀取緩沖區1k,一個連接1k
sysctl -w net.ipv4.tcp_wmem=1024 #每個tcp連接的寫入緩沖區1k
#修改默認的本地端口范圍
sysctl -w net.ipv4.ip_local_port_range='1024 65535'
sysctl -w net.ipv4.tcp_tw_recycle=1 #快速回收time_wait的連接
sysctl -w net.ipv4.tcp_tw_reuse=1
sysctl -w net.ipv4.tcp_timestamps=1
#用戶單進程的最大文件數,用戶登錄時生效
echo '* soft nofile 1048576' >> /etc/security/limits.conf
echo '* hard nofile 1048576' >> /etc/security/limits.conf
ulimit -n 1048576 #用戶單進程的最大文件數 當前會話生效
部署程序
下面可以開始部署我們的測試程序了
apt-get update
apt-get install -y screen git make g++ nload iptraf
git clone https://github.com/yedf/handy
cd handy
git checkout 97b5426f91d37
make -j4
運行測試程序
選取一台主機S作為服務器,運行服務器
10m/10m-svr 100 300 10 301 #啟動10個子進程,每個進程分別監聽100-300的端口
選取另一台主機C作為客戶端,運行客戶端,(需要填寫S的內網ip)
#啟動10個客戶端子進程,連接到S的100-300端口,發起10m個連接,在500秒內創建所有的連接,每600秒發送一個心跳,心跳數據為64字節,多進程的管理端口為301
10m/10m-cli <S> 100 300 10000000 500 10 600 64 301
觀察結果
然后,10m連接的建立就不需要更多的步驟啦,使用命令
watch ss -s
我們就可以開始觀察連接的創建進度啦,看着連接漸漸的往上走,超過10k,100k, 1m是不是很有成就感。
說明
並發連接數到達千萬時,有諸多方面的問題需要解決:
. 單進程最大文件數量限制:limit -n 最多能把這個數字修改到1048575,因此單個進程最多能夠打開百萬個文件,千萬並發連接需要千萬個文件描述符,於是我們使用多進程來做到千萬文件的支持
.多進程之間的負載均衡:nginx使用多進程來增加自己的吞吐量,原先采用共享鎖的方式來平衡負載,對核數較多的服務器,較多的進程並沒有達到性能的線性提升。最新的linux內核引入了SO_REUSEPORT選項,該選項可以自動平衡監聽同一端口的多進程,是內核級的解決方案。handy采用該方案,優於nginx的舊有方式(最新的nginx也支持SO_REUSEPORT)。
.測試中客戶端本地端口不夠:讓服務器監聽了200個端口,這樣客戶端連接服務器的每個端口只有50k個連接,然后加大默認的本地端口范圍就可以滿足要求(見前面的服務器系統參數)
測試中如果一次性創建千萬個連接,則絕大部分的連接創建都會失敗,因此讓客戶端每100ms創建2000個連接,提高連接創建的成功率。
系統在運行中,並沒有多少的負載,當然啦,一部分負載跑到底層的hypervisor去了
小編實驗的機器上內存占用大約40G,平均一個連接前后一共用了4k,不多不多
大家可以通過iptraf,nload等工具來查看系統的網絡情況
寫到這里,順便給出我測是的ucloud主機的性能參數吧:
網卡流量最多可以到1.2GBit/s,並非所有時間都到了這么高,並不穩定,一般在800M-1.2G之間波動
tcp收包發包的最高qps是12w/s,多了就上不去了
后續
為了達到千萬條連接,折騰了不少問題,上面只是個大概,有些地方的細節並沒有深入探討。如果大家有興趣,后續會慢慢把其他細節分享出來。
--------2017-12-02更新測試結果-------
最近看見阿里推出了網絡增強型服務器,pps能夠達到450w,於是拿handy的千萬連接進行了測試。在阿里雲上面,按量購買無法購買到最高配的虛機,最高的只購買了下面機型:
網絡增強型,60w pps,16核,64G
命令如下
handy/10m/10m-svr 100 500 16 501 #服務器 handy/10m/10m-cli <S> 100 500 10000000 150 16 170 64 501 # 150s創建1千萬連接
能夠完成千萬條連接,達到的pps大約是20w,進一步增加網絡負載會導致一定程度丟包,這個qps與主機聲稱的60w差距較大,可能跟當時共享的機器有關
網絡增強型,100wpps,8核,32G
命令如下
handy/10m/10m-svr 100 500 16 501 #服務器 handy/10m/10m-cli <S> 100 500 6500000 30 16 40 64 501 # 30s 創建650w連接
32G內存只到650w連接,達到的pps大約是65w,進一步增加網絡負載會導致一定程度丟包
handy的各個測試中,應用的性能都會隨着主機的性能提升而提升,瓶頸主要是在系統的內存和網卡IO處
大家如果有更高配的機型,並且有興趣測一測,歡迎大家把測試結果發給我,合並到本文的結果中