原文:https://learn.lianglianglee.com/專欄/Netty 核心原理剖析與 RPC 實踐-完/16 IO 加速:與衆不同的 Netty 零拷貝技術.md
此地址下的 【專欄】-> 【netty】https://learn.lianglianglee.com
參考:
- https://www.jianshu.com/p/a199ca28e80d
- https://zhuanlan.zhihu.com/p/76059333
- https://segmentfault.com/a/1190000022790435
- https://zhuanlan.zhihu.com/p/78335525
- https://blog.csdn.net/weixin_48726650/article/details/107664915
- http://dockone.io/article/10019
如果要把磁盤上一個文件發送給網絡上某臺主機,那麼:
Linux:disk -> kernel(dma) -> user context(cpu) -> socket buffer(cpu) -> nic(dma) 一共4次
Linux 2.4之前:sendfile()系統調用直接將kernel buffer 複製給socket buffer,一共3次
Linux 2.4之後:sendfile()系統調用直接將kernel buffer複製給nic buffer,一共2次,並且,cpu參與複製的兩次都被幹掉了
所謂零拷貝,並不是無拷貝,而是不需要cpu參與的拷貝,其中的兩次是必須要做的(dma在做),好像不能直接從disk拷貝到nic(比如網卡緩存),從廣義上說零拷貝是說,只要減少拷貝次數就是零拷貝,比如這裏只要少於4次就是
上面sendfile是2次拷貝,而mmap是3次拷貝,mmap和sendfile都是零拷貝的實現方式,Java對二者均有實現,分別是transferTo/transferFrom實現sendfile和channel.map()實現mmap,
上述方式對於固定文件的發送沒問題,但是如果希望在發送文件的時候能夠修改文件,那麼就不好使,此時就需要使用mmap,將文件映射到內核地址空間,並且用戶空間也共享這一段內存,
那麼就需要3次拷貝(2次dma,分別是disk->kernel buffer,socket buffer -> nic buffer,一次cpu從內核空間拷貝到socket buffer)以及4次上下文切換,此時的內核空間其實就是page cache,
修改pagecache如果不發生缺頁中斷那麼性能是相當高的,rocketmq就是這樣來實現comsulequeue和commitlog的
netty零拷貝,有5方面
- 全部使用直接內存,這樣一來就可以避免jvm堆內存copy數據到kernel內存
- CompositeBuf,可以拼接多個ByteBuf,並且底層並附copy,而是引用拼接
- wrap操作合併多個ByteBuf,也無需copy
- slice分割ByteBuf,也無需copy,底層共用一個buf
- 使用Java transferTo/transferFrom(底層調用sendfile())來實現無需cpu拷貝
RocketMQ零拷貝:mmap + write
kafka零拷貝:mmap + sendfile
1、partition順序讀寫,充分利用磁盤特性,這是基礎;
2、Producer生產的數據持久化到broker,採用mmap文件映射,實現順序的快速寫入;
3、Customer從broker讀取數據,採用sendfile,將磁盤文件讀到OS內核緩衝區後,直接轉到socket buffer進行網絡發送。
RocketMQ和kafka零拷貝區別:https://blog.csdn.net/weixin_48726650/article/details/107664915