亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

零拷貝的原理以及java實現方式

發布時間:2021-08-13 13:43:26 來源:億速云 閱讀:151 作者:chen 欄目:開發技術

本篇內容介紹了“零拷貝的原理以及java實現方式”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!

目錄
  • 零拷貝

  • 傳統I/O操作存在的性能問題

  • 零拷貝技術原理

    • 虛擬內存

    • mmap/write 方式

    • sendfile 方式

    • 帶有 scatter/gather 的 sendfile方式

    • splice 方式

  • 總結

    零拷貝

    零拷貝(Zero-Copy)是一種 I/O 操作優化技術,可以快速高效地將數據從文件系統移動到網絡接口,而不需要將其從內核空間復制到用戶空間。其在 FTP 或者 HTTP 等協議中可以顯著地提升性能。但是需要注意的是,并不是所有的操作系統都支持這一特性,目前只有在使用 NIO 和 Epoll 傳輸時才可使用該特性。

    需要注意,它不能用于實現了數據加密或者壓縮的文件系統上,只有傳輸文件的原始內容。這類原始內容也包括加密了的文件內容。

    傳統I/O操作存在的性能問題

    如果服務端要提供文件傳輸的功能,我們能想到的最簡單的方式是:將磁盤上的文件讀取出來,然后通過網絡協議發送給客戶端。

    傳統 I/O 的工作方式是,數據讀取和寫入是從用戶空間到內核空間來回復制,而內核空間的數據是通過操作系統層面的 I/O 接口從磁盤讀取或寫入。

    代碼通常如下,一般會需要兩個系統調用:

    read(file, tmp_buf, len);
    write(socket, tmp_buf, len);

    代碼很簡單,雖然就兩行代碼,但是這里面發生了不少的事情。

    零拷貝的原理以及java實現方式

    首先,期間共發生了 4 次用戶態與內核態的上下文切換,因為發生了兩次系統調用,一次是 read() ,一次是 write(),每次系統調用都得先從用戶態切換到內核態,等內核完成任務后,再從內核態切換回用戶態。

    上下文切換到成本并不小,一次切換需要耗時幾十納秒到幾微秒,雖然時間看上去很短,但是在高并發的場景下,這類時間容易被累積和放大,從而影響系統的性能。

    其次,還發生了 4 次數據拷貝,其中兩次是 DMA 的拷貝,另外兩次則是通過 CPU 拷貝的,下面說一下這個過程:

    • 第一次拷貝,把磁盤上的數據拷貝到操作系統內核的緩沖區里,這個拷貝的過程是通過 DMA 搬運的。

    • 第二次拷貝,把內核緩沖區的數據拷貝到用戶的緩沖區里,于是我們應用程序就可以使用這部分數據了,這個拷貝到過程是由 CPU 完成的。

    • 第三次拷貝,把剛才拷貝到用戶的緩沖區里的數據,再拷貝到內核的 socket 的緩沖區里,這個過程依然還是由 CPU 搬運的。

    • 第四次拷貝,把內核的 socket 緩沖區里的數據,拷貝到網卡的緩沖區里,這個過程又是由 DMA 搬運的。

    這種簡單又傳統的文件傳輸方式,存在冗余的上文切換和數據拷貝,在高并發系統里是非常糟糕的,多了很多不必要的開銷,會嚴重影響系統性能。

    所以,要想提高文件傳輸的性能,就需要減少「用戶態與內核態的上下文切換」和「內存拷貝」的次數。

    零拷貝技術原理

    零拷貝主要是用來解決操作系統在處理 I/O 操作時,頻繁復制數據的問題。關于零拷貝主要技術有 mmap+write、sendfile和splice等幾種方式。

    虛擬內存

    在了解零拷貝技術之前,先了解虛擬內存的概念。
    所有現代操作系統都使用虛擬內存,使用虛擬地址取代物理地址,主要有以下幾點好處:

    • 多個虛擬內存可以指向同一個物理地址。

    • 虛擬內存空間可以遠遠大于物理內存空間。

    利用上述的第一條特性可以優化,可以把內核空間和用戶空間的虛擬地址映射到同一個物理地址,這樣在 I/O 操作時就不需要來回復制了。

    如下圖展示了虛擬內存的原理。

    零拷貝的原理以及java實現方式

    mmap/write 方式

    使用mmap/write方式替換原來的傳統I/O方式,就是利用了虛擬內存的特性。下圖展示了mmap/write原理:

    零拷貝的原理以及java實現方式

    整個流程的核心區別就是,把數據讀取到內核緩沖區后,應用程序進行寫入操作時,直接把內核的Read Buffer的數據復制到Socket Buffer以便寫入,這次內核之間的復制也是需要CPU的參與的。

    上述流程就是少了一個 CPU COPY,提升了 I/O 的速度。不過發現上下文的切換還是4次并沒有減少,這是因為還是要應用程序發起write操作。

    那能不能減少上下文切換呢?這就需要sendfile方式來進一步優化了。

    sendfile 方式

    從 Linux 2.1 版本開始,Linux 引入了 sendfile來簡化操作。sendfile方式可以替換上面的mmap/write方式來進一步優化。

    sendfile將以下操作:

      mmap();
      write();

    替換為:

     sendfile();

    這樣就減少了上下文切換,因為少了一個應用程序發起write操作,直接發起sendfile操作。

    下圖展示了sendfile原理:

    零拷貝的原理以及java實現方式

    sendfile方式只有三次數據復制(其中只有一次 CPU COPY)以及2次上下文切換。

    那能不能把 CPU COPY 減少到沒有呢?這樣需要帶有 scatter/gather的sendfile方式了。

    帶有 scatter/gather 的 sendfile方式

    Linux 2.4 內核進行了優化,提供了帶有 scatter/gather 的 sendfile 操作,這個操作可以把最后一次 CPU COPY 去除。其原理就是在內核空間 Read BUffer 和 Socket Buffer 不做數據復制,而是將 Read Buffer 的內存地址、偏移量記錄到相應的 Socket Buffer 中,這樣就不需要復制。其本質和虛擬內存的解決方法思路一致,就是內存地址的記錄。

    下圖展示了scatter/gather 的 sendfile 的原理:

    零拷貝的原理以及java實現方式

    scatter/gather 的 sendfile 只有兩次數據復制(都是 DMA COPY)及 2 次上下文切換。CUP COPY 已經完全沒有。不過這一種收集復制功能是需要硬件及驅動程序支持的。

    splice 方式

    splice 調用和sendfile 非常相似,用戶應用程序必須擁有兩個已經打開的文件描述符,一個表示輸入設備,一個表示輸出設備。與sendfile不同的是,splice允許任意兩個文件互相連接,而并不只是文件與socket進行數據傳輸。對于從一個文件描述符發送數據到socket這種特例來說,一直都是使用sendfile系統調用,而splice一直以來就只是一種機制,它并不僅限于sendfile的功能。也就是說 sendfile 是 splice 的一個子集。

    在 Linux 2.6.17 版本引入了 splice,而在 Linux 2.6.23 版本中, sendfile 機制的實現已經沒有了,但是其 API 及相應的功能還在,只不過 API 及相應的功能是利用了 splice 機制來實現的。

    和 sendfile 不同的是,splice 不需要硬件支持。

    總結

    無論是傳統的 I/O 方式,還是引入了零拷貝之后,2 次 DMA copy是都少不了的。因為兩次 DMA 都是依賴硬件完成的。所以,所謂的零拷貝,都是為了減少 CPU copy 及減少了上下文的切換。
    下圖展示了各種零拷貝技術的對比圖:


    CPU拷貝DMA拷貝系統調用上下文切換
    傳統方法22read/write4
    內存映射12mmap/write4
    sendfile12sendfile2
    scatter/gather copy02sendfile2
    splice02splice0

    “零拷貝的原理以及java實現方式”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!

    向AI問一下細節

    免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

    AI

    廉江市| 阿克苏市| 普兰店市| 建昌县| 广宗县| 广州市| 门头沟区| 长顺县| 桃源县| 东台市| 樟树市| 连南| 舒兰市| 邓州市| 紫金县| 遂宁市| 博野县| 凌海市| 扬中市| 巴林左旗| 平舆县| 蒙自县| 六安市| 红安县| 万安县| 固安县| 马公市| 成武县| 肇州县| 焉耆| 峨边| 梧州市| 贵德县| 安塞县| 乌兰县| 砚山县| 德州市| 宁都县| 仙桃市| 庆城县| 荣成市|