欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

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

什么是零拷貝?

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

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

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

可以看出沒(méi)有說(shuō)不需要拷貝,只是說(shuō)減少冗余不必要的拷貝。

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

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

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

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

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

四次拷貝的過(guò)程:

  • 第一次:將磁盤(pán)文件,讀取到操作系統(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

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

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

打個(gè)比喻:200M的數(shù)據(jù),讀取文件,再用socket發(fā)送出去,實(shí)際經(jīng)過(guò)四次copy(2次cpu拷貝每次100ms ,2次DMA拷貝每次10ms),傳統(tǒng)網(wǎng)絡(luò)傳輸?shù)脑?huà):合計(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可以將硬盤(pán)上文件的位置和應(yīng)用程序緩沖區(qū)(application buffers)進(jìn)行映射(建立一種一一對(duì)應(yīng)關(guān)系),將文件直接映射到用戶(hù)空間,所以實(shí)際文件讀取時(shí)根據(jù)這個(gè)映射關(guān)系,直接將文件從硬盤(pán)拷貝到用戶(hù)空間,只進(jìn)行了一次數(shù)據(jù)拷貝,不再有文件內(nèi)容從硬盤(pán)拷貝到內(nèi)核空間的一個(gè)緩沖區(qū)。

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

1657181598680.png

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

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

mmap()是在<sys/mman.h>中定義的一個(gè)函數(shù),此函數(shù)的作用是創(chuàng)建一個(gè)新的虛擬內(nèi)存區(qū)域,并將指定的對(duì)象映射到此區(qū)域。mmap其實(shí)就是通過(guò)內(nèi)存映射的機(jī)制來(lái)進(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ù)并沒(méi)有產(chǎn)生write等系統(tǒng)調(diào)用,說(shuō)明數(shù)據(jù)的讀寫(xiě)直接發(fā)生在了應(yīng)用態(tài)。

FileChannal的使用

另外RocketMQ在源碼中還使用了FileChannel來(lái)做文件的寫(xiě)入。

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會(huì)同時(shí)使用FileChannel和MappedByteBuffer在做文件的寫(xiě)入,讀取卻只用MappedByteBuffer?

RocketMQ中MMAP運(yùn)用

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

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

這里需要注意的是,采用MappedByteBuffer這種內(nèi)存映射的方式一次只能映射2G的文件至用戶(hù)態(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類(lèi)型,但是限制了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)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • SpringBoot日志注解與緩存優(yōu)化詳解

    SpringBoot日志注解與緩存優(yōu)化詳解

    這篇文章主要給大家介紹了關(guān)于SpringBoot日志注解與緩存優(yōu)化的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2021-10-10
  • springcloud-gateway整合jwt+jcasbin實(shí)現(xiàn)權(quán)限控制的詳細(xì)過(guò)程

    springcloud-gateway整合jwt+jcasbin實(shí)現(xiàn)權(quán)限控制的詳細(xì)過(guò)程

    這篇文章主要介紹了springcloud-gateway整合jwt+jcasbin實(shí)現(xiàn)權(quán)限控制,基于springboot+springcloud+nacos的簡(jiǎn)單分布式項(xiàng)目,項(xiàng)目交互采用openFeign框架,單獨(dú)提取出來(lái)成為一個(gè)獨(dú)立的model,需要的朋友可以參考下
    2023-02-02
  • spring boot讀取Excel操作示例

    spring boot讀取Excel操作示例

    這篇文章主要介紹了spring boot讀取Excel操作,結(jié)合實(shí)例形式詳細(xì)分析了spring boot解析、讀取Excel相關(guān)操作技巧,需要的朋友可以參考下
    2019-11-11
  • Java實(shí)現(xiàn)每日給女友微信發(fā)送早安信息

    Java實(shí)現(xiàn)每日給女友微信發(fā)送早安信息

    這篇文章主要為大家詳細(xì)介紹了Java如何實(shí)現(xiàn)每日給女友微信發(fā)送早安等微信信息,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,需要的可以了解一下
    2022-12-12
  • spring boot tomcat jdbc pool的屬性綁定

    spring boot tomcat jdbc pool的屬性綁定

    這篇文章主要介紹了spring boot tomcat jdbc pool的屬性綁定的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友參考下
    2018-01-01
  • Java 8 Stream Api 中的 map和 flatMap 操作方法

    Java 8 Stream Api 中的 map和 flatMap 操作方法

    Java 8提供了非常好用的 Stream API ,可以很方便的操作集合。今天通過(guò)這篇文章給大家分享Java 8 Stream Api 中的 map和 flatMap 操作方法,需要的朋友可以參考下
    2019-11-11
  • Java 8 新特性終極版指南詳解

    Java 8 新特性終極版指南詳解

    Java 8已經(jīng)公布有一段時(shí)間了,種種跡象表明Java 8是一個(gè)有重大改變的發(fā)行版。本文給大家介紹Java 8 新特性終極版指南詳解,需要的朋友參考下
    2016-03-03
  • java的nio的使用示例分享

    java的nio的使用示例分享

    這篇教程展示了5個(gè)在Java編程的一些常見(jiàn)場(chǎng)景里使用NIO和NIO.2包的簡(jiǎn)單示例,需要的朋友可以參考下
    2014-03-03
  • 解決Maven項(xiàng)目中 Invalid bound statement 無(wú)效的綁定問(wèn)題

    解決Maven項(xiàng)目中 Invalid bound statement 無(wú)效的綁定問(wèn)題

    這篇文章主要介紹了解決Maven項(xiàng)目中 Invalid bound statement 無(wú)效的綁定問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-06-06
  • 淺談Java編程中string的理解與運(yùn)用

    淺談Java編程中string的理解與運(yùn)用

    這篇文章主要介紹了淺談Java編程中string的理解與運(yùn)用,還是比較不錯(cuò)的,這里分享給大家,供需要的朋友參考。
    2017-11-11

最新評(píng)論