妹妹10分鐘就玩懂了零拷貝和NIO,也太強了

2021-10-20 01:23:46 字數 4038 閱讀 6989

'零拷貝'這個詞大家應該不陌生了,也算是大廠面試中的乙個高頻考點,玩過 netty 的朋友應該對此相當熟悉了,netty 的「高併發」很大程度上都是因為 nio,而 nio 的核心就是零拷貝技術了,今天就讓你十分鐘玩懂零拷貝。

我們來看一張圖,讓我們看看乙個檔案從磁碟傳輸到網絡卡究竟要經歷什麼樣的磨難:

這種資料儲存的區域整體我們把它叫做「非直接緩衝區」

我們發現,居然有四步資料拷貝的過程!!並且整個資料的傳輸過程都是「需要 cpu 去執行」的。

這個過程也太繁瑣了,我就想傳輸一些資料,幹嘛要傳到使用者這裡,還要我自己再走一遍後續的流程,寫到 socket 緩衝區再發出去,你不能幫我實現嗎?

我們繼續看上面的流程圖理一下,看看哪些步驟是可以去掉的

我們發現在整個過程中,資料從磁碟讀出來到傳送給網絡卡,「檔案內容」都是「不會發生改變」的,但是我卻要經歷「4次檔案內容的拷貝」才真正能將檔案傳輸到網絡卡。

那麼以最簡單的的方式來說,「能不能直接將磁碟中的資料傳輸到網絡卡呢?」

當然不可以,這個原因也很簡單,因為「網絡卡和磁碟都是外部裝置」,所以一定要有乙個中間的緩衝區域來取儲存資料,做乙個**的作用。

那麼我們看上圖中能做緩衝的有兩個區域,乙個是「socket緩衝區」,乙個是「核心緩衝區」,那麼用哪乙個?

這個問題應該很好選擇了,socket 肯定不可以,socket 和我作業系統無瓜,那麼只有用核心緩衝區來做緩衝區。

那麼能不能通過「核心緩衝區直接給網絡卡」傳送資料呢?

看樣子是可以的,那麼我們來看看,socket 緩衝區的作用是什麼?

每個 socket 被建立後,都會分配兩個緩衝區,輸入緩衝區和輸出緩衝區。

write()/send() 並不立即向網路中傳輸資料,而是先將資料寫入緩衝區中,再由 tcp 協議將資料從緩衝區傳送到目標機器。一旦將資料寫入到緩衝區,函式就可以成功返回,不管它們有沒有到達目標機器,也不管它們何時被傳送到網路,這些都是 tcp 協議負責的事情。

所以socket就是用來「傳輸網路資料」的,看來沒它還不行。

但是我們換個思路,是不是說,只需要「告訴 socket 要傳輸哪些資料」就可以了?然後檔案內容就可以直接用核心緩衝區的就好了。

當你讀懂了上面的內容,基本上已經能摸到零拷貝的核心脈絡了,其實零拷貝就是使用「記憶體對映」來消除資料拷貝次數的,然後使用「dma」技術來減少cpu的工作時間。

就只從拷貝次數的效能來看,可以講效能提高至少百分之五十以上。

上文中經常提到乙個很重要的詞彙 - dma ,它在整個零拷貝的流程當中是有很大的佔比的,「能幫助 cpu 做大量的工作」,我們來介紹一下這個神奇的技術。

dma就是「直接儲存器訪問」,dma (direct memory access,「直接儲存器訪問」) 是所有現代電腦的重要特色,它允許不同速度的硬體裝置來溝通,而不需要依賴於 cpu 的大量中斷負載。否則,cpu 需要從**把每一片段的資料複製到暫存器,然後把它們再次寫回到新的地方。在這個時間中,cpu 對於其他的工作來說就無法使用。

「原理」:dma 傳輸將資料「從乙個位址空間複製到另外乙個位址空間」。當 cpu 初始化這個傳輸動作,傳輸動作本身是由 dma 控制器來實行和完成。

看到這裡的話相信你對零拷貝已經有了深刻的理解,那麼 nio 到底是什麼的?既然說了十分鐘讓你玩懂 nio 和零拷貝,那 nio 必不可少。

所有的系統i/o都分為「兩個階段」

需要說明的是等待就緒的阻塞是不使用cpu的,是在「「空等」」;而真正的讀寫操作的阻塞是使用cpu的,真正在」幹活」,而且這個過程非常快,屬於memory copy,頻寬通常在1gb/s級別以上,可以理解為「基本不耗時」

在傳統的 socket io中,需要為每個連線建立乙個執行緒。

「乙個執行緒對應乙個連線,只處理乙個連線的事情」,這就是傳統的socket io。

「併發的連線數量非常巨大」時,執行緒所占用的棧記憶體和cpu執行緒「切換的開銷就會非常大」

在這種情境下還可能會出現「執行緒數量小於連線數量」的情況,所以每個執行緒進行 i o操作時就不能阻塞,如果阻塞的話,有些連線就得不到處理。

如上圖,假設有三條執行緒在管理三條連線,如果此時有第四個任務插入,那麼就只能等待前面任務執行完成。

其操作就像是一條流水線一樣,是序列阻塞的,故傳統 io 我們也稱為「bio」

傳統 io 也「不知道什麼時候該處理資料」,所以只能一直傻等。

為了解決這些問題,nio 就出現了。

我們先來介紹一下 nio 的核心元件

buffer(緩衝區)

selectors(選擇器)

通道有如下4個事件可供我們監聽:

accept:有可以接受的連線

connect:連線成功

read:有資料可讀

write:可以寫入資料了

我們首先需要註冊當這幾個事件到來的時候所對應的處理器。然後在合適的時機告訴事件選擇器:我對這個事件感興趣。

也就是說,在選擇器上註冊了這四個事件的處理器,用來處理 channel 的事件,「當 channel 某個事件真的準備就緒了,可以進行下一步的動作時,再告訴服務端來處理相應的資料,把相應的任務分配給服務端」,這樣就能更好的利用 cpu 的資源。

前面我們說的零拷貝,就是在這時資料處理時發生的。

從傳統 io 模型 到 nio 零拷貝模型我們可以看出,乙個新技術的產生到崛起肯定是因為「其能滿足之前技術滿足不了的需求,或者相對於之前技術的效能有很高的提公升」

傳統 io 傳輸需要進行四次的資料內容拷貝,包括「核心態和使用者態」的切換,「核心態和資料載體」(磁碟、網絡卡)的切換,整個過程是阻塞的,過程浪費了很多資源。

而 nio 是通過選擇器,通道等核心模組,將整個 io 處理過程變為非同步的方式,只有其資料任務真正就緒了,才會讓 cpu 去做處理,大量的節省了資源,提高了效能。

零拷貝就是讓使用者態和核心態之間的資料不再通過拷貝的方式傳輸,使用了「記憶體對映」,做到了核心態和使用者態資料的零拷貝。

其拷貝方式使用了「dma」技術,其目的就是為了解決 cpu 拷貝資料的方式,讓「拷貝資料」這種累活「不再占用 cpu 的資源」,有 dma 去完成。

因為是使用了記憶體對映的關係,所以零拷貝技術「無法對資料內容做更改」

kafka原理和實踐(一)原理 10分鐘入門

目錄 正文 系列目錄 kafka原理和實踐 一 原理 10分鐘入門 kafka原理和實踐 二 spring kafka簡單實踐 kafka原理和實踐 三 spring kafka生產者原始碼 kafka原理和實踐 四 spring kafka消費者原始碼 kafka原理和實踐 五 spring ka...

教你10分鐘讀懂python閉包和裝飾器

先來講一下閉包的定義,在函式巢狀的情況下,在函式內部使用了外部函式的引數或者變數,並把這個內部函式返回,那麼這個返回的函式就叫做閉包。簡單來說,閉包就是對應乙個函式,不理解沒關係,接下來我們用 講解。def show 外部函式 num 10 外部函式的變數 def inner 內部函式 print ...

泊松分布和指數分布 10分鐘教程

大學時,我一直覺得統計學很難,還差點掛科。工作以後才發現,難的不是統計學,而是我們的教材寫得不好。比起高等數學,統計概念其實很容易理解。我舉乙個例子,什麼是泊松分布和指數分布?恐怕大多數人都說不清楚。我可以在 10 分鐘內,讓你毫不費力地理解這兩個概念。一 泊松分布 日常生活中,大量事件是有固定頻率...