各个查询引擎是如何提高写入效率,查询效率

RocketMq

1. 顺序IO

如果消息生产者生产了消息,发送到broker之后,需要存储在磁盘中,如果直接存储到话,并发度会很小,因为操作磁盘会很慢,尤其是操作随机IO,因此看看能不能在写入磁盘的时候,使用顺序IO,这样在接收数据的时候就能大大提高并发量。

在RocketMq则是使用了顺序IO的写入方法,使用了CommitLog文件,该文件是在顺序写入消息,每一个消息都是具有对应的物理偏移量。

当然commitLog的消息还无法进行快速消费,因此会有一个异步IO会将commitLog的消息进行取出来然后放在对应的consumerQueue中。

2. mmap内存映射

即使存在顺序IO,还是会很慢,因此为了提高并发度,采用了mmap内存映射,mmap内存映射是操作系统直接携带过来的功能。也就是虚拟内存,在内存中开辟一块空间和物理空间进行绑定,写入到commitLog文件可以直接写入到虚拟内存中,操作系统会异步将虚拟内存空间的数据写到磁盘文件中,当然这个时机我们也能控制,这个就被称为刷盘。

  1. 同步刷盘 sync_flush
  2. 异步刷盘 async_flush
  3. 异步+缓冲区 ASYNC_FLUSH && transientStorePoolEnable=trye

这里的mmap开辟的内存空间被称为pagecache ,只有当机器断电才会消息丢失。

3. 使用java编写一个mmap内存映射

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

/**
 * @author : x
 * @date : 2023/5/26 10:28
 * @description : java使用虚拟内存操作文件
 *
 * 1. 映射文件
 * 2. 进行写入数据
 * 3. 进行读取数据
 * 4. 对比方案
 **/
public class MmapTest {

    private final String FILE_PATH = "/Users/edy/log/c.txt";
    private MappedByteBuffer buffer = null;
    private  FileChannel channel = null;
    private  RandomAccessFile randomAccessFile = null;
    public void init() throws IOException {
        File file = new File(FILE_PATH);
        randomAccessFile = new RandomAccessFile(file, "rw");
        // 获得文件通道
        channel = randomAccessFile.getChannel();
        // 映射文件到内存中
        buffer = channel.map(FileChannel.MapMode.READ_WRITE, 0, 1024 * 10);
    }

    public void read() throws IOException {
        init();
        Long start = System.currentTimeMillis();
        byte[] data = new byte[1024 * 1];
        buffer.get(data);
        System.out.println(new String(data,StandardCharsets.UTF_8));
        Long end = System.currentTimeMillis();
        System.out.println("耗时(s):"+ (end - start)  );
        channel.close();
        randomAccessFile.close();
    }

    public void mmap() throws IOException {
        try {
            init();
            Long start = System.currentTimeMillis();
            for (int i = 0; i < 100; i++) {
                buffer.put(("你好啊,我是第" + i + "\r\n").getBytes(StandardCharsets.UTF_8));
            }
            Long end = System.currentTimeMillis();
            System.out.println("耗时(s):"+ (end - start)  );
        } finally {
            buffer.force();
            channel.close();
            randomAccessFile.close();
        }

    }

    public static void main(String[] args) throws IOException {
        MmapTest mmapTest = new MmapTest();
        mmapTest.mmap();
        mmapTest.read();
    }
}

在查看源码注解时有如下说明

For most operating systems, mapping a file into memory is more expensive than reading or writing a few tens of kilobytes of data via the usual read and write methods. From the standpoint of performance it is generally only worth mapping relatively large files into memory.
也就是说应该是大文件进行内存映射,小文件开辟的性能更不适用

Mysql

1. 顺序IO

同理,mysql也存在顺序io的文件读写,如果直接将数据写入到对应磁盘空间,那么必然是随机IO,随机IO的吞吐量大大降低。

其中Redo log就是作为顺序IO进
行写入数据,然后通过异步IO同步到对应的磁盘文件中。

2. 内存映射

同样在查询数据的时候,也存在pageCache,将磁盘的文件映射到pagecache中,通过pagecache提供文件读取效率,写入效率。

那么mysql到innodb有一个buffer pool这个和pagecache的区别是什么呢?

我们知道InnoDB数据库的数据是持久化在磁盘上的,而磁盘的IO速度很慢,如果每次数据库访问都直接访问磁盘,显然严重影响数据库的性能。为了提升数据库的访问性能,InnoDB为数据库的数据增加了内存缓存区(BufferPool),避免每次访问数据库都进行磁盘IO。
也就是innoDB还在存储引擎中又新增一层缓冲区。

Kafka

1. 顺序写

在这里插入图片描述

在kafka和rocektmq的也是类似的,只不过这里叫segment文件,但是这里的segment是一个topic一个queue多个segment,同时也包括对应的索引文件。

2. 页缓存PageCache

虽然消息写入是磁盘顺序写入,没有磁盘寻道的开销,但是如果针对每条消息都执行一次磁盘写入,则也会造成大量的磁盘IO,影响性能。
由于是先将消息写入到操作系统的页缓存,而页缓存数据刷新同步sync到磁盘文件是由操作系统来控制的,即操作系统通过一个内核后台线程,每5秒检查一次是否需要将页缓存数据同步到磁盘文件,如果超过指定时间或者超过指定大小则将页缓存数据同步到磁盘。所以如果在刷新到磁盘文件之前broker机器宕机了,则会导致页缓存的数据丢失。
使用页缓存的另外一个好处是,如果重启了kafka服务端(这个服务重启,而不是机器突然宕机),页缓存中的数据还是可以继续使用的。

稀疏索引

在计算机科学中,稀疏索引(Sparse Index)是一种优化的数据结构,用于提高查找和检索大型数据集的效率。

相比于传统的密集索引(Dense Index),稀疏索引在索引记录的数量上具有很大的优势。密集索引通常需要维护所有的索引值和对应的记录位置信息,因此对于数据量较大的情况下会占用大量的内存空间和处理时间。而稀疏索引则只维护部分索引值和对应的记录位置信息,可以有效减少索引的大小和查询时需要遍历的索引条目数目。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值