MyRocks之memtable切换与刷盘

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: --- title: MySQL · myrocks · MyRocks之memtable切换与刷盘 author: 张远 --- # 概述 MyRocks的memtable默认是skiplist,其大小和个数分别由参数write_buffer_size和max_write_buffer_number控制。

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文件中。
屏幕快照 2017-07-19 下午4.07.35.png

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.

屏幕快照 2017-06-16 上午6.56.39.png

这里有两个重要的概念

  • 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需放开此限制。

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
目录
相关文章
|
5月前
|
运维 安全 数据挖掘
【服务器数据恢复】硬盘离线导致Raid5热备盘上线同步失败的数据恢复案例
**服务器数据恢复环境:** 两组由4块磁盘组建的raid5磁盘阵列,两组raid5阵列划分为lun并组成了lvm结构,ext3文件系统。 **服务器故障:** 一组raid5阵列中的一块硬盘离线,热备盘自动上线并开始同步数据。在热备盘完成同步之前,该组raid5阵列中另一块硬盘离线,热备盘同步失败,该组raid5阵列崩溃无法使用,lvm结构被破坏,ext3文件系统无法正常使用了。
|
2月前
|
存储 运维 数据挖掘
服务器数据恢复—raid5阵列2块硬盘离线,热备盘未全部启用的数据恢复案例
服务器存储数据恢复环境: 一台EMC某型号存储中有一组RAID5磁盘阵列。该raid5阵列中有12块硬盘,其中2块硬盘为热备盘。 服务器存储故障: 该存储raid5阵列中有两块硬盘离线,只有1块热备盘启用替换掉其中一块离线盘,另外1块热备盘未成功启用,raid5阵列崩溃,存储不可用。 磁盘阵列中硬盘离线的原因通常是磁盘存在物理故障或者硬盘出现坏道。由于EMC存储中的raid控制器的磁盘检查策略十分严格,经常将硬盘的性能不稳定判定为硬件故障并将该硬盘踢出raid。很多情况下EMC存储中raid崩溃的原因就是磁盘读写不稳定。
服务器数据恢复—raid5阵列2块硬盘离线,热备盘未全部启用的数据恢复案例
|
3月前
|
Linux
磁盘爆满如何解决?
磁盘爆满如何解决:df -h 查看磁盘空间的使用情况,释放磁盘空间、增加磁盘空间
|
4月前
|
存储 运维 数据挖掘
服务器数据恢复—raid5热备盘同步失败导致阵列崩溃的数据恢复案例
某品牌DS5300存储,包含一个存储机头和多个磁盘柜,组建了多组RAID5磁盘阵列。 某个磁盘柜中的一组RAID5阵列由15块数据盘和1块热备硬盘组建。该磁盘柜中的某块硬盘离线,热备盘自动替换并开始同步数据,在热备硬盘同步数据的过程中,又有一块硬盘出现问题离线,数据同步失败,该RAID5阵列失效,卷无法挂载访问。
|
5月前
C盘爆满?简单几招教你释放、清理C盘几十G空间,最有效的C盘清理方法
C盘爆满?简单几招教你释放、清理C盘几十G空间,最有效的C盘清理方法
|
5月前
|
存储 数据挖掘
服务器数据恢复—raid5热备盘同步失败的数据恢复案例
一台存储上有一组由多块硬盘组建的raid5阵列,该raid5阵列中的一块硬盘掉线,热备盘自动上线同步数据的过程中,raid阵列中又有一块硬盘掉线,热备盘的数据同步被中断,raid5阵列失效,卷挂载不上,存储瘫痪。 这类raid故障比较常见,服务器raid中的硬盘大多数情况下都是一个批次的同品牌同型号的硬盘,一旦有硬盘出现故障掉线,那么其他硬盘也随时有出故障掉线的可能。
|
5月前
|
Oracle 关系型数据库 数据挖掘
服务器数据恢复—raid5磁盘掉线热备盘未激活导致崩溃的数据恢复案例
服务器数据恢复环境: 某品牌X系列服务器,4块SAS硬盘组建了一组RAID5阵列,还有1块磁盘作为热备盘使用。服务器上层安装的linux操作系统,操作系统上部署了一个基于oracle数据库的OA(oracle已经不再为该OA系统提供后续服务支持)。 服务器故障: raid5中一块磁盘离线,热备盘未自动激活rebuild(原因不明)。服务器在运行一段时间后,另一块磁盘离线,RAID5阵列崩溃。用户方要求尽可能恢复服务器操作系统和服务器中的数据。
服务器数据恢复—raid5磁盘掉线热备盘未激活导致崩溃的数据恢复案例
|
Windows
如何轻松解决C盘爆满情况——SpaceSniffer
如何轻松解决C盘爆满情况——SpaceSniffer
442 0
|
SQL 安全 关系型数据库
需要binlog的场景下,“暴力”干掉历史binlog文件,尽情释放磁盘空间
需要binlog的场景下,“暴力”干掉历史binlog文件,尽情释放磁盘空间
103 0
|
SQL 安全 关系型数据库
正确、安全的手动删除历史binlog,尽情释放磁盘空间。
正确、安全的手动删除历史binlog,尽情释放磁盘空间。
927 0