深入淺出計算機組成原理學習筆記:第四十八講


一、引子

過去幾年里,整個計算機產業屆,都在嘗試不停地提升I/O設備的速度。把HDD硬盤換成SSD硬盤,我們仍然覺得不夠快;用PCI Express接口的SSD硬盤替代SATA接口的SSD硬盤,
我們還是覺得不夠快,所以,現在就有了傲騰(Optane)這樣的技術。

但是,無論I/O速度如何提升,比起CPU,總還是太慢。SSD硬盤的IOPS可以到2萬、4萬,但是我們CPU的主頻有2GHz以上,也就意味着每秒會有20億次的操作。

如果我們對於I/O的操作,都是由CPU發出對應的指令,然后等待I/O設備完成操作之后返回,那CPU有大量的時間其實都是在等待I/O設備完成操作。

但是,這個CPU的等待,在很多時候,其實並沒有太多的實際意義。我們對於I/O設備的⼤量操作,其實都只是把內存里面的數據,傳輸到I/O設備而已。
在這種情況下,其實CPU只是在傻等而已。特別是當傳輸的

因此,計算機工程師們,就發明了DMA技術,也就是 直接內存訪問(Direct Memory Access)技術,來減少CPU等待的時間。

二 、理解DMA,一個協處理器

1、什么是DMA?

其實DMA技術很容易理解,本質上,DMA技術就是我們在主板上放⼀塊獨立的芯片。在進行內存和I/O設備的數據傳輸的時候,我們不再通過CPU來控制數據傳輸,
而直接通過 DMA控制器(DMA?Controller,簡稱DMAC)。這塊芯片,我們可以認為它其實就是一個協處理器(Co-Processor)

2、DMAC最有價值的地方體現在那?

當我們要傳輸的數據特別大、速度特別快,或者傳輸的數據特別小、速度特別慢的時候

比如說,我們的千兆網卡或者硬盤傳輸大量數據的時候,如果都用CPU來搬運的話,肯定忙不過來,所以可以選擇DMAC。而當數據傳輸很慢的時候,
DMAC可以等數據到齊了,再發送信號,給到CPU去處理,而不是讓CPU在那里忙等待。

3、DMAC是一塊“協處理器芯片”,這是為什么呢?

注意,這里的“協”字。DMAC是在“協助”CPU,完成對應的數據傳輸⼯作。在DMAC控制數據傳輸的過程中,我們還是需要CPU的。

4、總線上的設備、分為那兩種類型?

除此之外,DMAC其實也是一個特殊的I/O設備,它和CPU以及其他I/O設備⼀樣,通過連接到總線來進行實際的數據傳輸。總線上的設備呢,
其實有兩種類型。一種我們稱之為 主設備(Master),另外一種,我們稱之為 從設備(Slave)。

5、想要主動發起數據傳輸,必須要是一個主設備才可以?

想要主動發起數據傳輸,必須要是一個主設備才可以,CPU就是主設備。而我們從設備(比如硬盤)只能接受數據傳輸。所以,如果通過CPU來傳輸數據,
要么是CPU從I/O設備讀數據,要么是CPU向I/O設備寫數據。

這個時候你可能要問了,那我們的I/O設備不能向主設備發起請求么?可以是可以,不過這個發送的不是數據內容,而是控制信號。
I/O設備可以告訴CPU,我這里有數據要傳輸給你,但是實際數據是CPU從拉取的,而不是I/O設備推給CPU的

6、DMAC既是一個主設備,又是一個從設備

不過,DMAC就很有意思了,它既是一個主設備,又是一個從設備。對於CPU來說,它是一個從設備;對於硬盤這樣的IO設備來說呢,它又變成了一個主設備。

7、使用DMAC進行數據傳輸的過程究竟是什么樣的呢?

1.首先,CPU還是作為一個主設備,向DMAC設備發起請求。這個請求,其實就是在DMAC里面修改配置寄存器。

2.CPU修改DMAC的配置的時候,會告訴DMAC這樣幾個信息:

3.設置完這些信息之后,DMAC就會變成一個空閑的狀態(Idle)。

4.如果我們要從硬盤上往內存里面加載數據,這個時候,硬盤就會向DMAC發起⼀個數據傳輸請求。這個請求並不是通過總線,而是通過一個額外的連線。

5.然后,我們的DMAC需要再通過一個額外的連線響應這個申請。

6.於是,DMAC這個芯片,就向硬盤的接口發起要總線讀的傳輸請求。數據就從硬盤里面,讀到了DMAC的控制器里面。

7.然后,DMAC再向我們的內存發起總線寫的數據傳輸請求,把數據寫⼊到內存⾥⾯。
8.DMAC會反復進行上面第6、7步的操作,直到DMAC的寄存器里面設置的數據長度傳輸完成。
9.數據傳輸完成之后,DMAC重新回到第3步的空閑狀態。

所以,整個數據傳輸的過程中,我們不是通過CPU來搬運數據,而是由DMAC這個芯⽚來搬運數據。但是CPU在這個過程中也是必不可少的。因為傳輸什么數據,
從哪里傳輸到哪里,其實還是由CPU來設置的。這也是為什么,DMAC被叫作“協處理器”。

最早,計算機里是沒有DMAC的,所有數據都是由CPU來搬運的。隨着對於數據傳輸的需求越來越多,先是出現了主板上獨立的DMAC控制器。到了今天,各種I/O設備越來越多,
數據傳輸的需求越來越復雜,使用的場景各不相同。加之顯示器、網卡、硬盤對於數據傳輸的需求都不一樣,所以各個設備里面都有自己的DMAC芯片了。

三、為什么那么快?一起來看Kafka的實現原理

1、它究竟是怎么利用DMA的?

Kafka是一個用來處理實時數據的管道,我們常常用它來做一個消息隊列,或者用來收集和落地海量的日志。作為一個處理實時數據和日志的管道,瓶頸自然也在I/O層面。

2、Kafka里面兩種常用的海量數據傳輸的情況是什么?

Kafka里面會有兩種常用的海量數據傳輸的情況。一種是從網絡絡中接收上游的數據,然后需要落地到本地的磁盤上,確保數據不丟失。
另一種情況呢,則是從本地磁盤上讀取出來,通過網絡發送出去。

我們來看一看后一種情況,從磁盤讀數據發送到網絡上去。如果我們自己寫一個簡單的程序,最直觀的辦法,自然是用個一件讀操作,從磁盤上把數據讀到內存里面來,
然后再用個Socket,把這些數據發送到網絡上去。

File.read(fileDesc, buf, len);
Socket.send(socket, buf, len);

3、我們只是要“搬運”一份數據,結果卻整整搬運了四次

在這個過程中,數據一共發生了四次傳輸的過程。其中兩次是DMA的傳輸,另外兩次,則是通過CPU控制的傳輸。下面我們來具體看看這個過程。

第一次傳輸,是從硬盤上,讀到操作系統內核的緩沖區里。這個傳輸是通過DMA搬運的。

第二次傳輸,需要從內核緩沖區里面的數據,復制到我們應用分配的內存里面。這個傳輸是通過CPU搬運的。

第三次傳輸,要從我們應用的內存里面,再寫到操作系統的Socket的緩沖區里面去。這個傳輸,還是由CPU搬運的。

最后一次傳輸,需要再從Socket的緩沖區里面,寫到網卡的緩沖區里面去。這個傳輸又是通過DMA搬運的。

 


這個時候,你可以回過頭看看這個過程。我們只是要“搬運”⼀份數據,結果卻整整搬運了四次。而且這里面,從內核的讀緩沖區傳輸到應用的內存里,
再從應用的內存里傳輸到Socket的緩沖區里,其實都是把同一份數據在內存里面搬運來搬運去,特別沒有效率。

4、我們就需要盡可能地減少數據搬運的需求

像Kafka這樣的應用場景,其實一部分最終利用到的硬件資源,其實又都是在干這個搬運數據的事兒。所以,我們就需要盡可能地減少數據搬運的需求。

事實上,Kafka做的事情就是,把這個數據搬運的次數,從上面的四次,變成了兩次,並且只有DMA來進行數據搬運,而不需要CPU。

@Override
public long transferFrom(FileChannel fileChannel, long position, long count) throws IOException {
    return fileChannel.transferTo(position, count, socketChannel);
}

Kafka的代碼調用了Java NIO庫,具體是FileChannel里面的transferTo方法。我們的數據並沒有讀到中間的應用內存里面,而是直接通過Channel,寫入到對應的網絡設備里。
並且,對於Socket的操作,也不是寫入到Socket的Buffer里面,而是直接根據描述符(Descriptor)寫到到網卡的緩沖區里面。於是,在這個過程之中,我們只進行了兩次數據傳輸。

5、同一份數據傳輸的次數從四次變成了兩次

 

第一次,是通過DMA,從硬盤直接讀到操作系統內核的讀緩沖區里面。第二次,則是根據Socket的描述符信息,直接從讀緩沖區里面,寫入到網卡的緩沖區里面。

這樣,我們同一份數據傳輸的次數從四次變成了兩次,並且沒有通過CPU來進行數據搬運,所有的數據都是通過DMA來進行傳輸的。

6、什么是零拷貝?

在這個方法里面,我們沒有在內存層面去“復制(Copy)”數據,所以這個方法,也被稱之為零拷貝(Zero-Copy)。IBM Developer Works里面有一篇文章,專們寫過程序來測試過在同樣的硬件下,使用零拷貝能夠帶來的性能提升。我在這里放上這篇文章鏈接。在這篇文章最后,你可以看到,無論傳輸數據量的大小,傳輸同樣的數據,使用了零拷貝能夠縮短65%的時間,大幅度提升了機器傳輸數據的吞吐量。想要深入了解零拷貝,建議你可以仔細讀讀讀這篇文章。

 四、總結延伸

講到這里,相信你對DMA的原理、作用和效果都有所理解了。那么,我們⼀起來回顧總結一下。、

如果我們始終讓CPU來進行各種數據傳輸工作,會特別浪費。一方面,我們的數據傳輸工作用不到多少CPU核新的“計算”功能。另一方面,CPU的運轉速度也比I/O操作要快很多。
所以,我們希望能夠給CPU“減負”。

於是,工程師們就在主板上放上了DMAC這樣一個協處理器芯片。通過這個芯片,CPU只需要告訴DMAC,我們要傳輸什么數據,從哪里來,到哪里去,就可以放心離開了。

后續的實際數據傳輸工作,都會有DMAC來完成。隨着現代計算機各種外設硬件越來越多,光一個通用的DMAC芯片不夠了,我們在各個外設上都加上了DMAC芯片,

使得CPU很少再需要關注數據傳輸的工作了。

在我們實際的系統開發過程中,利用好DMA的數據傳輸機制,也可以大幅提升I/O的吞吐率。最典型的例子就是Kafka。

傳統地從硬盤讀取數據,然后再通過網卡上向外發送,我們需要進行四次數據傳輸,其中有兩次是發生在內存里的緩沖區和對應的硬件設備之間,我們沒法節省掉。
但是還有兩次,完全是通過CPU在內存里面進行數據復制。

在Kafka里,通過Java的NIO里面FileChannel的transferTo方法調用,我們可以不用把數據復制到我們應用程序的內存里面。通過DMA的方式,
我們可以把數據從內存緩沖區直接寫到網卡的緩沖區里面。在使用了這樣的零拷貝的方法之后呢,我們傳輸同樣數據的時間,可以縮減為原來的1/3,相當於提升了3倍的吞吐率。

這也是為什么,Kafka是目前實時數據傳輸管道的標准解決方案


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM