io_submit,io_getevents可能被阻塞的原因

libaio雖然是異步direct-io,但某些情況下仍然會被阻塞。

測試環境,
硬盤信息:ATA HGST硬盤,6.0 Gbps SATA HDD,容量5.46TiB(6.00TB);
邏輯盤信息:RAID0,容量5.457TiB,條帶大小256KB,讀策略Read ahead,寫策略Write back;
[root@localhost ~]# lsscsi
[0:2:0:0]    disk    AVAGO    MR9361-8i        4.68  /dev/sda

fio測試命令:
./fio -ioengine=libaio -bs=8k -direct=1 -numjobs 16 -rw=read -size=10G -filename=/dev/sda2 -name="Max throughput" -iodepth=128 -runtime=60

查看系統調用耗時(如果被阻塞,libaio系統調用耗時會比較大,'--duration 1'表示如果系統調用耗時大於1ms則輸出):
perf trace -p `pidof -s fio` --duration 1

查看fio線程被調度出去的原因(即因libaio系統調用被阻塞而被調度出去):
offcputime -K -p `pgrep -nx fio`

sda請求隊列長度128(默認):
cat  /sys/block/sda/queue/nr_requests  

由於塊設備層的request資源有限(默認128,request的申請與擁塞控制原理見之前的博文"Linux IO併發擁塞控制機制分析-1/2/3"),在fio多任務測試下,由於request資源不夠用,導致io_submit系統調用被阻塞在request資源上。

在nr_requests調整爲256後,系統調用io_submit幾乎不阻塞,在修改爲512後,完全不阻塞;
但隨着nr_requests加大,io_getevents會越來越阻塞,與io_submit的阻塞情況完全相反,詳細測試結果見下面的貼圖。

nr_requests = 128時的測試日誌:

nr_requests = 256時的測試日誌:

關於nr_requests加大,io_getevents會變得阻塞,先看下io_getevents的主要邏輯,io_getevents會調到read_events函數來讀取aio的完成events:

 aio完成後,註冊的aio回調函數aio_complete(在bio的回調中被調用)被調用,在該函數中會判斷當前aio上下文的等待隊列(ctx->wait)是否爲空,若不空,就喚醒等待隊列中的線程,因爲aio_complete被調用時就表示已經有aio完成了,所以當前aio上下文的ring buffer必然不空,所以可以喚醒等待該event的線程:

aio_complete函數的最後部分:

所以本測試中,當nr_requests加大,io_getevents會變得阻塞,是因爲IO提交流程中request資源充足,io_submit的IO提交流程沒有阻塞,造成提交給後端設備的io會很多,後端設備處理IO的壓力變大,IO完成速率變慢,所以io_getevents需要更多的時間睡眠等待aio完成event。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章