MyRocks之memtable切换与刷盘



title: MySQL · myrocks · MyRocks之memtable切换与刷盘

author: 张远

概述

MyRocks的memtable默认是skiplist,其大小和个数分别由参数write_buffer_size和max_write_buffer_number控制。数据写入时先写入active memtable, 当active memtable写满时,active memtable会转化为immutable memtable. immutable memtable数据是不会变化的,最终会刷入level0的sst文件中。

memtable 内存分配

RocksDB有自己的内存分配机制,称为Arena. Arena由固定的inline_block_和动态的blocks_组成。
inline_block_固定为2048bytes, blocks_由一系列的block组成,这些block大小一般为KBlockSize, 但从arena申请较大内存时(> KBlockSize/4)单独分配一个所申请大小的block. KBlockSize由参数arena_block_size指定,arena_block_size 不指定时默认为write_buffer_size的1/8.

这里有两个重要的概念

  • blocks_memory_
    Arena当前已分配的内存
  • alloc_bytes_remaining_
    Arena当前block已分配但未使用的内存,注意不是整个Arena已分配而未使用的内存

RocksDB在实际使用内存中用的是ConcurrentArena, 它是在Arena的基础上封装,是线程安全的。
同时ConcurrentArena为了提高并发对内存进行了分片,分片数由cpu个数决定,例如cpu核数为24, 则分片数为32,以下是分片的算法

// find a power of two >= num_cpus and >= 8
  auto num_cpus = std::thread::hardware_concurrency();
  index_mask_ = 7;
  while (index_mask_ + 1 < num_cpus) {
    index_mask_ = index_mask_ * 2 + 1;
  }

  shards_.reset(new Shard[index_mask_ + 1]);

每个分片都有已分配但未使用的内存, 分片越多浪费的内存越多。

一个有趣的例子

测试环境:CPU核数64,write_buffer_size=1G, arena_block_size=0
根据前面的算法,CPU核数64, 内存分片数为64, arena_block_size 默认为write_buffer_size的1/8,对齐后是131072000

我们用1200个连接进行并发插入,这样能够充分使用内存分片数
这是测试某个瞬间取得的内存数据

allocated_memory:1179650048
AllocatedAndUnused:1172297392
write_buffer_size:1048576000
BlockSize:131072000

注意AllocatedAndUnused和allocated_memory是如此的接近,也就是说存在巨大的内存浪费。然而这不是最严重的,更严重的是这种情况导致memtable的切换,后面会进行分析。

memtable 切换

memtable 发生切换的条件有
1) memtable内存超过write_buffer_size会切换
2) WAL日志满,WAL日志超过rocksdb_max_total_wal_size,会从所有的colomn family中找出含有最老日志(the earliest log containing a prepared section)的memtable进行切换,详见HandleWALFull
3) Buffer满,全局的write buffer超过rocksdb_db_write_buffer_size时,会从所有的colomn family中找出最先创建的memtable进行切换,详见HandleWriteBufferFull
4) flush memtable前会切换memtable, 下节会介绍

下面详细介绍memtable满切换

  • memtable 满切换

memtable内存超过write_buffer_size会切换,由于arena的内存使用,memtable控制内存使用的算法更加精细,切换条件从源码中很容易理解

bool MemTable::ShouldFlushNow() const {
  // This constant variable can be interpreted as: if we still have more than
  // "kAllowOverAllocationRatio * kArenaBlockSize" space left, we'd try to over
  // allocate one more block.
  const double kAllowOverAllocationRatio = 0.6;

  // If arena still have room for new block allocation, we can safely say it
  // shouldn't flush.
  auto allocated_memory = table_->ApproximateMemoryUsage() +
                          range_del_table_->ApproximateMemoryUsage() +
                          arena_.MemoryAllocatedBytes();

  // if we can still allocate one more block without exceeding the
  // over-allocation ratio, then we should not flush.
  if (allocated_memory + kArenaBlockSize <
      moptions_.write_buffer_size +
      kArenaBlockSize * kAllowOverAllocationRatio) {
    return false;
  }

  // if user keeps adding entries that exceeds moptions.write_buffer_size,
  // we need to flush earlier even though we still have much available
  // memory left.
  if (allocated_memory > moptions_.write_buffer_size +
      kArenaBlockSize * kAllowOverAllocationRatio) {
    return true;
  }

 return arena_.AllocatedAndUnused() < kArenaBlockSize / 4;
}

而上一节举出的例子正好符合切换的条件,正如前面所说的,内存都分配好了,还没来得及使用就发生切换了,白忙活了一场。

这里的现象是虽然write_buffer_size是1G,但最后刷到level0的sst都远远小于1G。

那么如何避免这种情况呢

  • 减少内存分片数,不建议
  • 调小arena_block_size, 亲测可用

这里有一个原则是arena_block_size*内存分片数应该小于write_buffer_size

  • memtable 切换实现

    NewWritableFile //创建日志文件
    ConstructNewMemtable //创建memtable
    cfd->imm()->Add(cfd->mem(), &context->memtables_to_free_); //设置immutable
    cfd->SetMemtable(new_mem); //设置新的memtable

flush memtable

immutable memtable会不断flush到level0的SST文件中

触发flush的条件有

  • WAL日志满,WAL日志超过rocksdb_max_total_wal_size,会从所有的colomn family中找出含有最老日志(the earliest log containing a prepared section)的column family进行flush,详见HandleWALFull
  • Buffer满,全局的write buffer超过rocksdb_db_write_buffer_size时,会从所有的colomn family中找出最先创建的memtable的column family进行flush,详见HandleWriteBufferFull
  • 手动设置参数force_flush_memtable_now/rocksdb_force_flush_memtable_and_lzero_now时
  • CompactRange时
  • 创建checkpoint时
  • shutdown时avoid_flush_during_shutdown=0会flush所有memtable

other

rocksdb中设置max_background_flushes=-1可以禁止flush,而MyRocks中rocksdb_max_background_flushes最小值限制为0. 因此,MyRocks若要禁止flush需放开此限制。

时间: 2024-10-31 11:53:29

MyRocks之memtable切换与刷盘的相关文章

MySQL · myrocks · MyRocks之memtable切换与刷盘

概述 MyRocks的memtable默认是skiplist,其大小和个数分别由参数write_buffer_size和max_write_buffer_number控制.数据写入时先写入active memtable, 当active memtable写满时,active memtable会转化为immutable memtable. immutable memtable数据是不会变化的,最终会刷入level0的sst文件中. memtable 内存分配 RocksDB有自己的内存分配机制,称

阿里数据库内核月报:2017年06月

#01 MySQL · 源码分析 · Tokudb序列化和反序列化过程 #02 PgSQL · 应用案例 · HTAP视角,数据与计算的生态融合 #03 MySQL · 引擎特性 · 从节点可更新机制 #04 PgSQL · 特性分析 · 数据库崩溃恢复(下) #05 MySQL · 捉虫动态 · InnoDB crash #06 MSSQL · 实现分析 · SQL Server实现审计日志的方案探索 #07 MySQL · 源码分析 · InnoDB Repeatable Read隔离级别之

360安全卫士c盘搬家功能在哪里?

  360c盘搬家是一款功能非常实用的C盘文件转移功能,该功能主要为用户将C盘中的文件资源资料转移到其它盘符,从而减少C盘容量或避免重装系统造成文件丢失的问题,从轻情况下如果C盘文件过多会对系统的运行造成一定的影响,那么为了避免给C盘造成负担,除了传统的优化软件以外,适当的减少C盘容量也能够为您提升系统速度!   操作方法 1.打开"360安全卫士"程序界面,在右边窗口中找到"更多",点击"更多功能"选项 2.点击后会跳转到另一个页面,在页面中找

win7系统下怎么使用dos命令清除u盘病毒

win7系统下怎么使用dos命令清除u盘病毒 1.使用"win+r"快捷键打开运行窗口,输入cmd命令回车; 2.打开命令提示符窗口后,切换到u盘所在的盘符,依次执行以下两条命令,如下图所示:attrib -S -H -R autorun.inf del autorun.inf;

360安全卫士清理c盘的方法

  大家有没有发现电脑中的C盘如果装的东西很多的话,就会使电脑变得很卡,而且C盘中全是英文,看不懂的朋友们根本不知道从何开始清理,小编推荐大家使用360安全卫士清理c盘,下面小编就给大家详细的讲解一下360安全卫士清理c盘的方法,希望对大家有所帮助. 1.打开"360安全卫士"程序,在右边的框框里,找到"更多",点击"更多功能"项. 2.点击以后会跳转到另一个页面内,在这个页面找到"C盘搬家" 3.接着程序会对整个磁盘进行扫描

360安全卫士怎么清理c盘

  第一步:打开"360安全卫士"程序,在右边的框框里,找到"更多",点击"更多功能"项. 第二步:点击以后会跳转到另一个页面内,在这个页面找到"C盘搬家" 第三步:接着程序会对整个磁盘进行扫描,以确定可以进行搬家的内容.在"重要资料"项中,勾选"我的文档". 第四步:接着切换至"C盘软件",根据需要进行选择,当然,也可以直接采用默认选择方式.选择操作完成后,点击&q

360安全卫士如何彻底清理c盘

  1.打开360安全卫士"程序,在右边的框框里,找到"更多",点击"更多功能"项. 2.点击后会跳转到另一个页面内,在这个页面找到"C盘搬家". 3.程序会对整个磁盘进行扫描,以确定可以进行搬家的内容.在"重要资料"项中,勾选"我的文档",接着切换至"C盘软件",根据需要进行选择,点击"一键搬软件"按钮. 4.在弹出的窗口中,确保将要进行搬家的程序已退出的

巧用Dos命令轻松灭除U盘病毒

  1.点击"开始→运行",输入"CMD",按回车键 2.打开命令提示符窗口,切换到U盘所在盘符或是中了Autorun.inf病毒的盘符下,依次执行下面两条命令就可以了: attrib -S -H -R autorun.inf del autorun.inf 3.结束完成. 通过上述简单的两个小步骤的操作之后,你是不是见识到了DOS命令的强大作用,只要简单的两个小命令,就可以轻松地灭除了U盘病毒,是不是很神奇呢?这里小编需要提醒大家的是DOS命令执行后就很难恢复了,

利用DOS命令来对抗U盘病毒保护U盘数据_DOS/BAT

U盘的便捷性与大容量的存储性,深受着广大用户的欢迎,几乎每个用户都会人手一个,但就是这么广泛的使用,以至于U盘被病毒悄悄盯上,越来越多的病毒通过电脑.通过文件毁坏重要的数据,为了保护好U盘的数据,灭除U盘病毒成为了用户们的首要任务,下面就教大家一个小技巧,利用DOS命令来对抗U盘病毒. 利用DOS命令删除U盘病毒的步骤: 1.点击"开始→运行",输入"CMD",按回车键 2.打开命令提示符窗口,切换到U盘所在盘符或是中了Autorun.inf病毒的盘符下,依次执行下