傳統(tǒng)讀操作JAVA用傳統(tǒng)方式進行讀操作時,整體流程如上圖,,具體如下:
我們看一下一個讀操作,發(fā)了2次上下文切換,,和2次數據copy,,一次是DMA Copy,一次是CPU Copy,。
傳統(tǒng)寫操作上圖是JAVA傳統(tǒng)的寫操作,,具體流程:
傳統(tǒng)IO我們可以看出傳統(tǒng)的IO讀寫操作,總共進行了4次上下文切換,,4次Copy動作,。我們可以看到數據在內核空間和應用空間之間來回復制,其實他們什么都沒有做,就是復制而已,,這個機制太浪費時間了,,而且是浪費的CPU的時間。 那我們能不能讓數據不要來回復制呢,?零拷貝這個技術就是來解決這個問題,。關于零拷貝提供了兩種解決方式:mmap+write方式、sendfile方式 虛擬內存所有現(xiàn)代操作系統(tǒng)都使用虛擬內存,,使用虛擬地址取代物理地址,,這樣做的好處就是:
我們利用第一條特性可以優(yōu)化一下上面的設計思路,,就是把內核空間和用戶空間的虛擬地址映射到同一個物理地址,這樣就不需要來回復制了,,看圖: mmap+write方式使用mmap+write方式替換原來的傳統(tǒng)IO方式,,就是利用了虛擬內存的特性,看圖 整體流程的核心區(qū)別就是,,把數據讀取到內核緩沖區(qū)后,,應用程序進行寫入操作時,直接是把內核的Read Buffer的數據 復制到 Socket Buffer 以便進行寫入,,這次內核之間的復制也是需要CPU參與的,。
這個流程就少了一個CPU Copy,,提升了IO的速度,。不過發(fā)現(xiàn)上下文的切換還是4次,沒有減少,,因為還是要應用程序發(fā)起write操作,。那能不能減少上下文切換呢? sendfile方式這種方式可以替換上面的mmap+write方式,,如: mmap();write(); 替換為 sendfile(); 這樣就減少了一次上下文切換,,因為少了一個應用程序發(fā)起write操作,直接發(fā)起sendfile操作,。 到這里就只有3次Copy,,其中只有1次CPU Copy;3次上下文切換,。那能不能把CPU Copy減少到沒有呢,? gatherLinux2.4內核進行了優(yōu)化,提供了gather操作,,這個操作可以把最后一次CPU Copy去除,,什么原理呢,?就是在內核空間Read Buffer和Socket Buffer不做數據復制,而是將Read Buffer的內存地址,、偏移量記錄到相應的Socket Buffer中,,這樣就不需要復制(其實本質就是和虛擬內存的解決方法思路一樣,就是內存地址的記錄),,如圖: JAVA零拷貝java nio實現(xiàn)零拷貝,,JAVA提供了一下方法類: 1、MappedByteBuffer2,、DirectByteBuffer3、FileChannel.transferTo 具體如何使用,,小伙伴們上網自行查閱,。 總結零拷貝技術在很多中間件中,都有利用,;如:Kafka,,Spark、RocketMQ等,,這個在網絡傳輸數據時,,能夠提升速度,提升系統(tǒng)性能,、吞吐量,。小伙伴們不一定會編寫,可以先了解基本原理就行,。很多好的中間件產品都需要了解一些計算機原理方面的知識,,才會更深入的理解。 |
|