引言
io_uring是Linux內(nèi)核在v5.1引入的一套異步IO接口,隨著其迅速發(fā)展,現(xiàn)在的io_uring已經(jīng)遠(yuǎn)遠(yuǎn)超過了純IO的范疇。從Linux v5.3版本開始,io_uring陸續(xù)添加了網(wǎng)絡(luò)編程相關(guān)的API,對(duì)用戶提供sendmsg、recvmsg、accept、connect等接口的異步支持,將io_uring的生態(tài)范圍擴(kuò)大到了網(wǎng)絡(luò)領(lǐng)域。
另外從Linux v5.7開始,io_uring對(duì)這些異步接口提供FAST POLL機(jī)制,用戶無需再使用像select、event poll等多路復(fù)用機(jī)制來監(jiān)聽文件句柄,只要把讀寫請(qǐng)求直接丟到io_uring的submit queue中并提交,當(dāng)文件句柄不可讀寫時(shí),內(nèi)核會(huì)主動(dòng)添加poll handler,當(dāng)文件句柄可讀寫時(shí)主動(dòng)調(diào)用poll handler再次下發(fā)讀寫請(qǐng)求,從而減少系統(tǒng)調(diào)用次數(shù)提高性能。
上一篇我們初探了 io_uring 用于網(wǎng)絡(luò)的編程模型以及 echo server benchmark 下的性能表現(xiàn),這篇文章我們將基于通用應(yīng)用 nginx 實(shí)戰(zhàn)。
Nginx io_uring 代碼優(yōu)化
Nginx是一款輕量級(jí)的Web服務(wù)器、反向代理服務(wù)器,由于它的內(nèi)存占用少,啟動(dòng)極快,高并發(fā)能力強(qiáng),在互聯(lián)網(wǎng)項(xiàng)目中廣泛應(yīng)用。
從架構(gòu)上看,Nginx由一個(gè)master和多個(gè)worker進(jìn)程組成,多個(gè)worker之間不需要加鎖,獨(dú)立處理與client的連接和網(wǎng)絡(luò)請(qǐng)求。worker是一個(gè)單線程大循環(huán),這與上一篇“你認(rèn)為 io_uring 只適用于存儲(chǔ) IO?大錯(cuò)特錯(cuò)!”文章中描述的 echo server 模型基本一致。
基于event poll的編程模型
event poll是Nginx在Linux下的默認(rèn)事件模型。
event poll事件模型把listen fd以及新建連接的sock fd都注冊(cè)進(jìn)event poll中,當(dāng)這些fd上有數(shù)據(jù)可讀時(shí),等待在epoll_wait()的worker進(jìn)程會(huì)被喚醒,調(diào)用相應(yīng)的回調(diào)函數(shù)進(jìn)行處理,這里的recv、writev請(qǐng)求都為同步請(qǐng)求。
基于io_uring的編程模型
前面提到,io_uring的FAST POLL機(jī)制允許數(shù)據(jù)在未ready的情況下就直接下發(fā),不需要再把普通連接的fd注冊(cè)進(jìn)event poll。另外這里的讀寫請(qǐng)求通過io_uring異步下發(fā),處理流程大致如下:
事實(shí)上,accept()也可以采取FAFST POLL機(jī)制,無需等待listen_fd數(shù)據(jù)可讀就直接下發(fā),以減少系統(tǒng)調(diào)用次數(shù)。但在調(diào)試過程中發(fā)現(xiàn)這樣accept()失敗概率大大增加,而每次失敗的accept()都會(huì)帶來一次無效的sock內(nèi)存申請(qǐng)和釋放,這個(gè)開銷較大,因此依然采用類似event poll的方式來偵聽listen fd。后續(xù)針對(duì)這塊可以做一些優(yōu)化。
測(cè)試結(jié)果
測(cè)試環(huán)境
測(cè)試機(jī)器
CPU: Intel(R) Xeon(R) CPU E5-2682 v4 @ 2.50GHz 64邏輯核
server cmdline添加:mitigation=on
nginx配置
user root;http { access_log off; server { access_log off; // 關(guān)閉access log,否則會(huì)寫日志,影響測(cè)試 location / { return 200; // 不讀本地文件,直接返回200 } }}
benchmark
使用輕量級(jí)HTTP性能測(cè)試工具wrk進(jìn)行壓測(cè)。
測(cè)試命令
長(zhǎng)連接 wrk -c $connection -t $thread -d 120 $url短連接wrk-c$connection-t$thread-H"Connection:Close"-d120$url
測(cè)試結(jié)果
長(zhǎng)連接
? connection=1000,thread=200, 測(cè)試server上不同worker數(shù)目性能。
worker數(shù)目在8以下時(shí),QPS有20%左右的提升。隨著worker數(shù)目增大,CPU不成為瓶頸,收益逐漸降低。
server單worker,測(cè)試client端不同連接數(shù)性能(thread取默認(rèn)數(shù)2)。
可以看到單worker情況下,500個(gè)連接以上,QPS有20%以上的提升。從系統(tǒng)調(diào)用數(shù)目上看,io uring的系統(tǒng)調(diào)用數(shù)基本上在event poll的1/10以內(nèi)。
短連接
? connection=1000,thread=200, 測(cè)試server上不同worker數(shù)目性能。
短連接場(chǎng)景,io uring相對(duì)于event poll非但沒有提升,甚至在某些場(chǎng)景下有5%~10%的性能下降。究其原因,除了io uring框架本身帶來的開銷以外,還可能跟io uring編程模式下請(qǐng)求批量下發(fā)而帶來的延遲有關(guān)。
總結(jié)及下一步工作
從筆者目前的測(cè)試來看,io_uring在網(wǎng)絡(luò)編程方面的優(yōu)化更適合長(zhǎng)連接場(chǎng)景,在長(zhǎng)連接場(chǎng)景下最高有20%多的提升。短連接場(chǎng)景還有待優(yōu)化,主要考慮以下兩方面:
? io uring本身框架開銷的優(yōu)化,當(dāng)然這個(gè)優(yōu)化對(duì)長(zhǎng)連接同樣適用。
? 針對(duì)短連接的優(yōu)化,如針對(duì)accept()請(qǐng)求,先檢查是否有數(shù)據(jù)可讀,避免無效內(nèi)存申請(qǐng)釋放;多個(gè)accept()一起下發(fā)等。
nginx 和 echo server 等優(yōu)化實(shí)踐相關(guān)內(nèi)容(包含源代碼),我們都已經(jīng)在 OpenAnolis 社區(qū)高性能存儲(chǔ) SIG 開源(openanolis.org)。也歡迎大家積極參與討論和貢獻(xiàn),一起探索 io_uring 的高性能之路。
責(zé)任編輯:xj
原文標(biāo)題:面對(duì)疾風(fēng)吧!io_uring 優(yōu)化 nginx 實(shí)戰(zhàn)演練
文章出處:【微信公眾號(hào):Linuxer】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
-
Linux
+關(guān)注
關(guān)注
87文章
11331瀏覽量
209992 -
IO接口
+關(guān)注
關(guān)注
0文章
31瀏覽量
13431 -
nginx
+關(guān)注
關(guān)注
0文章
152瀏覽量
12195
原文標(biāo)題:面對(duì)疾風(fēng)吧!io_uring 優(yōu)化 nginx 實(shí)戰(zhàn)演練
文章出處:【微信號(hào):LinuxDev,微信公眾號(hào):Linux閱碼場(chǎng)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論