日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

可算是有文章,把Linux零拷贝讲透彻了!

發布時間:2024/4/11 linux 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 可算是有文章,把Linux零拷贝讲透彻了! 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

擊上方“朱小廝的博客”,選擇“設為星標”

后臺回復"加群",加入組織

來源:22j.co/brVn

本文探討 Linux 中主要的幾種零拷貝技術以及零拷貝技術的適用場景。為了迅速建立起零拷貝的概念,我們拿一個常用的場景進行引入。在寫一個服務端程序時(Web Server或者文件服務器),文件下載是一個基本功能。

這時候服務端的任務是:將服務端主機磁盤中的文件不做修改地從已連接的 Socket 發出去。

我們通常用下面的代碼完成:

while((n?=?read(diskfd,?buf,?BUF_SIZE))?>?0)write(sockfd,?buf?,?n);

基本操作就是循環的從磁盤讀入文件內容到緩沖區,再將緩沖區的內容發送到 Socket。但是由于 Linux 的 I/O 操作默認是緩沖 I/O。

這里面主要使用的也就是 Read 和 Write 兩個系統調用,我們并不知道操作系統在其中做了什么。實際上在以上 I/O 操作中,發生了多次的數據拷貝。

當應用程序訪問某塊數據時,操作系統首先會檢查,是不是最近訪問過此文件,文件內容是否緩存在內核緩沖區。

如果是,操作系統則直接根據 Read 系統調用提供的 buf 地址,將內核緩沖區的內容拷貝到 buf 所指定的用戶空間緩沖區中去。

如果不是,操作系統則首先將磁盤上的數據拷貝的內核緩沖區,這一步目前主要依靠 DMA 來傳輸,然后再把內核緩沖區上的內容拷貝到用戶緩沖區中。

接下來,Write 系統調用再把用戶緩沖區的內容拷貝到網絡堆棧相關的內核緩沖區中,最后 Socket 再把內核緩沖區的內容發送到網卡上。

說了這么多,不如看圖清楚:

數據拷貝

從上圖中可以看出,共產生了四次數據拷貝,即使使用了 DMA 來處理了與硬件的通訊,CPU 仍然需要處理兩次數據拷貝。

與此同時,在用戶態與內核態也發生了多次上下文切換,無疑也加重了 CPU 負擔。

在此過程中,我們沒有對文件內容做任何修改,那么在內核空間和用戶空間來回拷貝數據無疑就是一種浪費,而零拷貝主要就是為了解決這種低效性。

什么是零拷貝技術(zero-copy)?

零拷貝主要的任務就是避免 CPU 將數據從一塊存儲拷貝到另外一塊存儲。

主要就是利用各種零拷貝技術,避免讓 CPU 做大量的數據拷貝任務,減少不必要的拷貝,或者讓別的組件來做這一類簡單的數據傳輸任務,讓 CPU 解脫出來專注于別的任務。這樣就可以讓系統資源的利用更加有效。

我們繼續回到上文中的例子,我們如何減少數據拷貝的次數呢?一個很明顯的著力點就是減少數據在內核空間和用戶空間來回拷貝,這也引入了零拷貝的一個類型:讓數據傳輸不需要經過 user space。

使用 mmap

我們減少拷貝次數的一種方法是調用 mmap() 來代替 read 調用:

buf?=?mmap(diskfd,?len); write(sockfd,?buf,?len);

應用程序調用 mmap(),磁盤上的數據會通過 DMA 被拷貝的內核緩沖區,接著操作系統會把這段內核緩沖區與應用程序共享,這樣就不需要把內核緩沖區的內容往用戶空間拷貝。

應用程序再調用 write(),操作系統直接將內核緩沖區的內容拷貝到 Socket 緩沖區中,這一切都發生在內核態,最后,Socket 緩沖區再把數據發到網卡去。

同樣的,看圖很簡單:

mmap

使用 mmap 替代 Read 很明顯減少了一次拷貝,當拷貝數據量很大時,無疑提升了效率。

但是使用 mmap 是有代價的。當你使用 mmap 時,你可能會遇到一些隱藏的陷阱。

例如,當你的程序 map 了一個文件,但是當這個文件被另一個進程截斷 (truncate) 時,Write 系統調用會因為訪問非法地址而被 SIGBUS 信號終止。

SIGBUS 信號默認會殺死你的進程并產生一個 coredump,如果你的服務器這樣被中止了,那會產生一筆損失。

通常我們使用以下解決方案避免這種問題:

①為 SIGBUS 信號建立信號處理程序

當遇到 SIGBUS 信號時,信號處理程序簡單地返回,Write 系統調用在被中斷之前會返回已經寫入的字節數,并且 errno 會被設置成 success,但是這是一種糟糕的處理辦法,因為你并沒有解決問題的實質核心。

②使用文件租借鎖

通常我們使用這種方法,在文件描述符上使用租借鎖,我們為文件向內核申請一個租借鎖。

當其他進程想要截斷這個文件時,內核會向我們發送一個實時的 RTSIGNALLEASE 信號,告訴我們內核正在破壞你加持在文件上的讀寫鎖。

這樣在程序訪問非法內存并且被 SIGBUS 殺死之前,你的 Write 系統調用會被中斷。Write 會返回已經寫入的字節數,并且置 errno 為 success。

我們應該在 mmap 文件之前加鎖,并且在操作完文件后解鎖:

if(fcntl(diskfd,?F_SETSIG,?RT_SIGNAL_LEASE)?==?-1)?{perror("kernel?lease?set?signal");return?-1; } /*?l_type?can?be?F_RDLCK?F_WRLCK??加鎖*/ /*?l_type?can?be??F_UNLCK?解鎖*/ if(fcntl(diskfd,?F_SETLEASE,?l_type)){perror("kernel?lease?set?type");return?-1; }

使用 sendfile

從 2.1 版內核開始,Linux 引入了 sendfile 來簡化操作:

#include<sys/sendfile.h> ssize_t?sendfile(int?out_fd,?int?in_fd,?off_t?*offset,?size_t?count);

系統調用 sendfile() 在代表輸入文件的描述符 infd 和代表輸出文件的描述符 outfd 之間傳送文件內容(字節)。

描述符 outfd 必須指向一個套接字,而 infd 指向的文件必須是可以 mmap 的。

這些局限限制了 sendfile 的使用,使 sendfile 只能將數據從文件傳遞到套接字上,反之則不行。

使用 sendfile 不僅減少了數據拷貝的次數,還減少了上下文切換,數據傳送始終只發生在 kernel space。

sendfile 系統調用過程

在我們調用 sendfile 時,如果有其它進程截斷了文件會發生什么呢?假設我們沒有設置任何信號處理程序,sendfile 調用僅僅返回它在被中斷之前已經傳輸的字節數,errno 會被置為 success。

如果我們在調用 sendfile 之前給文件加了鎖,sendfile 的行為仍然和之前相同,我們還會收到 RTSIGNALLEASE 的信號。

目前為止,我們已經減少了數據拷貝的次數了,但是仍然存在一次拷貝,就是頁緩存到 Socket 緩存的拷貝。那么能不能把這個拷貝也省略呢?

借助于硬件上的幫助,我們是可以辦到的。之前我們是把頁緩存的數據拷貝到 Socket 緩存中。

實際上,我們僅僅需要把緩沖區描述符傳到 Socket 緩沖區,再把數據長度傳過去,這樣 DMA 控制器直接將頁緩存中的數據打包發送到網絡中就可以了。

總結一下:sendfile 系統調用利用 DMA 引擎將文件內容拷貝到內核緩沖區去,然后將帶有文件位置和長度信息的緩沖區描述符添加 Socket 緩沖區去。

這一步不會將內核中的數據拷貝到 Socket 緩沖區中,DMA 引擎會將內核緩沖區的數據拷貝到協議引擎中去,避免了最后一次拷貝。

帶 DMA 的 sendfile

不過這一種收集拷貝功能是需要硬件以及驅動程序支持的。

使用?splice

sendfile 只適用于將數據從文件拷貝到套接字上,限定了它的使用范圍。

Linux 在 2.6.17 版本引入 splice 系統調用,用于在兩個文件描述符中移動數據:

#define?_GNU_SOURCE?????????/*?See?feature_test_macros(7)?*/ #include?<fcntl.h> ssize_t?splice(int?fd_in,?loff_t?*off_in,?int?fd_out,?loff_t?*off_out,?size_t?len,?unsigned?int?flags);

splice 調用在兩個文件描述符之間移動數據,而不需要數據在內核空間和用戶空間來回拷貝。

他從 fdin 拷貝 len 長度的數據到 fdout,但是有一方必須是管道設備,這也是目前 splice 的一些局限性。

flags 參數有以下幾種取值:

  • SPLICEFMOVE:嘗試去移動數據而不是拷貝數據。這僅僅是對內核的一個小提示:如果內核不能從 pipe 移動數據或者 pipe 的緩存不是一個整頁面,仍然需要拷貝數據。

    Linux 最初的實現有些問題,所以從 2.6.21 開始這個選項不起作用,后面的 Linux 版本應該會實現。

  • SPLICEFNONBLOCK:splice 操作不會被阻塞。然而,如果文件描述符沒有被設置為不可被阻塞方式的 I/O ,那么調用 splice 有可能仍然被阻塞。

  • SPLICEFMORE:后面的 splice 調用會有更多的數據。

splice 調用利用了 Linux 提出的管道緩沖區機制, 所以至少一個描述符要為管道。

以上幾種零拷貝技術都是減少數據在用戶空間和內核空間拷貝技術實現的,但是有些時候,數據必須在用戶空間和內核空間之間拷貝。

這時候,我們只能針對數據在用戶空間和內核空間拷貝的時機上下功夫了。

Linux 通常利用寫時復制(copy on write)來減少系統開銷,這個技術又時常稱作 COW。

由于篇幅原因,本文不詳細介紹寫時復制。大概描述下就是:如果多個程序同時訪問同一塊數據,那么每個程序都擁有指向這塊數據的指針,在每個程序看來,自己都是獨立擁有這塊數據的。

只有當程序需要對數據內容進行修改時,才會把數據內容拷貝到程序自己的應用空間里去。

這時候,數據才成為該程序的私有數據。如果程序不需要對數據進行修改,那么永遠都不需要拷貝數據到自己的應用空間里,這樣就減少了數據的拷貝。

除此之外,還有一些零拷貝技術,比如傳統的 Linux I/O 中加上 O_DIRECT 標記可以直接 I/O,避免了自動緩存,還有尚未成熟的 fbufs 技術,本文尚未覆蓋所有零拷貝技術,只是介紹常見的一些,如有興趣,可以自行研究。

一般成熟的服務端項目也會自己改造內核中有關 I/O 的部分,提高自己的數據傳輸速率。

想知道更多?描下面的二維碼關注我

后臺回復”加群“獲取公眾號專屬群聊入口

【精彩推薦】

  • 超清晰的DNS入門指南

  • 深入理解Java Stream流水線

  • 干掉Swagger,試試這個

  • 干掉GuavaCache:Caffeine才是本地緩存的王

  • 如何用ELK搭建TB級的日志系統

  • 深度好文:Linux系統內存知識

  • 日志系統新貴Loki,確實比笨重的ELK輕

  • 日志采集系統都用到哪些技術?

  • 面試官:為什么HashMap的加載因子是0.75?

點個在看少個 bug?????

總結

以上是生活随笔為你收集整理的可算是有文章,把Linux零拷贝讲透彻了!的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 天天草天天射 | 美女自拍视频 | 免费看成人av | 黄色一级在线视频 | 久久极品视频 | 污污视频免费观看 | 狠狠久| 羞辱极度绿帽vk | 艳妇臀荡乳欲伦交换电影 | 国产精品视频一区在线观看 | 国内精品一区二区 | a级片一级片 | 玩弄人妻少妇500系列 | 国产成人久久 | 欧美 唯美 清纯 偷拍 | 色婷婷香蕉在线一区二区 | 日韩精品一区三区 | 黄色视屏在线 | 亚洲av成人无码久久精品老人 | 少妇又紧又色又爽又刺激 | 成人免费毛片男人用品 | 亚洲中文字幕无码专区 | 牛牛影视一区二区 | 欧美激情视频在线 | 亚洲精品高清视频在线观看 | 亚洲一区a | 亚洲久久在线 | 一区二区三区在线视频免费观看 | 五月综合久久 | 精品一二三区 | 一个色在线 | 欧美美女在线观看 | 老司机午夜性大片 | 美女131爽爽爽做爰视频 | 色屋永久 | 成人性视频在线 | 国产精品观看 | 奇米影视在线观看 | 少妇丰满尤物大尺度写真 | 黄色网入口| 黄页网站在线 | 日韩欧美亚洲一区二区三区 | 久久有精品 | 国产精品一区久久 | 欧美成人片在线观看 | 女同毛片一区二区三区 | 男女扒开双腿猛进入爽爽免费 | 在线观看中文字幕一区 | 中国极品少妇xxxx | 男操女免费网站 | 69热在线 | 老熟妇精品一区二区三区 | 日本在线中文字幕专区 | 一区二区日韩电影 | 天天干夜夜怕 | 啪啪网站视频 | 四虎成人精品永久免费av | 一二三av | 五月婷婷一区二区三区 | 97超碰人人模人人人爽人人爱 | 大肉大捧一进一出好爽 | 欧美日韩成人在线 | 国产在线一区二 | 色欲一区二区三区精品a片 在线观看黄网站 | 天堂网视频在线观看 | 黑森林av导航 | 91碰在线视频 | 思思精品视频 | 久久久蜜桃一区二区 | 女人张开双腿让男人捅 | 色妹av | 欧美变态口味重另类在线视频 | 一区免费观看 | 国产91沙发系列 | 在线免费观看成人 | 黄色尤物视频 | 亚洲av无码国产精品久久 | 午夜看片在线观看 | 丰满人妻综合一区二区三区 | 超碰公开免费 | 午夜久草 | 亚洲欧美精品一区二区 | 奇米第四色777 | 国产三级精品三级 | www.一区二区 | 国产九九热视频 | 男女视频网站 | 亚洲蜜桃精久久久久久久久久久久 | 中文在线最新版天堂8 | 亚洲精品国产91 | 久久一久久 | 日本三级欧美三级 | www.啪| 日本一区二区免费电影 | 午夜不卡福利 | 伊人婷婷色 | 大尺度做爰无遮挡露器官 | 一本大道久久 | 欧美日韩精品区别 |