偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

Java 開發(fā)者必知的零拷貝技術(shù):RocketMQ/Kafka 性能優(yōu)化的核心原理

開發(fā)
零拷貝技術(shù)通過減少或消除數(shù)據(jù)在內(nèi)存中的拷貝次數(shù),以及減少用戶態(tài)與內(nèi)核態(tài)之間的上下文切換,顯著提升了IO操作的性能。本文將詳細(xì)介紹零拷貝技術(shù)的工作原理及其在實際項目中的應(yīng)用。

在現(xiàn)代計算機(jī)系統(tǒng)中,高效的IO(輸入/輸出)操作對于系統(tǒng)整體性能至關(guān)重要。隨著應(yīng)用程序?qū)?shù)據(jù)處理需求的不斷增長,如何減少CPU在IO操作中的開銷,提高數(shù)據(jù)傳輸效率,成為系統(tǒng)設(shè)計中的重要課題。零拷貝(Zero-Copy)技術(shù)應(yīng)運(yùn)而生,成為解決這一問題的關(guān)鍵技術(shù)之一。

零拷貝技術(shù)通過減少或消除數(shù)據(jù)在內(nèi)存中的拷貝次數(shù),以及減少用戶態(tài)與內(nèi)核態(tài)之間的上下文切換,顯著提升了IO操作的性能。本文將詳細(xì)介紹零拷貝技術(shù)的工作原理及其在實際項目中的應(yīng)用。 

一、詳解零拷貝工作原理

1. 傳統(tǒng)的IO流程是什么樣的

我們先簡單了解一下文件讀取的粗略流程,應(yīng)用程序需要讀取文件時,對應(yīng)的流程為:

  • 應(yīng)用程序發(fā)起read讀取請求。
  • 系統(tǒng)內(nèi)核將數(shù)據(jù)從硬盤加載到內(nèi)核緩沖區(qū)。
  • 內(nèi)核緩沖區(qū)拷貝用戶空間緩沖區(qū)。
  • 應(yīng)用程序基于用戶緩沖區(qū)讀取數(shù)據(jù)進(jìn)行業(yè)務(wù)流程處理。

基于上述基礎(chǔ),我們在進(jìn)行深入了解如下幾個概念,這對我們了解傳統(tǒng)IO流程的理解有著重要的作用:

  • 內(nèi)核態(tài):內(nèi)核態(tài)是操作系統(tǒng)內(nèi)核運(yùn)行的模式,當(dāng)我們需要操作系統(tǒng)內(nèi)核級別的特權(quán)指令(例如上文的read操作),就需要切換為內(nèi)核態(tài)。內(nèi)核態(tài)具備操作系統(tǒng)的最高權(quán)限,可以訪問計算機(jī)所有的硬件資源和數(shù)據(jù)。
  • 用戶態(tài):和內(nèi)核態(tài)相反,應(yīng)用程序所處的模式也就是用戶態(tài),是應(yīng)用程序運(yùn)行的模式,在該模式下僅僅能執(zhí)行普通指令,無法直接訪問操作操作系統(tǒng)敏感數(shù)據(jù)和計算機(jī)硬件資源。
  • 內(nèi)核緩沖區(qū):內(nèi)核緩沖區(qū)可以理解為應(yīng)用程序和外部存儲介質(zhì)數(shù)據(jù)的中介,即應(yīng)用程序和外部存儲介質(zhì)或者網(wǎng)絡(luò)socket交互的數(shù)據(jù)都會經(jīng)由內(nèi)核緩沖區(qū)進(jìn)行中轉(zhuǎn)。
  • 用戶緩沖區(qū):提供于應(yīng)用程序直接讀寫操作的內(nèi)存空間,這也就意味著我們需要處理任何外部存儲介質(zhì)或者網(wǎng)絡(luò)socket數(shù)據(jù)都必須加載到內(nèi)核緩沖區(qū)應(yīng)用程序才能進(jìn)行進(jìn)一步的操作。
  • 磁盤空間緩沖區(qū):磁盤緩沖區(qū)用于處理那些從磁盤中讀取或者準(zhǔn)備寫入磁盤的數(shù)據(jù)的臨時內(nèi)存存儲空間,它是一種對于磁盤I/O的優(yōu)化策略,本質(zhì)上就是通過內(nèi)存高速的訪問速度,減少讀取磁盤數(shù)據(jù)的耗時,從而提高數(shù)據(jù)讀寫的執(zhí)行性能。
  • PageCache:PageCache也就是我們所說的磁盤高速緩存,操作系統(tǒng)為了保證讀寫性能,用到了局部性原理,通俗來說也就是操作系統(tǒng)認(rèn)為近期被讀取的數(shù)據(jù)以及相鄰的數(shù)據(jù)再次被訪問的概率很高,于是這些讀取過的數(shù)據(jù)以及相鄰的數(shù)據(jù)都會緩存在PageCache中,當(dāng)我們再次進(jìn)行相同數(shù)據(jù)讀取時,如果PageCache存在該數(shù)據(jù)則會直接返回,反之則會到外部存儲介質(zhì)讀取。注意PageCache數(shù)據(jù)并非一直活躍于內(nèi)存中,一旦內(nèi)存空間被占滿,由于緩存置換算法,某些長時間未被訪問的PageCache就會被淘汰。

有了初步的認(rèn)識我們就可以更加深入的去分析傳統(tǒng)IO流程了,先來說說讀的詳細(xì)流程,對應(yīng)的時序圖如下所示,可以看到完整IO讀流程為:

  • 應(yīng)用程序發(fā)起read調(diào)用,因為涉及系統(tǒng)內(nèi)核的操作,所以需要進(jìn)行一次模式切換,從用戶態(tài)轉(zhuǎn)為內(nèi)核態(tài)。
  • 內(nèi)核通過外部存儲介質(zhì)或者網(wǎng)絡(luò)socket發(fā)起讀操作。
  • 磁盤或者網(wǎng)絡(luò)數(shù)據(jù)寫入磁盤緩沖區(qū)。
  • 內(nèi)核將數(shù)據(jù)從磁盤緩沖區(qū)加載到內(nèi)核緩沖區(qū)。
  • 內(nèi)核緩沖區(qū)將數(shù)據(jù)拷貝到用戶緩沖區(qū),提供應(yīng)用程序處理。
  • 完成上述操作后,再次進(jìn)行模式切換,從內(nèi)核態(tài)轉(zhuǎn)為用戶態(tài)。

同理我們再次給出傳統(tǒng)IO的寫入操作:

  • 應(yīng)用程序發(fā)起write調(diào)用,進(jìn)行一次模式切換,從用戶態(tài)轉(zhuǎn)為內(nèi)核態(tài)。
  • 將數(shù)據(jù)從用戶緩沖區(qū)寫入內(nèi)核緩沖區(qū)。
  • 內(nèi)核緩沖區(qū)將數(shù)據(jù)寫入到磁盤緩沖區(qū)。
  • 最終磁盤緩沖區(qū)數(shù)據(jù)被寫入到磁盤或者網(wǎng)絡(luò)套接字中。

2. 解決傳統(tǒng)IO性能瓶頸的思路有哪些

傳統(tǒng)IO模式性能開銷存在于以下三點(diǎn):

  • 整個數(shù)據(jù)的傳輸過程都需要CPU參與,在此過程期間CPU不能做其他事情。
  • 因為數(shù)據(jù)需要經(jīng)過內(nèi)核緩沖區(qū)的緣故,導(dǎo)致發(fā)起IO調(diào)用時存在用戶態(tài)到內(nèi)核態(tài)模式上下文切換的開銷。
  • 數(shù)據(jù)傳輸時需要在用戶緩沖區(qū)、內(nèi)核緩沖區(qū)來回拷貝的開銷,消耗了大量CPU時間片和內(nèi)存帶寬。

3. mmap+write零拷貝

第一點(diǎn)本質(zhì)上可以通過內(nèi)存映射文件技術(shù)(Memory-mapped Files)解決。該技術(shù)通過將文件直接映射到用戶空間的內(nèi)存區(qū)域,使得應(yīng)用程序可以直接訪問文件數(shù)據(jù),避免了數(shù)據(jù)在用戶空間和內(nèi)核空間之間的拷貝操作:

通過DMA進(jìn)行數(shù)據(jù)寫入時,也是一個道理,通過DMA將內(nèi)核緩沖區(qū)數(shù)據(jù)寫入至外部存儲/socket:

再來聊聊第二點(diǎn),針對用戶態(tài)、內(nèi)核態(tài)上下文切換的開銷,我們可以通過內(nèi)存映射文件技術(shù)(Memory-mapped Files)解決。該技術(shù)將文件直接映射到用戶空間的內(nèi)存區(qū)域,使得應(yīng)用程序可以直接訪問文件數(shù)據(jù),避免了數(shù)據(jù)在用戶空間和內(nèi)核空間之間的拷貝操作,從而減少了上下文切換的開銷:

4. sendfile實現(xiàn)零拷貝

接下來就是第三點(diǎn),針對直接文件傳輸,實際上Linux內(nèi)核2.1及其以上版本提供sendfile內(nèi)核函數(shù),該函數(shù)可直接將文件數(shù)據(jù)從一個文件描述符傳輸?shù)搅硪粋€文件描述符(如從文件到socket),減少了數(shù)據(jù)在內(nèi)核緩沖區(qū)和用戶緩沖區(qū)之間的拷貝操作,節(jié)省了一大部分拷貝的開銷:

5. sendfile更進(jìn)一步的優(yōu)化

實際上sendfile內(nèi)核函數(shù)在Linux的2.4版本做了更進(jìn)一步的優(yōu)化,若網(wǎng)卡支持SG-DMA(Scatter-Gather DMA)技術(shù)的情況下,上一步將磁盤數(shù)據(jù)寫入到內(nèi)核緩沖區(qū)再通過CPU將磁盤數(shù)據(jù)拷貝到socket緩沖區(qū)的步驟可以省去,通過DMA控制器將數(shù)據(jù)直接寫入到網(wǎng)卡,將寫入的文件描述符和數(shù)據(jù)長度告知socket緩沖區(qū),由此通過避免CPU參與,完成大文件的高效傳輸:

6. splice實現(xiàn)零拷貝

除了sendfile,Linux還提供了splice系統(tǒng)調(diào)用,它可以在兩個文件描述符之間移動數(shù)據(jù),其中一個必須是管道描述符。splice通過在內(nèi)核空間中直接移動數(shù)據(jù),避免了用戶空間和內(nèi)核空間之間的數(shù)據(jù)拷貝,進(jìn)一步提升了IO性能:

應(yīng)用程序 → splice() → 管道緩沖區(qū) → splice() → 目標(biāo)文件描述符

splice特別適用于需要在文件和管道之間傳輸數(shù)據(jù)的場景,例如在網(wǎng)絡(luò)服務(wù)器中將文件數(shù)據(jù)傳輸?shù)骄W(wǎng)絡(luò)套接字。

二、聊聊零拷貝技術(shù)在大型開源項目中的運(yùn)用

1. mmap+write技術(shù)的運(yùn)用

對于mmap+write技術(shù)的運(yùn)用,最典型的就是RocketMQ中MappedFile的init方法,可以看到它的mappedByteBuffer 就是通過map方法與內(nèi)核緩沖區(qū)構(gòu)成映射,實現(xiàn)盡可能少的數(shù)據(jù)拷貝提升數(shù)據(jù)讀寫性能:

private void init(final String fileName, final int fileSize) throws IOException {
 //封裝文件信息
    this.fileName = fileName;
    this.fileSize = fileSize;
    this.file = new File(fileName);
    this.fileFromOffset = Long.parseLong(this.file.getName());
    boolean ok = false;
 
    ensureDirOK(this.file.getParent());

    try {
     //與文件file的內(nèi)核緩沖區(qū)數(shù)據(jù)構(gòu)成映射,并將內(nèi)核緩沖區(qū)數(shù)據(jù)地址信息封裝到mappedByteBuffer 
        this.fileChannel = new RandomAccessFile(this.file, "rw").getChannel();
        this.mappedByteBuffer = this.fileChannel.map(MapMode.READ_WRITE, 0, fileSize);
       //......
    } catch (FileNotFoundException e) {
          //......
    } catch (IOException e) {
         //......
    } finally {
        if (!ok && this.fileChannel != null) {
            this.fileChannel.close();
        }
    }
}

從java開發(fā)者的角度來說,mmap+write技術(shù)在java中的實現(xiàn)有如下優(yōu)缺點(diǎn),先來說說優(yōu)點(diǎn):

  • 通過內(nèi)存映射減少了內(nèi)核緩沖區(qū)和用戶緩沖區(qū)來回拷貝的開銷,提升程序讀寫效率。
  • 對于小文件,這種方式即使頻繁調(diào)用,效果也會比sendfile更好。

說完了優(yōu)點(diǎn),我們再來說說缺點(diǎn):

  • MappedByteBuffer 一次只能映射2G的文件,超出則會拋出異常,這也是為什么RocketMQ的CommitLog日志文件大小為1G。
  • 在網(wǎng)絡(luò)傳輸過程中,內(nèi)核緩沖區(qū)的數(shù)據(jù)仍然需要CPU進(jìn)行拷貝,在某些場景下相較于sendfile會多消耗CPU資源。
  • mmap技術(shù)內(nèi)存分配存在復(fù)雜的安全性控制,對于內(nèi)存進(jìn)行嚴(yán)格管控處理,避免JVM Crash問題。

2. Kafka對于sendfile技術(shù)的運(yùn)用

查看Kafka中FileRecords的writeTo方法可知,Kafka中partition leader到follower的消息同步和consumer拉取partition中的消息,都是直接通過transferFrom(底層就是通過sendfile實現(xiàn))實現(xiàn)的:

// org.apache.kafka.common.record.FileRecords
    @Override
    public long writeTo(GatheringByteChannel destChannel, long offset, int length) throws IOException {
        //......
        if (destChannel instanceof TransportLayer) {
            TransportLayer tl = (TransportLayer) destChannel;
            //調(diào)用transferFrom從channel中拉取數(shù)據(jù)到destChannel中
            bytesTransferred = tl.transferFrom(channel, position, count);
        } else {
         //將channel數(shù)據(jù)寫到destChannel中
            bytesTransferred = channel.transferTo(position, count, destChannel);
        }
        return bytesTransferred;
    }

這種方式實現(xiàn)的零拷貝可以很好的利用DMA方式,盡可能減少CPU的消耗,對于大塊的文件傳輸,效率會高一些,但它也有著如下幾個缺點(diǎn):

  • 就當(dāng)前java的實現(xiàn)而言,它僅僅支持源為FileChannel傳輸?shù)絪ocketChannel,不支持源為socketChannel。
  • 對于小文件傳輸,處理效率不如mmap方式,只能是BIO方式傳輸,不能使用NIO。

三、小結(jié)

零拷貝技術(shù)通過減少或消除數(shù)據(jù)在內(nèi)存中的拷貝次數(shù),以及減少用戶態(tài)與內(nèi)核態(tài)之間的上下文切換,顯著提升了IO操作的性能。本文詳細(xì)介紹了以下幾種零拷貝技術(shù):

  • mmap+write:通過內(nèi)存映射文件技術(shù),將文件直接映射到用戶空間,避免了數(shù)據(jù)在用戶空間和內(nèi)核空間之間的拷貝。
  • sendfile:通過系統(tǒng)調(diào)用直接在內(nèi)核空間中傳輸數(shù)據(jù),避免了用戶空間和內(nèi)核空間之間的數(shù)據(jù)拷貝。
  • splice:通過管道在內(nèi)核空間中傳輸數(shù)據(jù),進(jìn)一步減少了數(shù)據(jù)拷貝。

在實際應(yīng)用中,不同的零拷貝技術(shù)適用于不同的場景:

  • 對于小文件傳輸,mmap方式通常表現(xiàn)更好
  • 對于大文件傳輸,sendfile方式通常表現(xiàn)更好
  • 在網(wǎng)絡(luò)傳輸中,sendfile可以更好地利用DMA技術(shù),減少CPU消耗

通過合理選擇和應(yīng)用零拷貝技術(shù),可以顯著提升系統(tǒng)的IO性能,特別是在處理大量數(shù)據(jù)傳輸?shù)膱鼍爸小?/p>

責(zé)任編輯:趙寧寧 來源: 寫代碼的SharkChili
相關(guān)推薦

2011-07-08 14:14:13

Web服務(wù)器

2013-05-06 15:41:30

Android開發(fā)資源

2013-07-18 17:22:07

Android開發(fā)資源Android開發(fā)學(xué)習(xí)Android開發(fā)

2024-01-10 18:01:22

編程技巧Java 12

2012-03-05 10:01:43

移動開發(fā)

2025-02-10 08:18:27

JSON數(shù)據(jù)交換格式

2015-12-11 14:38:54

開發(fā)快速開發(fā)工具

2025-06-26 03:00:00

2023-11-08 18:01:53

硬重置Git命令

2024-11-04 06:30:00

文本匹配模式Python開發(fā)

2014-02-09 10:30:17

Python程序員工具

2012-05-14 18:35:20

Windows Pho

2023-11-21 20:15:10

Git命令開發(fā)

2016-01-05 13:43:37

谷歌Java競爭

2011-12-01 09:00:12

Android提升開發(fā)性能要點(diǎn)

2020-07-15 07:00:00

移動應(yīng)用開發(fā)者指南

2011-02-25 09:18:50

WebPHPMySQL

2011-07-19 09:51:32

性能優(yōu)化Designing FAndroid

2024-09-18 07:10:00

2010-12-06 14:49:34

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號