自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Java Nio,Netty,Kafka 中經常提到“零拷貝”到底是什么?

開發(fā) 前端
Linux 系統(tǒng)中,傳統(tǒng)的訪問方式是通過 write() 和 read() 兩個系統(tǒng)調用實現(xiàn)的,通過 read() ?函數(shù)讀取文件到到緩存區(qū)中,然后通過 write() 方法把緩存中的數(shù)據(jù)輸出到網(wǎng)絡端口 。

零拷貝技術 Zero-Copy 是指計算機執(zhí)行操作時,可以直接從源(如文件或網(wǎng)絡套接字)將數(shù)據(jù)傳輸?shù)侥繕司彌_區(qū), 而不需要 CPU 先將數(shù)據(jù)從某處內存復制到另一個特定區(qū)域,從而減少上下文切換以及 CPU 的拷貝時間。

1 I/O 中斷原理

在 DMA 技術出現(xiàn)之前,應用程序與磁盤之間的 I/O 操作都是通過 CPU 的中斷完成的。

圖片圖片

  • 用戶進程向 CPU 發(fā)起 read 系統(tǒng)調用讀取數(shù)據(jù),由用戶態(tài)切換為內核態(tài),然后一直阻塞等待數(shù)據(jù)的返回。
  • CPU 在接收到指令以后對磁盤發(fā)起 I/O 請求,將磁盤數(shù)據(jù)先放入磁盤控制器緩沖區(qū)。
  • 數(shù)據(jù)準備完成以后,磁盤向 CPU 發(fā)起 I/O 中斷。
  • CPU 收到 I/O 中斷以后將磁盤緩沖區(qū)中的數(shù)據(jù)拷貝到內核緩沖區(qū),然后再從內核緩沖區(qū)拷貝到用戶緩沖區(qū)。
  • 用戶進程由內核態(tài)切換回用戶態(tài),解除阻塞狀態(tài),然后等待 CPU 的下一個執(zhí)行時間鐘。

可以看到,整個數(shù)據(jù)的傳輸過程,都要需要 CPU 親自參與搬運數(shù)據(jù)的過程,而且這個過程,CPU 是不能做其他事情的。

假如通過千兆網(wǎng)卡或者磁盤傳輸大量數(shù)據(jù)時,使用 CPU 來拷貝的話,對 CPU 資源是種極大的消耗。

2 DMA 方式

DMA 的全稱是直接內存訪問(Direct Memory Access),是一種硬件設備繞開 CPU 獨立直接訪問內存的機制。

目前支持 DMA 的硬件包括:網(wǎng)卡、聲卡、顯卡、磁盤控制器等。

圖片圖片

基于 DMA 訪問方式,系統(tǒng)主內存于硬盤或網(wǎng)卡之間的數(shù)據(jù)傳輸可以繞開 CPU 的全程調度,數(shù)據(jù)搬運的工作交給 DMA 控制器,在傳輸過程中,CPU 可以繼續(xù)處理其他的工作,提升系統(tǒng)的資源利用率。

圖片圖片

  • 用戶進程向 CPU 發(fā)起 read 系統(tǒng)調用讀取數(shù)據(jù),用戶態(tài)切換為內核態(tài),然后一直阻塞等待數(shù)據(jù)的返回。
  • CPU 在接收到指令以后對 DMA 磁盤控制器發(fā)起調度指令。
  • DMA 磁盤控制器對磁盤發(fā)起 I/O 請求,將磁盤數(shù)據(jù)先拷貝到磁盤控制器緩沖區(qū),CPU 全程不參與此過程。
  • 數(shù)據(jù)讀取完成后,DMA 磁盤控制器會接受到磁盤的通知,將數(shù)據(jù)從磁盤控制器緩沖區(qū)拷貝到內核緩沖區(qū)。
  • DMA 磁盤控制器向 CPU 發(fā)出數(shù)據(jù)讀完的信號,由 CPU 負責將數(shù)據(jù)從內核緩沖區(qū)拷貝到用戶緩沖區(qū)。
  • 用戶進程由內核態(tài)切換回用戶態(tài),解除阻塞狀態(tài),然后等待 CPU 的下一個執(zhí)行時間鐘。

3 傳統(tǒng) I/O 方式

為了理解零拷貝技術的思路,首先了解一下傳統(tǒng) I/O 方式存在的問題。

Linux 系統(tǒng)中,傳統(tǒng)的訪問方式是通過 write() 和 read() 兩個系統(tǒng)調用實現(xiàn)的,通過 read()  函數(shù)讀取文件到到緩存區(qū)中,然后通過 write() 方法把緩存中的數(shù)據(jù)輸出到網(wǎng)絡端口 。

圖片圖片

下圖分別對應傳統(tǒng) I/O 操作的數(shù)據(jù)讀寫流程,整個過程涉及 4 次上下文切換、 2 次 CPU 拷貝、2 次 DMA 拷貝總共 4 次拷貝

圖片圖片

  • 4 次上下文切換

因為發(fā)生了兩次系統(tǒng)調用,一次是 read() ,一次是 write(),用戶程序向內核發(fā)起系統(tǒng)調用時,CPU 將用戶進程從用戶態(tài)切換到內核態(tài);當系統(tǒng)調用返回時,CPU 將用戶進程從內核態(tài)切換回用戶態(tài)。

  • 4 次 數(shù)據(jù)拷貝
  • 第一次 DMA 拷貝,將磁盤上的數(shù)據(jù)拷貝到操作系統(tǒng)內核的緩沖區(qū) ;
  • 第二次 CPU 拷貝,將內核緩沖區(qū)的數(shù)據(jù)拷貝到用戶的緩沖區(qū)里;
  • 第三次 CPU 拷貝,將用戶緩沖區(qū)的數(shù)據(jù),拷貝到內核 Socket 緩沖區(qū);
  • 第四次 DMA 拷貝,將內核 Socket 緩沖區(qū)的數(shù)據(jù)拷貝到網(wǎng)卡的緩沖區(qū)。

綜上,想要提升文件傳輸?shù)男阅?,因此我們需要減少「上下文切換」和「數(shù)據(jù)拷貝」的次數(shù)。

3 零拷貝方式

零拷貝技術實現(xiàn)的方式通常有 2 種:mmap + write 、sendfile、sendfile + DMA scatter-gather 。

3.1 mmap + write

mmap 是 Linux 提供的一種內存映射文件的機制,它實現(xiàn)了將內核中讀緩沖區(qū)地址與用戶空間緩沖區(qū)地址進行映射,從而實現(xiàn)內核緩沖區(qū)與用戶緩沖區(qū)的共享。

圖片圖片

基于 mmap + write 系統(tǒng)調用的零拷貝方式,整個拷貝過程會發(fā)生 4 次上下文切換,1 次 CPU 拷貝和 2 次 DMA 拷貝。

圖片圖片

用戶程序讀寫數(shù)據(jù)的流程如下:

  • 用戶進程通過 mmap() 函數(shù)向內核發(fā)起系統(tǒng)調用,上下文從用戶態(tài)切換為內核態(tài)。
  • 將用戶進程的內核空間的讀緩沖區(qū)與用戶空間的緩存區(qū)進行內存地址映射。
  • CPU 利用 DMA 控制器將數(shù)據(jù)從主存或硬盤拷貝到內核空間的讀緩沖區(qū)。
  • 上下文從內核態(tài)切換回用戶態(tài),mmap 系統(tǒng)調用執(zhí)行返回。
  • 用戶進程通過 write() 函數(shù)向內核發(fā)起系統(tǒng)調用,上下文從用戶態(tài)切換為內核態(tài)。
  • CPU 將讀緩沖區(qū)中的數(shù)據(jù)拷貝到的網(wǎng)絡緩沖區(qū)。
  • CPU 利用 DMA 控制器將數(shù)據(jù)從網(wǎng)絡緩沖區(qū)(socket buffer)拷貝到網(wǎng)卡進行數(shù)據(jù)傳輸。
  • 上下文從內核態(tài)切換回用戶態(tài),write 系統(tǒng)調用執(zhí)行返回。

mmap 的拷貝雖然減少了 1 次 CPU 拷貝,提升了效率,但也存在一些隱藏的問題。

當 mmap 一個文件時,如果這個文件被另一個進程所截獲,那么 write 系統(tǒng)調用會因為訪問非法地址被 SIGBUS 信號終止,SIGBUS 默認會殺死進程并產生一個 coredump,服務器可能因此被終止。

3.2 sendfile

sendfile 系統(tǒng)調用在 Linux 內核版本 2.1 中被引入,目的是簡化通過網(wǎng)絡在兩個通道之間進行的數(shù)據(jù)傳輸過程。

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

sendfile 系統(tǒng)調用的引入,不僅減少了 CPU 拷貝的次數(shù),還減少了上下文切換的次數(shù),它的偽代碼如下:

圖片圖片

基于 sendfile 系統(tǒng)調用的零拷貝方式,整個拷貝過程會發(fā)生 2 次上下文切換,1 次 CPU 拷貝和 2 次 DMA 拷貝。

圖片圖片

用戶程序讀寫數(shù)據(jù)的流程如下:

  • 用戶進程通過 sendfile() 函數(shù)向內核發(fā)起系統(tǒng)調用,上下文從用戶態(tài)切換為內核態(tài)。
  • CPU 利用 DMA 控制器將數(shù)據(jù)從主存或硬盤拷貝到內核空間的讀緩沖區(qū)。
  • CPU 將讀緩沖區(qū)中的數(shù)據(jù)拷貝到的網(wǎng)絡緩沖區(qū)。
  • CPU 利用 DMA 控制器將數(shù)據(jù)從網(wǎng)絡緩沖區(qū)拷貝到網(wǎng)卡進行數(shù)據(jù)傳輸。
  • 上下文從內核態(tài)切換回用戶態(tài),sendfile 系統(tǒng)調用執(zhí)行返回。

相比較于 mmap 內存映射的方式,sendfile 少了 2 次上下文切換,但是仍然有 1 次 CPU 拷貝操作。

3.3 sendfile + DMA gather copy

Linux 2.4 版本的內核對 sendfile 系統(tǒng)調用進行修改,為 DMA 拷貝引入了 gather 操作。

它將內核空間的讀緩沖區(qū)中對應的數(shù)據(jù)描述信息(內存地址、地址偏移量)記錄到相應的網(wǎng)絡緩沖區(qū)中,由 DMA 根據(jù)內存地址、地址偏移量將數(shù)據(jù)批量地從讀緩沖區(qū)拷貝到網(wǎng)卡設備中,這樣就省去了內核空間中僅剩的 1 次 CPU 拷貝操作。

圖片圖片

在硬件的支持下,sendfile 拷貝方式不再從內核緩沖區(qū)的數(shù)據(jù)拷貝到 socket 緩沖區(qū),取而代之的僅僅是緩沖區(qū)文件描述符和數(shù)據(jù)長度的拷貝,這樣 DMA 引擎直接利用 gather 操作將頁緩存中數(shù)據(jù)打包發(fā)送到網(wǎng)絡中即可,本質就是和虛擬內存映射的思路類似。

圖片圖片

基于 sendfile + DMA gather copy 系統(tǒng)調用的零拷貝方式,整個拷貝過程會發(fā)生 2 次上下文切換、0 次 CPU 拷貝以及 2 次 DMA 拷貝,用戶程序讀寫數(shù)據(jù)的流程如下:

  • 用戶進程通過 sendfile() 函數(shù)向內核發(fā)起系統(tǒng)調用,上下文從用戶態(tài)切換為內核態(tài)。
  • CPU 利用 DMA 控制器將數(shù)據(jù)從主存或硬盤拷貝到內核空間的讀緩沖區(qū)。
  • CPU 把讀緩沖區(qū)的文件描述符(file descriptor)和數(shù)據(jù)長度拷貝到網(wǎng)絡緩沖區(qū)。
  • 基于已拷貝的文件描述符和數(shù)據(jù)長度,CPU 利用 DMA 控制器的 gather/scatter 操作直接批量地將數(shù)據(jù)從內核的讀緩沖區(qū)拷貝到網(wǎng)卡進行數(shù)據(jù)傳輸。
  • 上下文從內核態(tài)切換回用戶態(tài),sendfile 系統(tǒng)調用執(zhí)行返回。

5 寫到最后

無論是傳統(tǒng) I/O 拷貝方式還是引入零拷貝的方式,2 次 DMA 拷貝是都少不了的,因為兩次 DMA 都是依賴硬件完成的。

拷貝方式

CPU拷貝

DMA拷貝

系統(tǒng)調用

上下文切換

傳統(tǒng)方式(read + write)

2

2

read / write

4

內存映射(mmap + write)

1

2

mmap / write

4

sendfile

1

2

sendfile

2

sendfile + DMA gather copy

0

2

sendfile

2

RocketMQ 選擇了 mmap + write 這種零拷貝方式,適用于業(yè)務級消息這種小塊文件的數(shù)據(jù)持久化和傳輸;

而 Kafka 采用的是 sendfile 這種零拷貝方式,適用于系統(tǒng)日志消息這種高吞吐量的大塊文件的數(shù)據(jù)持久化和傳輸。

但是值得注意的一點是,Kafka 的索引文件使用的是 mmap + write 方式,數(shù)據(jù)文件使用的是 sendfile 方式。

責任編輯:武曉燕 來源: 勇哥Java實戰(zhàn)
相關推薦

2022-10-09 07:33:38

JavaSPI程序

2022-09-23 08:47:01

DMA網(wǎng)卡CPU

2017-09-07 14:44:10

程序員

2024-12-26 17:04:47

2020-10-14 06:22:14

UWB技術感知

2010-11-01 01:25:36

Windows NT

2020-09-22 08:22:28

快充

2020-09-27 06:53:57

MavenCDNwrapper

2011-04-27 09:30:48

企業(yè)架構

2023-10-11 08:29:54

volatileJava原子性

2021-01-21 21:24:34

DevOps開發(fā)工具

2023-07-12 15:32:49

人工智能AI

2020-03-05 10:28:19

MySQLMRR磁盤讀

2021-07-07 05:07:15

JDKIterator迭代器

2021-09-01 23:29:37

Golang語言gRPC

2022-10-08 00:00:00

Spring數(shù)據(jù)庫項目

2021-02-05 10:03:31

區(qū)塊鏈技術智能

2024-02-04 00:01:00

云原生技術容器

2019-10-30 10:13:15

區(qū)塊鏈技術支付寶

2013-06-09 09:47:31

.NetPDBPDB文件
點贊
收藏

51CTO技術棧公眾號