加入星計劃,您可以享受以下權(quán)益:

  • 創(chuàng)作內(nèi)容快速變現(xiàn)
  • 行業(yè)影響力擴散
  • 作品版權(quán)保護
  • 300W+ 專業(yè)用戶
  • 1.5W+ 優(yōu)質(zhì)創(chuàng)作者
  • 5000+ 長期合作伙伴
立即加入
  • 正文
    • 內(nèi)核態(tài)和用戶態(tài)
    • 內(nèi)核態(tài)和用戶態(tài)是怎么控制數(shù)據(jù)傳輸?shù)模?/span>
    • 什么是 DMA ?
    • 那到底什么是 DMA 技術(shù)?
    • 零拷貝技術(shù)實現(xiàn)的方式
    • 為啥要聊PageCache?
    • 大文件傳輸怎么做?
  • 相關(guān)推薦
  • 電子產(chǎn)業(yè)圖譜
申請入駐 產(chǎn)業(yè)圖譜

一文讀懂計算機內(nèi)核態(tài)、用戶態(tài)和零拷貝技術(shù)

2023/02/12
1439
閱讀需 24 分鐘
加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點資訊討論

存儲介質(zhì)的性能

話不多說,先看一張圖,下圖左邊是磁盤到內(nèi)存的不同介質(zhì),右邊形象地描述了每種介質(zhì)的讀寫速率。一句話總結(jié)就是越靠近cpu,讀寫性能越快。了解了不同硬件介質(zhì)的讀寫速率后,你會發(fā)現(xiàn)零拷貝技術(shù)是多么的香,對于追求極致性能的讀寫系統(tǒng)而言,掌握這個技術(shù)是多么的優(yōu)秀~

上圖是當(dāng)前主流存儲介質(zhì)的讀寫性能,從磁盤到內(nèi)存、內(nèi)存到緩存、緩存到寄存器,每上一個臺階,性能就提升10倍。如果我們打開一個文件去讀里面的內(nèi)容,你會發(fā)現(xiàn)時間讀取的時間是遠大于磁盤提供的這個時延的,這是為什么呢?問題就在內(nèi)核態(tài)和用戶態(tài)這2個概念后面深藏的I/O邏輯作怪。

內(nèi)核態(tài)和用戶態(tài)

內(nèi)核態(tài):也稱為內(nèi)核空間。cpu可以訪問內(nèi)存的所有數(shù)據(jù),還控制著外圍設(shè)備的訪問,例如硬盤、網(wǎng)卡、鼠標(biāo)、鍵盤等。cpu也可以將自己從一個程序切換到另一個程序。

用戶態(tài):也稱為用戶空間。只能受限的訪問內(nèi)存地址,cpu資源可以被其他程序獲取。

計算機資源的管控范圍

坦白地說內(nèi)核態(tài)就是一個高級管理員,它可以控制整個資源的權(quán)限,用戶態(tài)就是一個業(yè)務(wù),每個人都可以使用它。那計算機為啥要這么分呢?且看下文......

由于需要限制不同的程序之間的訪問能力, 防止他們獲取別的程序的內(nèi)存數(shù)據(jù), 或者獲取外圍設(shè)備的數(shù)據(jù), 并發(fā)送到網(wǎng)絡(luò)。CPU劃分出兩個權(quán)限等級:用戶態(tài)和內(nèi)核態(tài)。

32 位操作系統(tǒng)和 64 位操作系統(tǒng)的虛擬地址空間大小是不同的,在 Linux 操作系統(tǒng)中,虛擬地址空間的內(nèi)部又被分為內(nèi)核空間和用戶空間兩部分,如下所示:

通過這里可以看出:

32 位系統(tǒng)的內(nèi)核空間占用 1G,位于最高處,剩下的 3G 是用戶空間;

64 位系統(tǒng)的內(nèi)核空間和用戶空間都是 128T,分別占據(jù)整個內(nèi)存空間的最高和最低處,剩下的中間部分是未定義的。

內(nèi)核態(tài)控制的是內(nèi)核空間的資源管理,用戶態(tài)訪問的是用戶空間內(nèi)的資源。

從用戶態(tài)到內(nèi)核態(tài)切換可以通過三種方式:

系統(tǒng)調(diào)用,其實系統(tǒng)調(diào)用本身就是中斷,但是軟件中斷,跟硬中斷不同。

異常:如果當(dāng)前進程運行在用戶態(tài),如果這個時候發(fā)生了異常事件,就會觸發(fā)切換。例如:缺頁異常。

外設(shè)中斷:當(dāng)外設(shè)完成用戶的請求時,會向CPU發(fā)送中斷信號。

內(nèi)核態(tài)和用戶態(tài)是怎么控制數(shù)據(jù)傳輸?shù)模?/h2>

舉個例子:當(dāng)計算機A上a進程要把一個文件傳送到計算機B上的b進程空間里面去,它是怎么做的呢?在當(dāng)前的計算機系統(tǒng)架構(gòu)下,它的I/O路徑如下圖所示:

計算機A的進程a先要通過系統(tǒng)調(diào)用Read(內(nèi)核態(tài))打開一個磁盤上的文件,這個時候就要把數(shù)據(jù)copy一次到內(nèi)核態(tài)的PageCache中,進入了內(nèi)核態(tài);

進程a負責(zé)將數(shù)據(jù)從內(nèi)核空間的 Page Cache 搬運到用戶空間的緩沖區(qū),進入用戶態(tài);

進程a負責(zé)將數(shù)據(jù)從用戶空間的緩沖區(qū)搬運到內(nèi)核空間的 Socket(資源由內(nèi)核管控) 緩沖區(qū)中,進入內(nèi)核態(tài)。

進程a負責(zé)將數(shù)據(jù)從內(nèi)核空間的 Socket 緩沖區(qū)搬運到的網(wǎng)絡(luò)中,進入用戶態(tài);

從以上4個步驟我們可以發(fā)現(xiàn),正是因為用戶態(tài)沒法控制磁盤和網(wǎng)絡(luò)資源,所以需要來回的在內(nèi)核態(tài)切換。這樣一個發(fā)送文件的過程就產(chǎn)生了4 次上下文切換:

read 系統(tǒng)調(diào)用讀磁盤上的文件時:用戶態(tài)切換到內(nèi)核態(tài);

read 系統(tǒng)調(diào)用完畢:內(nèi)核態(tài)切換回用戶態(tài);

write 系統(tǒng)調(diào)用寫到socket時:用戶態(tài)切換到內(nèi)核態(tài);

write 系統(tǒng)調(diào)用完畢:內(nèi)核態(tài)切換回用戶態(tài)。

如此笨拙的設(shè)計,我們覺得計算機是不是太幼稚了,為啥要來回切換不能直接在用戶態(tài)做數(shù)據(jù)傳輸嗎?

CPU 全程負責(zé)內(nèi)存內(nèi)的數(shù)據(jù)拷貝,參考磁盤介質(zhì)的讀寫性能,這個操作是可以接受的,但是如果要讓內(nèi)存的數(shù)據(jù)和磁盤來回拷貝,這個時間消耗就非常的難看,因為磁盤、網(wǎng)卡的速度遠小于內(nèi)存,內(nèi)存又遠遠小于 CPU;

4 次 copy + 4 次上下文切換,代價太高。

所以計算機體系結(jié)構(gòu)的大佬們就想到了能不能單獨地做一個模塊來專職負責(zé)這個數(shù)據(jù)的傳輸,不因為占用cpu而降低系統(tǒng)的吞吐呢?方案就是引入了DMA(Direct memory access)

什么是 DMA ?

沒有 DMA ,計算機程序訪問磁盤上的數(shù)據(jù)I/O 的過程是這樣的:

CPU 先發(fā)出讀指令給磁盤控制器(發(fā)出一個系統(tǒng)調(diào)用),然后返回;

磁盤控制器接受到指令,開始準(zhǔn)備數(shù)據(jù),把數(shù)據(jù)拷貝到磁盤控制器的內(nèi)部緩沖區(qū)中,然后產(chǎn)生一個中斷;

CPU 收到中斷信號后,讓出CPU資源,把磁盤控制器的緩沖區(qū)的數(shù)據(jù)一次一個字節(jié)地拷貝進自己的寄存器,然后再把寄存器里的數(shù)據(jù)拷貝到內(nèi)存,而在數(shù)據(jù)傳輸?shù)钠陂g CPU 是無法執(zhí)行其他任務(wù)的。

可以看到,整個數(shù)據(jù)的傳輸有幾個問題:一是數(shù)據(jù)在不同的介質(zhì)之間被拷貝了多次;二是每個過程都要需要 CPU 親自參與(搬運數(shù)據(jù)的過程),在這個過程,在數(shù)據(jù)拷貝沒有完成前,CPU 是不能做額外事情的,被IO獨占。

如果I/O操作能比較快的完成,比如簡單的字符數(shù)據(jù),那沒問題。如果我們用萬兆網(wǎng)卡或者硬盤傳輸大量數(shù)據(jù),CPU就會一直被占用,其他服務(wù)無法使用,對單核系統(tǒng)是致命的。

為了解決上面的CPU被持續(xù)占用的問題,大佬們就提出了 DMA 技術(shù),即直接內(nèi)存訪問(Direct Memory Access) 技術(shù)。

那到底什么是 DMA 技術(shù)?

所謂的 DMA(Direct Memory Access,即直接存儲器訪問)其實是一個硬件技術(shù),其主要目的是減少大數(shù)據(jù)量傳輸時的 CPU 消耗,從而提高 CPU 利用效率。其本質(zhì)上是一個主板和 IO 設(shè)備上的 DMAC 芯片。CPU 通過調(diào)度 DMAC 可以不參與磁盤緩沖區(qū)到內(nèi)核緩沖區(qū)的數(shù)據(jù)傳輸消耗,從而提高效率。

那有了DMA,數(shù)據(jù)讀取過程是怎么樣的呢?下面我們來具體看看。

詳細過程:

用戶進程a調(diào)用系統(tǒng)調(diào)用read 方法,向OS內(nèi)核(資源總管)發(fā)出 I/O 請求,請求讀取數(shù)據(jù)到自己的內(nèi)存緩沖區(qū)中,進程進入阻塞狀態(tài);

OS內(nèi)核收到請求后,進一步將 I/O 請求發(fā)送 DMA,然后讓 CPU 執(zhí)行其他任務(wù);

DMA 再將 I/O 請求發(fā)送給磁盤控制器;

磁盤控制器收到 DMA 的 I/O 請求,把數(shù)據(jù)從磁盤拷貝到磁盤控制器的緩沖區(qū)中,當(dāng)磁盤控制器的緩沖區(qū)被寫滿后,它向 DMA 發(fā)起中斷信號,告知自己緩沖區(qū)已滿;

DMA 收到磁盤的中斷信號后,將磁盤控制器緩沖區(qū)中的數(shù)據(jù)拷貝到內(nèi)核緩沖區(qū)中,此時不占用 CPU,CPU 可以執(zhí)行其他任務(wù);

當(dāng) DMA 讀取了一個固定buffer的數(shù)據(jù),就會發(fā)送中斷信號給 CPU;

CPU 收到 DMA 的信號,知道數(shù)據(jù)已經(jīng)Ready,于是將數(shù)據(jù)從內(nèi)核拷貝到用戶空間,結(jié)束系統(tǒng)調(diào)用;

DMA技術(shù)就是釋放了CPU的占用時間,它只做事件通知,數(shù)據(jù)拷貝完全由DMA完成。雖然DMA優(yōu)化了CPU的利用率,但是并沒有提高數(shù)據(jù)讀取的性能。為了減少數(shù)據(jù)在2種狀態(tài)之間的切換次數(shù),因為狀態(tài)切換是一個非常、非常、非常繁重的工作。為此,大佬們就提了零拷貝技術(shù)。

零拷貝技術(shù)實現(xiàn)的方式

常見的有2種,而今引入持久化內(nèi)存后,還有APP直接訪問內(nèi)存數(shù)據(jù)的方式,這里先不展開。下面介紹常用的2種方案,它們的目的減少“上下文切換”和“數(shù)據(jù)拷貝”的次數(shù)。

mmap + write(系統(tǒng)調(diào)用)

sendfile

mmap + write

主要目的,減少數(shù)據(jù)的拷貝

read() 系統(tǒng)調(diào)用:把內(nèi)核緩沖區(qū)的數(shù)據(jù)拷貝到用戶的緩沖區(qū)里,用 mmap() 替換 read() ,mmap() 直接把內(nèi)核緩沖區(qū)里的數(shù)據(jù)映射到用戶空間,減少這一次拷貝。

buf = mmap(file, len);
write(sockfd, buf, len);

具體過程如下:

應(yīng)用進程調(diào)用了 mmap() 后,DMA 會把磁盤的數(shù)據(jù)拷貝到內(nèi)核的緩沖區(qū)里。因為建立了這個內(nèi)存的mapping,所以用戶態(tài)的數(shù)據(jù)可以直接訪問了;

應(yīng)用進程再調(diào)用 write(),CPU將內(nèi)核緩沖區(qū)的數(shù)據(jù)拷貝到 socket 緩沖區(qū)中,這一切都發(fā)生在內(nèi)核態(tài)

DMA把內(nèi)核的 socket 緩沖區(qū)里的數(shù)據(jù),拷貝到網(wǎng)卡的緩沖區(qū)里

由上可知,系統(tǒng)調(diào)用mmap() 來代替 read(), 可以減少一次數(shù)據(jù)拷貝。那我們是否還有優(yōu)化的空間呢?畢竟用戶態(tài)和內(nèi)核態(tài)仍然需要 4 次上下文切換,系統(tǒng)調(diào)用還是 2 次。那繼續(xù)研究下是否還能繼續(xù)減少切換和數(shù)據(jù)拷貝呢?答案是確定的:可以

sendfile

Linux 內(nèi)核版本 2.1 提供了一個專門發(fā)送文件的系統(tǒng)調(diào)用函數(shù) sendfile(),函數(shù)形式如下:

#include <sys/socket.h>
ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count);

參數(shù)說明:

前2個參數(shù)分別是目的端和源端的文件描述符,

后2個參數(shù)是源端的偏移量和復(fù)制數(shù)據(jù)的長度,返回值是實際復(fù)制數(shù)據(jù)的長度。

首先,使用sendfile()可以替代前面的 read() 和 write() 這兩個系統(tǒng)調(diào)用,減少一次系統(tǒng)調(diào)用和 2 次上下文切換。

其次,sendfile可以直接把內(nèi)核緩沖區(qū)里的數(shù)據(jù)拷貝到 socket 緩沖區(qū)里,不再拷貝到用戶態(tài),優(yōu)化后只有 2 次上下文切換,和 3 次數(shù)據(jù)拷貝。如下圖:

盡管如此,我們還是又數(shù)據(jù)拷貝,這不符合我們的標(biāo)題目標(biāo)。如果網(wǎng)卡支持 SG-DMA(The Scatter-Gather Direct Memory Access)技術(shù),我們就可以進一步減少通過 CPU 把內(nèi)核緩沖區(qū)里的數(shù)據(jù)拷貝到 socket 緩沖區(qū)的過程。

我們可以在 Linux 系統(tǒng)下通過下面的命令,查看網(wǎng)卡是否支持 scatter-gather 特性:

$ ethtool -k eth0 | grep scatter-gather
scatter-gather: on

于是,從 Linux 內(nèi)核 2.4 版本開始起,對于支持網(wǎng)卡支持 SG-DMA 技術(shù)的情況下, sendfile() 系統(tǒng)調(diào)用的過程發(fā)生了點變化,具體過程如下:

通過 DMA 將磁盤上的數(shù)據(jù)拷貝到內(nèi)核緩沖區(qū)里;

緩沖區(qū)描述符和數(shù)據(jù)長度傳到 socket 緩沖區(qū),這樣網(wǎng)卡的 SG-DMA 控制器就可以直接將內(nèi)核緩存中的數(shù)據(jù)拷貝到網(wǎng)卡的緩沖區(qū)里;

在這個過程之中,實際上只進行了 2 次數(shù)據(jù)拷貝,如下圖:

這就是零拷貝(Zero-copy)技術(shù),因為我們沒有在內(nèi)存層面去拷貝數(shù)據(jù),也就是說全程沒有通過 CPU 來搬運數(shù)據(jù),所有的數(shù)據(jù)都是通過 DMA 來進行傳輸?shù)摹?/p>

零拷貝技術(shù)的文件傳輸方式相比傳統(tǒng)文件傳輸?shù)姆绞?,只需?2 次上下文切換和數(shù)據(jù)拷貝次數(shù),就可以完成文件的傳輸,而且 2 次的數(shù)據(jù)拷貝過程,都不需要通過 CPU,2 次都是由 DMA 來搬運。

所以,零拷貝技術(shù)可以把文件傳輸?shù)男阅芴岣咧辽僖槐丁?/p>

為啥要聊PageCache?

回顧第一節(jié)的存儲介質(zhì)的性能,如果我們總是在磁盤和內(nèi)存間傳輸數(shù)據(jù),一個大文件的跨機器傳輸肯定會讓你抓狂。那有什么方法加速呢?直觀的想法就是建立一個離CPU近的一個臨時通道,這樣就可以加速文件的傳輸。這個通道就是我們前文提到的「內(nèi)核緩沖區(qū)」,這個「內(nèi)核緩沖區(qū)」實際上是磁盤高速緩存(PageCache)。

零拷貝就是使用了DMA + PageCache 技術(shù)提升了性能,我們來看看 PageCache 是如何做到的。

從開篇的介質(zhì)性能看,磁盤相比內(nèi)存讀寫的速度要慢很多,所以優(yōu)化的思路就是盡量的把「讀寫磁盤」替換成「讀寫內(nèi)存」。因此通過 DMA 把磁盤里的數(shù)據(jù)搬運到內(nèi)存里,轉(zhuǎn)為直接讀內(nèi)存,這樣就快多了。但是內(nèi)存的空間是有限的,成本也比磁盤貴,它只能拷貝磁盤里的一小部分數(shù)據(jù)。

那就不可避免的產(chǎn)生一個問題,到底選擇哪些磁盤數(shù)據(jù)拷貝到內(nèi)存呢?

從業(yè)務(wù)的視角來看,業(yè)務(wù)的數(shù)據(jù)有冷熱之分,我們通過一些的淘汰算法可以知道哪些是熱數(shù)據(jù),因為數(shù)據(jù)訪問的時序性,被訪問過的數(shù)據(jù)可能被再次訪問的概率很高,于是我們可以用 PageCache 來緩存最近被訪問的數(shù)據(jù),當(dāng)空間不足時淘汰最久未被訪問的數(shù)據(jù)。

讀Cache

當(dāng)內(nèi)核發(fā)起一個讀請求時(例如進程發(fā)起read()請求),首先會檢查請求的數(shù)據(jù)是否緩存到了Page Cache中。如果有,那么直接從內(nèi)存中讀取,不需要訪問磁盤,這被稱為cache命中(cache hit);如果cache中沒有請求的數(shù)據(jù),即cache未命中(cache miss),就必須從磁盤中讀取數(shù)據(jù)。然后內(nèi)核將讀取的數(shù)據(jù)緩存到cache中,這樣后續(xù)的讀請求就可以命中cache了。

page可以只緩存一個文件部分的內(nèi)容,不需要把整個文件都緩存進來。

寫Cache

當(dāng)內(nèi)核發(fā)起一個寫請求時(例如進程發(fā)起write()請求),同樣是直接往cache中寫入,后備存儲中的內(nèi)容不會直接更新(當(dāng)服務(wù)器出現(xiàn)斷電關(guān)機時,存在數(shù)據(jù)丟失風(fēng)險)。

內(nèi)核會將被寫入的page標(biāo)記為dirty,并將其加入dirty list中。內(nèi)核會周期性地將dirty list中的page寫回到磁盤上,從而使磁盤上的數(shù)據(jù)和內(nèi)存中緩存的數(shù)據(jù)一致。

當(dāng)滿足以下兩個條件之一將觸發(fā)臟數(shù)據(jù)刷新到磁盤操作:

數(shù)據(jù)存在的時間超過了dirty_expire_centisecs(默認300厘秒,即30秒)時間;

臟數(shù)據(jù)所占內(nèi)存 > dirty_background_ratio,也就是說當(dāng)臟數(shù)據(jù)所占用的內(nèi)存占總內(nèi)存的比例超過dirty_background_ratio(默認10,即系統(tǒng)內(nèi)存的10%)的時候會觸發(fā)pdflush刷新臟數(shù)據(jù)。

還有一點,現(xiàn)在的磁盤是擦除式讀寫,每次需要讀一個固定的大小,隨機讀取帶來的磁頭尋址會增加時延,為了降低它的影響,PageCache 使用了「預(yù)讀功能」。

在某些應(yīng)用場景下,比如我們每次打開文件只需要讀取或者寫入幾個字節(jié)的情況,會比Direct I/O多一些磁盤的讀取于寫入。

舉個例子,假設(shè)每次我們要讀 32 KB 的字節(jié),read填充到用戶buffer的大小是0~32KB,但內(nèi)核會把其后面的 32~64 KB 也讀取到 PageCache,這樣后面讀取 32~64 KB 的成本就很低,如果在 32~64 KB 淘汰出 PageCache 前,進程需要讀這些數(shù)據(jù),對比分塊讀取的方式,這個策略收益就非常大。

Page Cache的優(yōu)勢與劣勢

優(yōu)勢

加快對數(shù)據(jù)的訪問

減少磁盤I/O的訪問次數(shù),提高系統(tǒng)磁盤壽命

減少對磁盤I/O的訪問,提高系統(tǒng)磁盤I/O吞吐量(Page Cache的預(yù)讀機制)

劣勢

使用額外的物理內(nèi)存空間,當(dāng)物理內(nèi)存比較緊俏的時候,可能會導(dǎo)致頻繁的swap操作,最終會導(dǎo)致系統(tǒng)的磁盤I/O負載上升。

Page Cache沒有給應(yīng)用層提供一個很好的API。導(dǎo)致應(yīng)用層想要優(yōu)化Page Cache的使用策略很難。因此一些應(yīng)用實現(xiàn)了自己的Page管理,比如MySQL的InnoDB存儲引擎以16KB的頁進行管理。

另外,由于文件太大,可能某些部分的文件數(shù)據(jù)已經(jīng)被淘汰出去了,這樣就會帶來 2 個問題:

PageCache 由于長時間被大文件的部分塊占據(jù),而導(dǎo)致一些「熱點」的小文件可能就無法常駐 PageCache,導(dǎo)致頻繁讀寫磁盤而引起性能下降;

PageCache 中的大文件數(shù)據(jù),由于沒有全部常駐內(nèi)存,只有部分無法享受到緩存帶來的好處,同時過多的DMA 拷貝動作,增加了時延;

因此針對大文件的傳輸,不應(yīng)該使用 PageCache。

Page Cache緩存查看工具:cachestat

PageCache的參數(shù)調(diào)優(yōu)

備注:不同硬件配置的服務(wù)器可能效果不同,所以,具體的參數(shù)值設(shè)置需要考慮自己集群硬件配置。

考慮的因素主要包括:CPU核數(shù)、內(nèi)存大小、硬盤類型、網(wǎng)絡(luò)帶寬等。

查看Page Cache參數(shù):sysctl -a|grep dirty

調(diào)整內(nèi)核參數(shù)來優(yōu)化IO性能?

vm.dirty_background_ratio參數(shù)優(yōu)化:當(dāng)cached中緩存當(dāng)數(shù)據(jù)占總內(nèi)存的比例達到這個參數(shù)設(shè)定的值時將觸發(fā)刷磁盤操作。把這個參數(shù)適當(dāng)調(diào)小,這樣可以把原來一個大的IO刷盤操作變?yōu)槎鄠€小的IO刷盤操作,從而把IO寫峰值削平。對于內(nèi)存很大和磁盤性能比較差的服務(wù)器,應(yīng)該把這個值設(shè)置的小一點。

vm.dirty_ratio參數(shù)優(yōu)化:對于寫壓力特別大的,建議把這個參數(shù)適當(dāng)調(diào)大;對于寫壓力小的可以適當(dāng)調(diào)??;如果cached的數(shù)據(jù)所占比例(這里是占總內(nèi)存的比例)超過這個設(shè)置,系統(tǒng)會停止所有的應(yīng)用層的IO寫操作,等待刷完數(shù)據(jù)后恢復(fù)IO。所以萬一觸發(fā)了系統(tǒng)的這個操作,對于用戶來說影響非常大的。

vm.dirty_expire_centisecs參數(shù)優(yōu)化:這個參數(shù)會和參數(shù)vm.dirty_background_ratio一起來作用,一個表示大小比例,一個表示時間;即滿足其中任何一個的條件都達到刷盤的條件。

vm.dirty_writeback_centisecs參數(shù)優(yōu)化:理論上調(diào)小這個參數(shù),可以提高刷磁盤的頻率,從而盡快把臟數(shù)據(jù)刷新到磁盤上。但一定要保證間隔時間內(nèi)一定可以讓數(shù)據(jù)刷盤完成。

vm.swappiness參數(shù)優(yōu)化:禁用swap空間,設(shè)置vm.swappiness=0

大文件傳輸怎么做?

我們先來回顧下前文的讀流程,當(dāng)調(diào)用 read 方法讀取文件時,如果數(shù)據(jù)沒有準(zhǔn)備好,進程會阻塞在 read 方法調(diào)用,要等待磁盤數(shù)據(jù)的返回,如下圖:

具體過程:

當(dāng)調(diào)用 read 方法時,切到內(nèi)核態(tài)訪問磁盤資源。此時內(nèi)核會向磁盤發(fā)起 I/O 請求,磁盤收到請求后,準(zhǔn)備數(shù)據(jù)。數(shù)據(jù)讀取到控制器緩沖區(qū)完成后,就會向內(nèi)核發(fā)起 I/O 中斷,通知內(nèi)核磁盤數(shù)據(jù)已經(jīng)準(zhǔn)備好;

內(nèi)核收到 I/O 中斷后,將數(shù)據(jù)從磁盤控制器緩沖區(qū)拷貝到 PageCache 里;

內(nèi)核把 PageCache 中的數(shù)據(jù)拷貝到用戶緩沖區(qū),read 調(diào)用返回成功。

對于大塊數(shù)傳輸導(dǎo)致的阻塞,可以用異步 I/O 來解決,如下圖:

分為兩步執(zhí)行:

內(nèi)核向磁盤發(fā)起讀請求,因為是異步請求可以不等待數(shù)據(jù)就位就可以返回,于是CPU釋放出來可以處理其他任務(wù);

當(dāng)內(nèi)核將磁盤中的數(shù)據(jù)拷貝到進程緩沖區(qū)后,進程將接收到內(nèi)核的通知,再去處理數(shù)據(jù);

從上面流程來看,異步 I/O 并沒有讀寫 PageCache,繞開 PageCache 的 I/O 叫直接 I/O,使用 PageCache 的 I/O 則叫緩存 I/O。通常,對于磁盤異步 I/O 只支持直接 I/O。

因此,在高并發(fā)的場景下,針對大文件的傳輸?shù)姆绞?,?yīng)該使用「異步 I/O + 直接 I/O」來替代零拷貝技術(shù)。

直接 I/O 的兩種場景:

應(yīng)用程序已經(jīng)實現(xiàn)了磁盤數(shù)據(jù)的緩存

大文件傳輸

相關(guān)推薦

電子產(chǎn)業(yè)圖譜

公眾號『一口Linux』號主彭老師,擁有15年嵌入式開發(fā)經(jīng)驗和培訓(xùn)經(jīng)驗。曾任職ZTE,某研究所,華清遠見教學(xué)總監(jiān)。擁有多篇網(wǎng)絡(luò)協(xié)議相關(guān)專利和軟件著作。精通計算機網(wǎng)絡(luò)、Linux系統(tǒng)編程、ARM、Linux驅(qū)動、龍芯、物聯(lián)網(wǎng)。原創(chuàng)內(nèi)容基本從實際項目出發(fā),保持原理+實踐風(fēng)格,適合Linux驅(qū)動新手入門和技術(shù)進階。