日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網為廣大站長提供免費收錄網站服務,提交前請做好本站友鏈:【 網站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

當涉及到網絡編程和IO操作時,數據拷貝是一個常見的性能瓶頸。傳統的數據拷貝過程中,數據需要從內核緩沖區復制到用戶空間緩沖區,然后再從用戶空間緩沖區復制到內核緩沖區,這個過程會耗費大量的CPU時間和內存帶寬,降低系統的性能和吞吐量。

為了解決這個問題,零拷貝技術應運而生。零拷貝技術是指在數據傳輸過程中,避免將數據從一塊內存拷貝到另一塊內存,從而減少了CPU的開銷和內存帶寬的消耗,提高了系統的性能。

在JAVA后端開發中,使用零拷貝技術可以有效提升系統的性能和吞吐量。本文將介紹零拷貝技術的概念、實現原理以及在Java后端開發中的應用,希望能夠為讀者提供有價值的參考和幫助。

一、傳統I/O

在展開說零拷貝之前,我們先來回顧一下傳統IO的方式是怎么樣的。

早期的數據IO,由用戶進程向CPU發起,應用程序與磁盤之間的 I/O 操作都是通過 CPU 的中斷完成的。CPU還要負責將磁盤緩沖區拷貝到內核緩沖區(pageCache),再從內核緩沖區拷貝到用戶緩沖區。為了減少CPU占用,產生了DMA技術,大大解放了CPU。

DMA 的全稱叫直接內存存取(Direct Memory Access),是一種允許外圍設備(硬件子系統)直接訪問系統主內存的機制。目前大多數的硬件設備,包括磁盤控制器、網卡、顯卡以及聲卡等都支持 DMA 技術。

1.1傳統I/O的問題

我們以讀取一張圖片數據的過程為例來分析傳統IO有哪些問題。傳統的訪問方式是通過 write() 和 read() 兩個系統調用實現的,通過 read() 函數讀取圖片到到緩存區中,然后通過 write() 方法把緩存中的圖片輸出到網絡端口。

read操作:

當應用程序執行 read 系統調用讀取一塊數據的時候,如果這塊數據已經存在于用戶進程的頁內存中,就直接從內存中讀取數據。

如果數據不存在,則先將數據從磁盤加載數據到內核空間的讀緩存(read buffer)中,再從讀緩存拷貝到用戶進程的頁內存中。

write操作:

當應用程序準備好數據,執行 write 系統調用發送網絡數據時,先將數據從用戶空間的頁緩存拷貝到內核空間的網絡緩沖區(socket buffer)中,然后再將寫緩存中的數據拷貝到網卡設備完成數據發送。

從上圖中可以看出,整個IO的過程需要進行兩次DMA拷貝,兩次CPU拷貝,四次上下文切換。總共四次拷貝,四次切換。這個代價確實有些大。

說完傳統IO,接下來我們看下零拷貝都做了哪些優化。

二、零拷貝

2.1什么是零拷貝

零拷貝這個詞,在很多地方都出現過,比如Kafka、Nginx、Tomcat等等這些技術的底層都有用到零拷貝技術,那么究竟什么是零拷貝呢?

零拷貝是指在數據傳輸過程中,避免了數據的多次拷貝,從而提高了數據傳輸的效率。在傳統的IO模型中,數據從磁盤中讀取到內核緩沖區,然后再從內核緩沖區拷貝到用戶緩沖區,最后再從用戶緩沖區拷貝到應用程序中。而在零拷貝模型中,數據可以直接從內核緩沖區拷貝到應用程序中,避免了數據的多次拷貝,提高了數據傳輸的效率。零拷貝技術可以通過mmap和sendfile等系統調用實現。

所以說零拷貝并不是說不拷貝,而是減少拷貝的次數,因為從磁盤中拷貝數據到內存,或者從內存中的一塊兒區域拷貝到另一塊兒區域都是一個耗費性能的操作。零拷貝技術的目的就是減少這種行為的發生次數以此來提高性能。

2.2零拷貝實現的幾種方式

對比開頭說到的傳統IO,我們可以在以下幾個方面進行優化

1. 用戶態可以直接操作讀寫,不需要在用戶態和內核態之間反復橫跳。

2. 盡量減少拷貝次數,盡量減少上下文切換次數。

3. 寫時復制,需要寫操作的時候再拷貝,只是讀操作沒必要拷貝

用戶態直接IO

用戶態直接 I/O 使得應用進程或運行在用戶態(user space)下的庫函數直接訪問硬件設備。

用戶態直接 I/O 只能適用于不需要內核緩沖區處理的應用程序,這些應用程序通常在進程地址空間有自己的數據緩存機制,稱為自緩存應用程序,如數據庫管理系統 就是一個代表。

其次,這種零拷貝機制會直接操作磁盤 I/O,由于 CPU 和磁盤 I/O 之間的執行時間差距,會造成大量資源的浪費,解決方案是配合異步 I/O 使用。

寫時復制

寫時復制指的是當多個進程共享同一塊數據時,如果其中一個進程需要對這份數據進行修改,那么就需要將其拷貝到自己的進程地址空間中。

這樣做并不影響其他進程對這塊數據的操作,每個進程要修改的時候才會進行拷貝,所以叫寫時拷貝。

減少拷貝次數

1. mmap+write零拷貝技術

以mmap+write的方式替代傳統的read+write的方式,減少了一次拷貝。

mmap 是 linux 提供的一種內存映射文件方法,即將一個進程的地址空間中的一段虛擬地址映射到磁盤文件地址使用 mmap 的目的是將內核中讀緩沖區(read buffer)的地址與用戶空間的緩沖區(user buffer)進行映射。從而實現內核緩沖區與應用程序內存的共享,省去了將數據從內核讀緩沖區(read buffer)拷貝到用戶緩沖區(user buffer)的過程。

整個拷貝過程會發生 4 次上下文切換,1 次 CPU 拷貝和 2 次 DMA 拷貝。mmap 主要的用處是提高 I/O 性能,特別是針對大文件。對于小文件,內存映射文件反而會導致碎片空間的浪費。

2. Sendfile零拷貝技術

通過 Sendfile 系統調用,數據可以直接在內核空間內部進行 I/O 傳輸,從而省去了數據在用戶空間和內核空間之間的來回拷貝。

將要讀取的文件緩沖區的文件 fd 和要發送的Socket緩沖區的Socket fd 傳給sendfile函數,Sendfile 調用中 I/O 數據對用戶空間是完全不可見的。也就是說,這是一次完全意義上的數據傳輸過程。也就是說用戶程序不能對數據進行修改,而只是單純地完成了一次數據傳輸過程。整個拷貝過程會發生 2 次上下文切換,1 次 CPU 拷貝和 2 次 DMA 拷貝。

3. Sendfile+DMA gather copy

它只適用于將數據從文件拷貝到 socket 套接字上的傳輸過程。

它將內核空間的讀緩沖區(read buffer)中對應的數據描述信息(內存地址、地址偏移量)記錄到相應的網絡緩沖區( socket buffer)中,由 DMA 根據內存地址、地址偏移量將數據批量地從讀緩沖區(read buffer)拷貝到網卡設備中。

這樣 DMA 引擎直接利用 gather 操作將頁緩存中數據打包發送到網絡中即可,本質就是和虛擬內存映射的思路類似。

整個拷貝過程會發生 2 次上下文切換、0 次 CPU 拷貝以及 2 次 DMA 拷貝。

4.Splice零拷貝技術

Splice相當于在Sendfile+DMA gather copy上的提升,Splice 系統調用可以在內核空間的讀緩沖區(read buffer)和網絡緩沖區(socket buffer)之間建立管道(pipeline),從而避免了兩者之間的 CPU 拷貝操作。

基于 Splice 系統調用的零拷貝方式,整個拷貝過程會發生 2 次上下文切換,0 次 CPU 拷貝以及 2 次 DMA 拷貝。

2.3總結

無論是傳統I/O拷貝方式,還是引入了零拷貝的方式,2次DMA Copy都是必要的步驟,因為兩次DMA都是依賴硬件完成的。

三、零拷貝的實際應用

3.1JavaNIO基于零拷貝的實現

Java-NIO:主要有三個方面用到了零拷貝技術:

MAppedByteBuffer.map():底層調用了操作系統的mmap()內核函數。

DirectByteBuffer.allocateDirect():可以直接創建基于本地內存的緩沖區。

FileChannel.transferFrom()/transferTo():底層調用了sendfile()內核函數。

3.2主流技術中零拷貝的應用

1..NETty中零拷貝的應用

Netty中的零拷貝是一種用戶進程級別的零拷貝體現,主要也包含三方面:

1) Netty的發送、接收數據的ByteBuf緩沖區,默認會使用堆外本地內存創建,采用直接內存進行Socket讀寫,數據傳輸時無需經過二次拷貝。如果使用傳統的堆內存進行Socket網絡數據讀寫,JVM需要先將堆內存中的數據拷貝一份到直接內存,然后才寫入Socket緩沖區中,相較于堆外直接內存,消息在發送過程中多了一次緩沖區的內存拷貝。

2)Netty的文件傳輸采用了transferTo()/transferFrom()方法,它可以直接將文件緩沖區的數據發送到目標Channel(Socket),底層就是調用了sendfile()內核函數,避免了文件數據的CPU拷貝過程。

3)Netty提供了組合、拆解ByteBuf對象的API,咱們可以基于一個ByteBuf對象,對數據進行拆解,也可以基于多個ByteBuf對象進行數據合并,這個過程中不會出現數據拷貝,這個是程序級別的零拷貝,實際上就是在原數據的基礎上用不同的引用表示而已。

2. 其他技術中的零拷貝技術應用

Kafka底層基于java.nio包下的FileChannel.transferTo()實現零拷貝。Kafka Server基于FileChannel將文件中的消息數據發送到SocketChannel。

RocketMQ基于mmap + write的方式實現零拷貝。內部實現基于nio提供的java.nio.MappedByteBuffer,基于FileChannel的map方法得到mmap的緩沖區。

分享到:
標簽:拷貝
用戶無頭像

網友整理

注冊時間:

網站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網站吧!
最新入駐小程序

數獨大挑戰2018-06-03

數獨一種數學游戲,玩家需要根據9

答題星2018-06-03

您可以通過答題星輕松地創建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數有氧達人2018-06-03

記錄運動步數,積累氧氣值。還可偷

每日養生app2018-06-03

每日養生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定