聊聊消息隊列高性能的祕密——零拷貝技術

前言

RocketMQ爲什麼這麼快、Kafka爲什麼這麼快?用了零拷貝技術?什麼是零拷貝技術,它們二者的零拷貝技術有不同嗎?

爲什麼需要零拷貝

在計算機產業中,I/O的速度相較CPU,總是太慢的。SSD硬盤的IOPS可以達到2W、4W,但是我們CPU的主頻有2GHz以上,也就意味着每秒會有20億次的操作。如果對於I/O操作,都是由CPU發出對應的指令,然後等待I/O設備完成操作之後返回,那CPU有大量的時間其實都是在等待I/O設備完成操作。但是,這個 CPU 的等待,在很多時候,其實並沒有太多的實際意義。我們對於 I/O 設備的大量操作,其實都只是把內存裏面的數據,傳輸到 I/O 設備而已。在這種情況下,其實 CPU 只是在傻等而已。特別是當傳輸的數據量比較大的時候,比如進行大文件複製,如果所有數據都要經過 CPU,實在是有點兒太浪費時間了。因此計算機工程是們就發明了DMA技術,也就是直接內存訪問(Direct Memory Access)技術,來減少CPU等待的時間。

DMA技術

本文不做過多相關介紹,這裏我簡單總結下對它的理解。
如上所述,CPU資源很寶貴,如果用它來處理I/O那麼將是極大的損失,比如說我們用千兆網卡或者硬盤傳輸大量數據的時候,如果都用CPU來搬運的話,肯定是忙不過來,所以可以選擇DMAC(DMA控制器即DMA Controller,簡稱DMAC),CPU告訴DMAC它需要傳輸什麼數據,從哪裏傳輸,傳輸到哪裏去這些信息,然後交給DMAC去做,DMAC可以等到數據都到齊了,再發送信號,交給CPU去處理,而不是讓CPU在哪裏忙等待。(DMAC:我們不加工數據,只是數據的搬運工
具體傳輸過程(從磁盤傳輸到網絡)如圖:

零拷貝

如上我們發現,雖然通過DMA技術能夠使得CPU不用忙等待I/O操作,減輕了一些壓力,但是從圖中也能清晰地看出,兩次CPU的Copy完全是在搞笑的,能不能把這兩個步驟去掉呢?這就是零拷貝需要做的事情了,而我們熟知的RocketMQ、Kafka都是使用了零拷貝技術來優化I/O,而它們的零拷貝處理方式卻有些不同。

Kafka零拷貝——SendFile

Kafka的代碼調用了Java NIO庫,具體是FileChannel裏面的transferTo方法(底層是。我們的數據並沒有讀到中間的應用內存裏面,而是直接通過Channel,寫入到對應的網絡設備裏。並且對於Socket的操作,也不是寫入到Socket的Buffer裏面,而是直接根據描述符(Descriptor)寫入到網卡的緩衝區裏面。於是,在這個過程中,只進行了兩次數據傳輸。(由於沒有在用戶態內存層裏面去Copy數據,幹掉了兩次CPU的Copy,所以我們將之稱爲零拷貝(Zero-Copy)

SendFile的工作原理

系統調用sendfile()通過DMA把磁盤數據拷貝到kernel buffer(read buffer),然後數據被kernel直接拷貝到另外一個與socket相關的kernel buffer(socket buffer)。這樣就沒有用戶態和內核態之間的切換,從內核中直接完成了從一個buffer到另一個buffer的拷貝,因爲數據就在kernel裏。
如圖:
第一次,是通過 DMA,從硬盤直接讀到操作系統內核的讀緩衝區裏面。第二次,則是根據 Socket 的描述符信息,直接從讀緩衝區裏面,寫入到網卡的緩衝區裏面。

這是Kafka目前實時數據傳輸管道的標準解決方案,也是Kafka高吞吐的祕密之一,零拷貝。

RocketMQ零拷貝——Mmap

Mmap全稱Memory Mapped Files。簡單描述其作用就是:將磁盤文件映射到內存,用戶通過修改內存就能修改磁盤文件。
它的工作原理是直接利用操作系統的Page來實現文件到物理內存的直接映射,完成映射之後你對物理內存的操作會被同步到磁盤上(操作系統在適當的時候)。

通過mmap也有一個很明顯的缺陷——不可靠,寫到mmap中的數據並沒有被真正地寫到磁盤,操作系統會在程序主動調用flush的時候才把數據真正寫到磁盤。

RocketMQ主要通過MappedByteBuffer對文件進行讀寫操作。其中,利用了NIO中的FileChannel模型將磁盤上的物理文件直接映射到用戶態的內存地址中(這種Mmap的方式減少了傳統IO將磁盤文件數據在操作系統內核地址空間的緩衝區和用戶應用程序地址空間的緩衝區之間來回進行拷貝的性能開銷),將對文件的操作轉化爲直接對內存地址進行操作,從而極大地提高了文件的讀寫效率(正因爲需要使用內存映射機制,故RocketMQ的文件存儲都使用定長結構來存儲,方便一次將整個文件映射至內存)。
如圖:

總結

  • CPU比I/O性能好很多,應當盡力給CPU讓步,讓它去做更多的事情,於是就有了DMA。DMA對CPU說,"你告訴我搬什麼數據,搬到哪裏,搬好了我告訴你,你先去忙別的"
  • 我們發現,在數據傳輸過程中,有兩次CPU的Copy可以省去,於是就有了內存映射技術(Mmap)、SendFile技術(內核數據Copy),讓CPU不需要再白忙活了
  • 市面上熟知的優秀中間件如RocketMQ使用的零拷貝技術是Mmap、Kafka使用的則是SendFile

參考資料:
《極客時間——深入淺出計算機組成原理》
Kafka順序讀寫與零拷貝(kafka爲什麼這麼快)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章