最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

淺析MMAP零拷貝在RocketMQ中的運(yùn)用

 更新時(shí)間:2022年07月27日 14:55:23   作者:morris131  
零拷貝技術(shù)可以減少數(shù)據(jù)拷貝和共享總線操作的次數(shù),消除傳輸數(shù)據(jù)在存儲器之間不必要的中間拷貝次數(shù),從而有效地提高數(shù)據(jù)傳輸效率,這篇文章主要介紹了MMAP零拷貝在RocketMQ中的運(yùn)用,需要的朋友可以參考下

什么是零拷貝?

零拷貝(英語: Zero-copy)技術(shù)是指計(jì)算機(jī)執(zhí)行操作時(shí),CPU不需要先將數(shù)據(jù)從某處內(nèi)存復(fù)制到另一個(gè)特定區(qū)域。這種技術(shù)通常用于通過網(wǎng)絡(luò)傳輸文件時(shí)節(jié)省CPU周期和內(nèi)存帶寬。

零拷貝技術(shù)可以減少數(shù)據(jù)拷貝和共享總線操作的次數(shù),消除傳輸數(shù)據(jù)在存儲器之間不必要的中間拷貝次數(shù),從而有效地提高數(shù)據(jù)傳輸效率。

零拷貝技術(shù)減少了用戶進(jìn)程地址空間和內(nèi)核地址空間之間因?yàn)樯舷挛那袚Q而帶來的開銷。

可以看出沒有說不需要拷貝,只是說減少冗余不必要的拷貝。

下面這些組件、框架中均使用了零拷貝技術(shù):Kafka、Netty、Rocketmq、Nginx、Apache。

傳統(tǒng)數(shù)據(jù)傳送機(jī)制

比如:讀取文件,再用socket發(fā)送出去,實(shí)際經(jīng)過四次copy。

偽碼實(shí)現(xiàn)如下:

buffer = File.read() 
Socket.send(buffer)

四次拷貝的過程:

  • 第一次:將磁盤文件,讀取到操作系統(tǒng)內(nèi)核緩沖區(qū);
  • 第二次:將內(nèi)核緩沖區(qū)的數(shù)據(jù),copy到應(yīng)用程序的buffer;
  • 第三步:將application應(yīng)用程序buffer中的數(shù)據(jù),copy到socket網(wǎng)絡(luò)發(fā)送緩沖區(qū)(屬于操作系統(tǒng)內(nèi)核的緩沖區(qū));
  • 第四次:將socket buffer的數(shù)據(jù),copy到網(wǎng)卡,由網(wǎng)卡進(jìn)行網(wǎng)絡(luò)傳輸。

1657181537156.png

分析上述的過程,雖然引入DMA來接管CPU的中斷請求,但四次copy是存在“不必要的拷貝”的。實(shí)際上并不需要第二個(gè)和第三個(gè)數(shù)據(jù)副本。應(yīng)用程序除了緩存數(shù)據(jù)并將其傳輸回套接字緩沖區(qū)之外什么都不做。相反,數(shù)據(jù)可以直接從讀緩沖區(qū)傳輸?shù)教捉幼志彌_區(qū)。

顯然,第二次和第三次數(shù)據(jù)copy其實(shí)在這種場景下沒有什么幫助反而帶來開銷(DMA拷貝速度一般比CPU拷貝速度快一個(gè)數(shù)量級),這也正是零拷貝出現(xiàn)的背景和意義。

打個(gè)比喻:200M的數(shù)據(jù),讀取文件,再用socket發(fā)送出去,實(shí)際經(jīng)過四次copy(2次cpu拷貝每次100ms ,2次DMA拷貝每次10ms),傳統(tǒng)網(wǎng)絡(luò)傳輸?shù)脑挘汉嫌?jì)耗時(shí)將有220ms。

同時(shí),read和send都屬于系統(tǒng)調(diào)用,每次調(diào)用都牽涉到兩次上下文切換:

1657181556654.png

總結(jié)下,傳統(tǒng)的數(shù)據(jù)傳送所消耗的成本:4次拷貝,4次上下文切換。4次拷貝,其中兩次是DMA copy,兩次是CPU copy。

mmap內(nèi)存映射

mmap可以將硬盤上文件的位置和應(yīng)用程序緩沖區(qū)(application buffers)進(jìn)行映射(建立一種一一對應(yīng)關(guān)系),將文件直接映射到用戶空間,所以實(shí)際文件讀取時(shí)根據(jù)這個(gè)映射關(guān)系,直接將文件從硬盤拷貝到用戶空間,只進(jìn)行了一次數(shù)據(jù)拷貝,不再有文件內(nèi)容從硬盤拷貝到內(nèi)核空間的一個(gè)緩沖區(qū)。

mmap內(nèi)存映射將會經(jīng)歷:3次拷貝: 1次cpu copy,2次DMA copy;

1657181598680.png

打個(gè)比喻:200M的數(shù)據(jù),讀取文件,再用socket發(fā)送出去,如果是使用MMAP實(shí)際經(jīng)過三次copy(1次cpu拷貝每次100ms ,2次DMA拷貝每次10ms),合計(jì)只需要120ms。

從數(shù)據(jù)拷貝的角度上來看,就比傳統(tǒng)的網(wǎng)絡(luò)傳輸,性能提升了近一倍。

mmap()是在<sys/mman.h>中定義的一個(gè)函數(shù),此函數(shù)的作用是創(chuàng)建一個(gè)新的虛擬內(nèi)存區(qū)域,并將指定的對象映射到此區(qū)域。mmap其實(shí)就是通過內(nèi)存映射的機(jī)制來進(jìn)行文件操作。

mmap的使用:

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.StandardCharsets;

public class MmapDemo {
    public static void main(String[] args) throws IOException {

        File f = new File("/root/map.txt");
        RandomAccessFile randomAccessFile = new RandomAccessFile(f, "rw");
        FileChannel fileChannel = randomAccessFile.getChannel();
        MappedByteBuffer mappedByteBuffer = fileChannel.map(FileChannel.MapMode.READ_WRITE, 0, 4096);
        mappedByteBuffer.put("hello".getBytes(StandardCharsets.UTF_8));
        mappedByteBuffer.flip();
        byte[] bytes = new byte[5];
        mappedByteBuffer.get(bytes, 0, 5);
        System.out.println("content:" + new String(bytes, StandardCharsets.UTF_8));
    }
}

使用命令:

strace -ff -o out java MmapDemo

追蹤MmapDemo程序產(chǎn)生的系統(tǒng)調(diào)用:

openat(AT_FDCWD, "/root/map.txt", O_RDWR|O_CREAT, 0666) = 5
... ...
fstat(5, {st_mode=S_IFREG|0644, st_size=0, ...}) = 0
ftruncate(5, 4096)                      = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_SHARED, 5, 0) = 0x7f9e1c000000

發(fā)現(xiàn)底層調(diào)用了mmap系統(tǒng)調(diào)用,后續(xù)并沒有產(chǎn)生write等系統(tǒng)調(diào)用,說明數(shù)據(jù)的讀寫直接發(fā)生在了應(yīng)用態(tài)。

FileChannal的使用

另外RocketMQ在源碼中還使用了FileChannel來做文件的寫入。

package com.morris.rocketmq.mmap;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.StandardCharsets;

public class FileChannelDemo {
    public static void main(String[] args) throws IOException {
        File f = new File("d:\\map.txt");
        RandomAccessFile randomAccessFile = new RandomAccessFile(f, "rw");
        FileChannel fileChannel = randomAccessFile.getChannel();
        ByteBuffer byteBuffer = ByteBuffer.allocate(128);
        byteBuffer.put("hello rocketmq".getBytes(StandardCharsets.UTF_8));
        byteBuffer.flip();
        fileChannel.write(byteBuffer);
        fileChannel.close();
    }
}

為什么RocketMQ會同時(shí)使用FileChannel和MappedByteBuffer在做文件的寫入,讀取卻只用MappedByteBuffer?

RocketMQ中MMAP運(yùn)用

如果按照傳統(tǒng)的方式進(jìn)行數(shù)據(jù)傳送,那肯定性能上不去,作為MQ也是這樣,尤其是RocketMQ,要滿足一個(gè)高并發(fā)的消息中間件,一定要進(jìn)行優(yōu)化。所以RocketMQ使用的是MMAP。

RocketMQ源碼中,使用MappedFile這個(gè)類進(jìn)行MMAP的映射。

這里需要注意的是,采用MappedByteBuffer這種內(nèi)存映射的方式一次只能映射2G的文件至用戶態(tài)的虛擬內(nèi)存,這也是為何RocketMQ默認(rèn)設(shè)置單個(gè)CommitLog日志數(shù)據(jù)文件為1G的原因了。

為什么是2G?

sun.nio.ch.FileChannelImpl#map

public MappedByteBuffer map(MapMode mode, long position, long size) throws IOException {
    if (size > Integer.MAX_VALUE)
        throw new IllegalArgumentException("Size exceeds Integer.MAX_VALUE");

雖然size是long類型,但是限制了size只能是int的最大值,也就是2G。

mmap在源碼MappedFile中的使用:

public MappedFile(final String fileName, final int fileSize) throws IOException {
	init(fileName, fileSize);
}

private void init(final String fileName, final int fileSize) throws IOException {
	this.fileName = fileName;
	this.fileSize = fileSize;
	this.file = new File(fileName);
	this.fileFromOffset = Long.parseLong(this.file.getName());
	boolean ok = false;

	ensureDirOK(this.file.getParent());

	try {
		this.fileChannel = new RandomAccessFile(this.file, "rw").getChannel();
		this.mappedByteBuffer = this.fileChannel.map(MapMode.READ_WRITE, 0, fileSize);
		TOTAL_MAPPED_VIRTUAL_MEMORY.addAndGet(fileSize);
		TOTAL_MAPPED_FILES.incrementAndGet();
		ok = true;
	} catch (FileNotFoundException e) {
		log.error("Failed to create file " + this.fileName, e);
		throw e;
	} catch (IOException e) {
		log.error("Failed to map file " + this.fileName, e);
		throw e;
	} finally {
		if (!ok && this.fileChannel != null) {
			this.fileChannel.close();
		}
	}
}

到此這篇關(guān)于MMAP零拷貝在RocketMQ中的運(yùn)用的文章就介紹到這了,更多相關(guān)MMAP RocketMQ運(yùn)用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 解決idea無法導(dǎo)入識別本地類的問題

    解決idea無法導(dǎo)入識別本地類的問題

    今天做實(shí)驗(yàn)不知道按了哪里不能導(dǎo)入識別本地的類,只有jar包的類,百度搜索也沒有找到合理的解決方案,經(jīng)過朋友援助問題根源找到,下面小編把解決方法分享給大家,需要的朋友參考下吧
    2021-08-08
  • Spring事務(wù)管理原理及方法詳解

    Spring事務(wù)管理原理及方法詳解

    這篇文章主要介紹了Spring事務(wù)管理原理及方法詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-01-01
  • JAVA中JSONObject對象和Map對象之間的相互轉(zhuǎn)換

    JAVA中JSONObject對象和Map對象之間的相互轉(zhuǎn)換

    這篇文章主要介紹了JAVA中JSONObject對象和Map對象之間的相互轉(zhuǎn)換,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-01-01
  • Mybatis配置之<environments>配置元素詳解

    Mybatis配置之<environments>配置元素詳解

    這篇文章主要介紹了Mybatis配置之<environments>配置元素,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-01-01
  • Java實(shí)現(xiàn)時(shí)間片輪轉(zhuǎn)調(diào)度算法的示例代碼

    Java實(shí)現(xiàn)時(shí)間片輪轉(zhuǎn)調(diào)度算法的示例代碼

    時(shí)間片輪轉(zhuǎn)調(diào)度是一種最古老,最簡單,最公平且使用最廣的算法,這篇文章主要為大家介紹了如何利用Java實(shí)現(xiàn)這一算法,需要的可以參考一下
    2023-07-07
  • 在eclipse中中文漢字亂碼的解決方案

    在eclipse中中文漢字亂碼的解決方案

    在本篇文章里小編給大家分享的是關(guān)于在eclipse中中文漢字亂碼的解決方案,有需要的朋友們可以學(xué)習(xí)下。
    2019-12-12
  • MyBatis中使用foreach循環(huán)的坑及解決

    MyBatis中使用foreach循環(huán)的坑及解決

    這篇文章主要介紹了MyBatis中使用foreach循環(huán)的坑及解決方案,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-01-01
  • 一文帶你搞懂什么是BIO

    一文帶你搞懂什么是BIO

    BIO英文全名是 blocking IO,也叫做 阻塞IO,是最容易理解、最容易實(shí)現(xiàn)的IO工作方式,本文就來通過一些簡單的示例為大家講講什么是BIO吧
    2023-06-06
  • Java HttpURLConnection使用方法詳解

    Java HttpURLConnection使用方法詳解

    這篇文章主要為大家詳細(xì)介紹了Java HttpURLConnection使用方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-11-11
  • Java實(shí)現(xiàn)求小于n的質(zhì)數(shù)的3種方法

    Java實(shí)現(xiàn)求小于n的質(zhì)數(shù)的3種方法

    這篇文章主要介紹了Java實(shí)現(xiàn)求小于n的質(zhì)數(shù)的3種方法,本文給出了根據(jù)定義去求解、平方根、找規(guī)律三種解法,需要的朋友可以參考下
    2015-03-03

最新評論

屯昌县| 桂平市| 麻栗坡县| 嘉黎县| 满洲里市| 梁河县| 沐川县| 镇沅| 鸡西市| 连城县| 绩溪县| 西平县| 新蔡县| 平远县| 禹州市| 德州市| 金溪县| 凤庆县| 渭南市| 黄浦区| 长岛县| 开化县| 盖州市| 广灵县| 页游| 合作市| 论坛| 萨迦县| 石棉县| 乐陵市| 枣强县| 丰都县| 郑州市| 上高县| 油尖旺区| 镶黄旗| 伊宁县| 黑山县| 南川市| 九台市| 镇雄县|