新聞中心
隨著計算機(jī)技術(shù)的不斷發(fā)展,我們的日常生活中離不開各類設(shè)備和軟件的幫助。而在這些設(shè)備和軟件中,I/O(輸入輸出)操作占據(jù)了非常重要的地位,它也是計算機(jī)系統(tǒng)中最常用的操作之一。以Linux操作系統(tǒng)為例,本文將從bio(塊輸入輸出)和nio(新輸入輸出)兩個方面來介紹Linux中的I/O模型。

創(chuàng)新互聯(lián)專注于維西企業(yè)網(wǎng)站建設(shè),成都響應(yīng)式網(wǎng)站建設(shè),成都商城網(wǎng)站開發(fā)。維西網(wǎng)站建設(shè)公司,為維西等地區(qū)提供建站服務(wù)。全流程按需網(wǎng)站開發(fā),專業(yè)設(shè)計,全程項目跟蹤,創(chuàng)新互聯(lián)專業(yè)和態(tài)度為您提供的服務(wù)
1. bio
bio是Linux操作系統(tǒng)中最早的I/O模型之一,它是塊設(shè)備驅(qū)動程序接口的一部分。在使用bio時,應(yīng)用程序可以將I/O請求發(fā)送給塊設(shè)備驅(qū)動程序,而驅(qū)動程序?qū)⒄埱髠鬟f給硬件設(shè)備。換句話說,bio是一種“阻塞”I/O模型,因為應(yīng)用程序在等待I/O完成之前會一直被阻塞。
由于bio的阻塞特性,它的效率并不高。在多個I/O請求同時到達(dá)時,bio只能順序地處理這些請求,因此會出現(xiàn)I/O請求阻塞的情況。也就是說,在等待前一個請求完成之前,后續(xù)相關(guān)的I/O請求都無法處理。此外,在進(jìn)行I/O讀寫時,bio也是將整塊數(shù)據(jù)讀寫,而無法進(jìn)行數(shù)據(jù)的拆分和合并操作。
2. nio
nio是一種“非阻塞”I/O模型,它在Linux操作系統(tǒng)中得到廣泛應(yīng)用。與bio不同的是,nio提供了更高效和靈活的I/O操作。它采用異步I/O機(jī)制,應(yīng)用程序可以在等待I/O完成的同時繼續(xù)執(zhí)行其他操作,而不必一直等待I/O完成。
nio的優(yōu)勢主要體現(xiàn)在兩個方面:一方面,在進(jìn)行I/O讀寫時,nio可以將數(shù)據(jù)拆分成多個小塊進(jìn)行讀寫,這樣可以更好地適應(yīng)硬件設(shè)備的特性,提高I/O效率;另一方面,nio可以支持多個I/O請求并發(fā)執(zhí)行,從而減少I/O查詢的阻塞時間,提高系統(tǒng)的吞吐量。
此外,nio還提供了很多高級的I/O操作方式,比如epoll機(jī)制、信號驅(qū)動I/O和異步I/O等,并且能夠?qū)Σ煌愋偷腎/O任務(wù)進(jìn)行分類和調(diào)度。這些高級特性讓nio成為了當(dāng)前Linux操作系統(tǒng)下更流行的I/O模型之一。
3. bio和nio的比較
來說,bio和nio是兩種不同的I/O模型,它們各有優(yōu)缺點(diǎn)。bio可以很好地適應(yīng)傳輸大數(shù)據(jù)塊的I/O操作,并且在單線程環(huán)境下運(yùn)作流暢,但它的阻塞特性會影響系統(tǒng)的效率。而nio在處理大量小數(shù)據(jù)塊時效率更高,可以處理更多的并發(fā)請求,并且可以靈活地對不同類型的I/O任務(wù)進(jìn)行管理,但它需要較為復(fù)雜的邏輯處理。
對于開發(fā)人員來說,bio和nio的選擇是根據(jù)應(yīng)用場景來決定的。如果需要進(jìn)行大數(shù)據(jù)塊的I/O讀寫,或者只有少量的并發(fā)請求,那么bio是一個不錯的選擇。而如果需要進(jìn)行大量小數(shù)據(jù)塊的I/O讀寫,或者需要支持大量的并發(fā)請求,那么nio是更加合適的選擇。
I/O操作是計算機(jī)系統(tǒng)中非常關(guān)鍵的一部分,對于操作系統(tǒng)和應(yīng)用程序的性能有很大的影響。bio和nio是Linux操作系統(tǒng)中兩種不同類型的I/O模型,它們各具優(yōu)勢,應(yīng)用場景也不同。了解bio和nio的特點(diǎn)和使用方式,可以幫助我們更好地進(jìn)行I/O操作,提高Linux系統(tǒng)的效率和性能。
相關(guān)問題拓展閱讀:
- Linux系統(tǒng)I/O操作與零拷貝
- Web中間件——Tomcat中的BIO、NIO、APR模式
Linux系統(tǒng)I/O操作與零拷貝
Linux中傳統(tǒng)的I/O操作是一種緩存I/O,I/O過程中產(chǎn)生的數(shù)據(jù)傳輸通常需要在緩沖區(qū)中進(jìn)行多次拷貝。當(dāng)應(yīng)用程序需要訪問某個數(shù)據(jù)(read()操作)時,操作系統(tǒng)會先判斷這塊數(shù)據(jù)是否在內(nèi)核緩沖區(qū)中,如果在內(nèi)核緩沖區(qū)中找不到這塊數(shù)據(jù),內(nèi)核會先將這塊數(shù)據(jù)從磁盤中讀出來放到內(nèi)核緩沖區(qū)中,應(yīng)用程序再從緩沖區(qū)中讀取。當(dāng)應(yīng)用程序需要將數(shù)據(jù)輸出(write())時,同樣需要先將數(shù)據(jù)拷貝到輸出堆棧相關(guān)的內(nèi)核緩沖區(qū),再從內(nèi)核緩沖區(qū)拷貝到輸出設(shè)備中。
以一次網(wǎng)絡(luò)請求為例,如下圖。對于一次數(shù)據(jù)讀取,用戶應(yīng)用程序只需要調(diào)用read()及write()兩個系統(tǒng)調(diào)用就可以完成一次數(shù)據(jù)傳輸,但這個過程中數(shù)據(jù)經(jīng)過了四次拷貝,且數(shù)據(jù)拷貝需要由CPU來調(diào)控。在某些情況下,這些數(shù)據(jù)拷貝會極大地降低系統(tǒng)數(shù)據(jù)傳輸?shù)男阅?,比如文件服?wù)器中,一個文件從磁盤讀取后不加修改地回傳給調(diào)用方,那么這占用CPU時間去處理這四次數(shù)據(jù)拷貝的性價比是極低的。
一次處理網(wǎng)絡(luò)調(diào)用的系統(tǒng)I/O的流程:
以上可以發(fā)現(xiàn),傳統(tǒng)的Linux系統(tǒng)I/O 操作要進(jìn)行4次內(nèi)核空間與應(yīng)用程序空間的上下文切換,以及4次數(shù)據(jù)拷貝。
直接內(nèi)存訪問(Direct Memory Access,DMA)是計算機(jī)科學(xué)中的一種內(nèi)存訪問技術(shù),允許某些電腦內(nèi)部的硬件子系統(tǒng)獨(dú)立地讀取系統(tǒng)內(nèi)存,而不需要中央處理器(CPU)的介入。在同等程度的處理器負(fù)擔(dān)亂薯畢下,DMA是一種快速的數(shù)據(jù)傳送方式。這類子系統(tǒng)包括硬盤控制器、顯卡、網(wǎng)卡和聲卡。
在Linux系統(tǒng)中,當(dāng)應(yīng)用程序需要讀取文件中的數(shù)據(jù)時,操作系統(tǒng)先分配一些內(nèi)存,將數(shù)據(jù)從存儲設(shè)備讀入到這些內(nèi)存中,然后再將數(shù)據(jù)傳遞應(yīng)用進(jìn)程;當(dāng)需要往文件中寫數(shù)據(jù)時,操作系統(tǒng)先分配內(nèi)存接收用戶數(shù)據(jù),然后再將數(shù)據(jù)從內(nèi)存寫入磁盤。文件cache管理就是對這些由操作系統(tǒng)分配并用開存儲文件數(shù)據(jù)的內(nèi)存的管理。
在Linux系統(tǒng)中,文件cache分為兩個層面,page cache 與 Buffer cache,每個page cache包含若干個buffer cache。操作系統(tǒng)中,磁盤文件都是由一系列的數(shù)據(jù)塊(Block)組成,buffer cache也叫塊緩存,是對磁盤一個數(shù)據(jù)塊的緩存,目的是為了在程序多次訪問同一個磁盤塊時減少訪問時間;而文件系統(tǒng)對數(shù)據(jù)的組織形式為頁,page cache為頁緩存,是由多個塊緩存構(gòu)成,其對應(yīng)的緩存數(shù)據(jù)塊在磁盤上不一定是連續(xù)的。也就是說buffer cache緩存文件的具體內(nèi)容–物理磁盤上的磁盤塊,加速對磁盤的訪問,而page cache緩存文件的邏輯內(nèi)容,加速對文件內(nèi)容的訪問。
buffer cache的大小一般為1k,page cache在32位系統(tǒng)上一般為4k,在64位系統(tǒng)上一般為8k。磁盤數(shù)據(jù)塊、buffer cache、page cache及文件的關(guān)系如下圖:
文件cache的目的是加快對數(shù)據(jù)文件的訪問,同時會有一個預(yù)讀過程。對于每個文件的之一次讀請求,系統(tǒng)會讀入所請求的頁面并讀入緊隨其后的幾個頁面;對于第二次讀請求,如果所讀頁面在cache中,則會直接返回,同時又一個異步預(yù)讀的過程(將讀取頁面的下幾頁讀入cache中),如果不在cache中,說明讀請求不是順序讀,則會從磁盤中讀取文件內(nèi)容并刷新cache。因此在順序讀取情況下,讀取數(shù)據(jù)的性能近乎內(nèi)存讀取。
DMA允許硬件子系手鎮(zhèn)統(tǒng)直接將數(shù)據(jù)從磁盤讀取到內(nèi)核緩沖區(qū),那么在一次數(shù)據(jù)傳輸中,磁盤與內(nèi)核緩沖區(qū),輸出設(shè)備與內(nèi)核緩沖區(qū)之間的兩次數(shù)據(jù)拷貝就不需要CPU進(jìn)行調(diào)度,CPU只需要進(jìn)行緩沖區(qū)管嘩芹理、以及創(chuàng)建和處理DMA。而Page Cache/Buffer Cache的預(yù)讀取機(jī)制則加快了數(shù)據(jù)的訪問效率。如下圖所示,還是以文件服務(wù)器請求為例,此時CPU負(fù)責(zé)的數(shù)據(jù)拷貝次數(shù)減少了兩次,數(shù)據(jù)傳輸性能有了較大的提高。
使用DMA的系統(tǒng)I/O操作要進(jìn)行4次內(nèi)核空間與應(yīng)用程序空間的上下文切換,2次CPU數(shù)據(jù)拷貝及2次DMA數(shù)據(jù)拷貝。
Mmap內(nèi)存映射與標(biāo)準(zhǔn)I/O操作的區(qū)別在于當(dāng)應(yīng)用程序需要訪問數(shù)據(jù)時,不需要進(jìn)行內(nèi)核緩沖區(qū)到應(yīng)用程序緩沖區(qū)之間的數(shù)據(jù)拷貝。Mmap使得應(yīng)用程序和操作系統(tǒng)共享內(nèi)核緩沖區(qū),應(yīng)用程序直接對內(nèi)核緩沖區(qū)進(jìn)行讀寫操作,不需要進(jìn)行數(shù)據(jù)拷貝。Linux系統(tǒng)中通過調(diào)用mmap()替代read()操作。
同樣以文件服務(wù)器獲取文件(不加修改)為例,通過mmap操作的一次系統(tǒng)I/O過程如下:
通過以上流程可以看到,數(shù)據(jù)拷貝從原來的4次變?yōu)?次,2次DMA拷貝1次內(nèi)核空間數(shù)據(jù)拷貝,CPU只需要調(diào)控1次內(nèi)核空間之間的數(shù)據(jù)拷貝,CPU花費(fèi)在數(shù)據(jù)拷貝上的時間進(jìn)一步減少(4次上下文切換沒有改變)。對于大容量文件讀寫,采用mmap的方式其讀寫效率和性能都比較高。(數(shù)據(jù)頁較多,需要多次拷貝)
注:mmap()是讓應(yīng)用程序空間與內(nèi)核空間共享DMA從磁盤中讀取的文件緩沖,也就是應(yīng)用程序能直接讀寫這部分PageCache,至于上圖中從頁緩存到socket緩沖區(qū)的數(shù)據(jù)拷貝只是文件服務(wù)器的處理,根據(jù)應(yīng)用程序的不同會有不同的處理,應(yīng)用程序也可以讀取數(shù)據(jù)后進(jìn)行修改。重點(diǎn)是虛擬內(nèi)存映射,內(nèi)核緩存共享。
djk中nio包下的MappedByteBuffer,官方注釋為
A direct byte buffer whose content is a memory-mapped region of a file,即直接字節(jié)緩沖區(qū),其內(nèi)容是文件的內(nèi)存映射區(qū)域。
FileChannel是是nio操作文件的類,其map()方法在在實現(xiàn)類中調(diào)用native map0()本地方法,該方法通過mmap()實現(xiàn),因此是將文件從磁盤讀取到內(nèi)核緩沖區(qū),用戶應(yīng)用程序空間直接操作內(nèi)核空間共享的緩沖區(qū),Java程序通過MappedByteBuffer的get()方法獲取內(nèi)存數(shù)據(jù)。
MappedByteBuffer允許Java程序直接從內(nèi)存訪問文件,可以將整個文件或文件的一部分映射到內(nèi)存中,由操作系統(tǒng)進(jìn)行相關(guān)的請求并將內(nèi)存中的修改寫入到磁盤中。
FileChannel map有三種模式
MappedByteBuffer的應(yīng)用,以rocketMQ為例(簡單介紹)。
producer端發(fā)送消息最終會被寫入到commitLog文件中,consumer端消費(fèi)時先從訂閱的consumeQueue中讀取持久化消息的commitLogOffset、size等內(nèi)容,隨后再根據(jù)offset、size從commitLog中讀取消息的真正實體內(nèi)容。其中,commitLog是混合部署的,所有topic下的消息隊列共用一個commitLog日志數(shù)據(jù)文件,consumeQueue類似于索引,同時區(qū)分開不同topic下不同MessageQueue的消息。
rocketMQ利用MappedByteBuffer及PageCache加速對持久化文件的讀寫操作。rocketMQ通過MappedByteBuffer將日志數(shù)據(jù)文件映射到OS的虛擬內(nèi)存中(PageCache),寫消息時首先寫入PageCache,通過刷盤方式(異步或同步)將消息批量持久化到磁盤;consumer消費(fèi)消息時,讀取consumeQueue是順序讀取的,雖然有多個消費(fèi)者操作不同的consumeQueue,對混合部署的commitLog的訪問時隨機(jī)的,但整體上是從舊到新的有序讀,加上PageCache的預(yù)讀機(jī)制,大部分情況下消息還是從PageCache中讀取,不會產(chǎn)生太多的缺頁中斷(要讀取的消息不在pageCache中)而從磁盤中讀取。
rocketMQ利用mmap()使程序與內(nèi)核空間共享內(nèi)核緩沖區(qū),直接對PageCache中的文件進(jìn)行讀寫操作,加速對消息的讀寫請求,這是其高吞吐量的重要手段。
使用mmap能減少CPU數(shù)據(jù)拷貝的次數(shù),但也存在一些問題。
從Linux2.1開始,Linux引入sendfile()簡化操作。取消read()/write(),mmap()/write()。
調(diào)用sendfile的流程如下:
通過sendfile()的I/O進(jìn)行了2次應(yīng)用程序空間與內(nèi)核空間的上下文切換,以及3次數(shù)據(jù)拷貝,其中2次是DMA拷貝,1次是CPU拷貝。sendfile相比起mmap,數(shù)據(jù)信息沒有進(jìn)入到應(yīng)用程序空間,所以能減少2次上下文切換的開銷,而數(shù)據(jù)拷貝次數(shù)是一樣的。
上述流程也可以看出,sendfile()適合對文件不加修改的I/O操作。
sendfile()只是減少應(yīng)用程序空間與內(nèi)核空間的上下文切換,并沒有減少CPU數(shù)據(jù)拷貝的次數(shù),還存在一次內(nèi)核空間的兩個緩沖區(qū)的數(shù)據(jù)拷貝。要實現(xiàn)CPU零數(shù)據(jù)拷貝,需要引入一些硬件上的支持。在上一小節(jié)的sendfile流程中,數(shù)據(jù)需要從內(nèi)核緩沖區(qū)拷貝到內(nèi)核空間socket緩沖區(qū),數(shù)據(jù)都是在內(nèi)核空間,如果socket緩沖區(qū)到網(wǎng)卡的這次DMA數(shù)據(jù)傳輸操作能直接讀取到內(nèi)核緩沖區(qū)中的數(shù)據(jù),那么這一次的CPU數(shù)據(jù)拷貝也就能避免。要達(dá)到這個目的,DMA需要知道存有文件位置和長度信息的緩沖區(qū)描述符,即socket緩沖區(qū)需要從內(nèi)核緩沖區(qū)接收這部分信息,DMA需要支持?jǐn)?shù)據(jù)收集功能。
sendfile()調(diào)用后,數(shù)據(jù)從磁盤文件拷貝到內(nèi)核緩沖區(qū)中,然后將文件位置和長度信息的緩沖區(qū)描述符傳遞到socket緩沖區(qū),此時數(shù)據(jù)并沒有被拷貝。之后網(wǎng)卡子系統(tǒng)根據(jù)socket緩沖區(qū)中的文件信息利用DMA技術(shù)收集拷貝數(shù)據(jù)。整個過程進(jìn)行了2次內(nèi)核空間和應(yīng)用程序空間的上下文切換,及2次DMA數(shù)據(jù)拷貝,CPU不需要參與數(shù)據(jù)拷貝工作,從而實現(xiàn)零拷貝。當(dāng)然DMA收集拷貝功能需要硬件和驅(qū)動程序的支持。
在操作系統(tǒng)中,硬件和軟件之間的數(shù)據(jù)傳輸可以通過DMA來進(jìn)行,DMA進(jìn)行數(shù)據(jù)傳輸?shù)倪^程幾乎不需要CPU參與,但是在內(nèi)核緩沖區(qū)(頁緩存)與應(yīng)用程序緩沖區(qū)之間的數(shù)據(jù)拷貝并沒有類似于DMA之類的工具可以使用,mmap、sendfile都是為了減少數(shù)據(jù)在內(nèi)核空間與應(yīng)用程序空間傳輸時的數(shù)據(jù)拷貝和上下文切換次數(shù),有效地改善數(shù)據(jù)在兩者之間傳遞的效率。
linux操作系統(tǒng)的零拷貝技術(shù)并不單指某一種方式,現(xiàn)有的零拷貝技術(shù)種類非常多,在不同的Linux內(nèi)核版本上有不同的支持。常見的,如果應(yīng)用程序需要修改數(shù)據(jù),則使用mmap(),如果只進(jìn)行文件數(shù)據(jù)傳輸,則可選擇sendfile()。
另外,關(guān)于零拷貝技術(shù)適用于什么場景?在上述的描述中,數(shù)據(jù)在傳遞過程中,除了mmap外,應(yīng)用程序和操作系統(tǒng)幾乎是沒有改變數(shù)據(jù)的,mmap的內(nèi)存映射也是沒有改變數(shù)據(jù)的,也就是說在靜態(tài)資源的讀取場景下,零拷貝更能發(fā)揮作用。正如其名,拷貝是在不改變數(shù)據(jù)的情況下,零是利用手段去減少CPU參與數(shù)據(jù)拷貝的次數(shù),以釋放CPU去進(jìn)行其他系統(tǒng)調(diào)用與計算。
Web中間件——Tomcat中的BIO、NIO、APR模式
Tomcat在我們?nèi)粘i_發(fā)B/S項目時常常進(jìn)行使用,當(dāng)然在Spring全家桶中我們現(xiàn)在也是使用的內(nèi)置tomcat,但是很多人可能不會對于tomcat進(jìn)行深入性研究,其實在我們的產(chǎn)品進(jìn)行性能提升時,web中間件的優(yōu)化也是占有很大一部分,而tomcat中采用不同的模式對應(yīng)的使用場景下性能也是不一樣的,因此本篇文章將對于這幾個模式進(jìn)行簡單講解,后如帆續(xù)我們會對于不同的模式進(jìn)行配置方式講解。
阻塞式I/O操作,這個模式使用的是Java I/O操作。該運(yùn)行方式性能更低。
基于Java 緩存區(qū)提供非阻塞式I/O操作,相比BIO,該運(yùn)行方式有更好的性能。當(dāng)前tomcat7及以上版本默認(rèn)采用該模式。
以JNI的形式調(diào)用Apache HTTP服務(wù)器的核心動態(tài)鏈接轎灶庫來處理文件讀取或網(wǎng)絡(luò)傳輸操作,有效提高靜態(tài)文件的處理性能。該運(yùn)行方式對于高并發(fā)場景性能更高(當(dāng)然高并發(fā)還有其他優(yōu)化點(diǎn))。閉橡扮
注:APR配置方式可以參見 我的文章
linux nio bio的介紹就聊到這里吧,感謝你花時間閱讀本站內(nèi)容,更多關(guān)于linux nio bio,從bio到nio:了解Linux中的I/O模型,Linux系統(tǒng)I/O操作與零拷貝,Web中間件——Tomcat中的BIO、NIO、APR模式的信息別忘了在本站進(jìn)行查找喔。
成都網(wǎng)站設(shè)計制作選創(chuàng)新互聯(lián),專業(yè)網(wǎng)站建設(shè)公司。
成都創(chuàng)新互聯(lián)10余年專注成都高端網(wǎng)站建設(shè)定制開發(fā)服務(wù),為客戶提供專業(yè)的成都網(wǎng)站制作,成都網(wǎng)頁設(shè)計,成都網(wǎng)站設(shè)計服務(wù);成都創(chuàng)新互聯(lián)服務(wù)內(nèi)容包含成都網(wǎng)站建設(shè),小程序開發(fā),營銷網(wǎng)站建設(shè),網(wǎng)站改版,服務(wù)器托管租用等互聯(lián)網(wǎng)服務(wù)。
分享題目:從bio到nio:了解Linux中的I/O模型 (linux nio bio)
瀏覽地址:http://fisionsoft.com.cn/article/cdhdjed.html


咨詢
建站咨詢
