zoukankan      html  css  js  c++  java
  • 聊聊RocksDB Compact

    | 导语 对于 LevelCompact 策略,RocksDB会根据每一层不同的策略计算出CompactScore,根据CompactScore大小来决定那一层将会优先进行Compact,然后选择Level-N 和Level-(N+1)的文件进行Compact。如何计算CompactScore? 如何选择文件进行Compact?Compact有哪些参数?如何知道RocksDB当前的一个状态?

     

    RocksDB是基于LSM结构的K-V存储引擎,由于数据文件采用Append Only方式写入,而对于过期的数据、重复的数据必然会存在有多份副本,这部分数据通过Compact的方式进行逐步的清理。 
    那么这里好奇的提出几个问题,由这几个问题引出下文:

    1. RocksDB是如何进行Compact 的?
    2. Compact的时候这些文件是如何进行选择的?
    3. Compact在什么时候、或者什么条件下触发?
    4. 对于Compact我们能知道哪些信息?通过TRedis怎么查看这部分信息?
    5. 有哪些参数可以控制或者影响到Compact

    由于我们的TRedis底层采用RocksDB存储引擎进行持久化,底层数据文件采用分层的方式管理,故这里讨论的Compact 基于Level Compact 。

    数据怎么来?我们调用TRedis接口进行写数据时,数据会先写入到内存中的Memtable里边,当Memtable写满后会写入下一个Memtable,Memtable采用Skiplist结构以此保证数据按照Key的字典序进行排序,同时这个Memtable会被后台线程刷到磁盘文件–Level-0,当Level-0文件个数达到一定数量,Compact线程可能会进行Compact,由此产生Level-1,当Level-1文件总大小达到一定大小后, Compact线程可能会进行Compact,由此产生Level-2,…….

    RocksDB对每一层的处理规则不太一样,由于Level-0层的数据直接由Memtable dump得到,从而不能保证Level-0层的每个文件Key的范围不能有交集,故对Level-0层的会进行特殊处理,而对于Level-1+层处理规则一样。

    Level-0 层的文件在不停的从Memtable 中dump出来,那么何时才会把这些Level-0层的文件合并到Level-1 ? 
    RocksDB对对每一层进行打分,分数从0~1000000,这个分数的大小决定了进行Compact 的优先级,分数越大,越先进行Compact。

    那么这个分数如何计算出来?
    • 如果是Level-0层,会先算出当前有多少个没有进行Compact 的文件个数numfiles, 然后根据这个文件的个数进行判断,当numfiles<20 时,Score = numfiles/4;当24>numfiles>=20时,Score = 10000;当 numfiles>=24时,Score = 1000000
    相关参数说明
    level0_file_num_compaction_trigger 4 当有4个未进行Compact的文件时,达到触发Compact的条件
    level0_slowdown_writes_trigger 20 当有20个未进行Compact的文件时,触发RocksDB,减慢写入速度
    level0_stop_writes_trigger 24 当有24个未进行Compact的文件时,触发RocksDB停止写入文件,此时会尽快的Compact Level-0层文件
    • 如果是Level-1+层,会去计算每一层未进行Compact文件的总Size,然后再和这一层的”容量值”做对比,得到一个比值,这个值就是该层的 CompactScore ,也就是说对于Level-1+层,Compact 触发条件是看这一层文件的大小而不是个数。Score = level_bytes / MaxBytesForLevel(level)
    对于Level-1+层,每一层的最大Bytes 是如何计算出来的?

    Level-1 层 文件总大小由 max_bytes_for_level_base 参数控制,而 Level-2 层的大小通过: Level_max_bytes[N] = Level_max_bytes[N-1] * max_bytes_for_level_multiplier^(N-1)*max_bytes_for_level_multiplier_additional[N-1] 计算得出:

    参数说明
    max_bytes_for_level_base 10485760 用于指定Level-1 层总大小,超过这个值满足触发Compact条件
    max_bytes_for_level_multiplier 10 每一层最大Bytes 乘法因子
    max_bytes_for_level_multiplier_addtl[2] 1 Level-2 层总大小调整参数
    max_bytes_for_level_multiplier_addtl[3] 1 Level-3 层总大小调整参数
    max_bytes_for_level_multiplier_addtl[4] 1 Level-4 层总大小调整参数
    max_bytes_for_level_multiplier_addtl[5] 1 Level-5 层总大小调整参数
    max_bytes_for_level_multiplier_addtl[6] 1 Level-6 层总大小调整参数
    if (i > 1) {
    level_max_bytes[i] = MultiplyCheckOverflow(
    MultiplyCheckOverflow(level_max_bytes[i - 1],
    max_bytes_for_level_multiplier),
    max_bytes_for_level_multiplier_additional[i - 1]);
    } else {
    level_max_bytes[i] = max_bytes_for_level_base;
    }
    在进行Compact的时候,会选择哪些文件进行Compact操作呢?

    对于Level-0层文件,RocksDB总是选择所有的文件进行Compact操作,因为Level-0层的文件之间,可能会有key范围的重叠。 
    对于Level-N (N>1)层的文件,会先按照文件大小排序(冒泡排序),选出最大的文件,并计算这个文件Key 的起止范围,通过这个范围查找Level-N+1层文件,把选出的Level-N 文件和Level-N+1 文件做为输入,并且在Level-N+1新建一个或多个SST文件作为输出。 
    可以通过设置max_background_compactions 大于1 来使用并行Compact,不过这个并行Compact 不能作用到Level-0层。

      // Find the compactions by size on all levels.
    for (int i = 0; i < NumberLevels() - 1; i++) {
    double score = vstorage->CompactionScore(i);
    level = vstorage->CompactionScoreLevel(i);
    assert(i == 0 || score <= vstorage->CompactionScore(i - 1));
    if ((score >= 1)) {
    c = PickCompactionBySize(mutable_cf_options, vstorage, level, score);
    if (c == nullptr ||
    ExpandWhileOverlapping(cf_name, vstorage, c) == false) {
    delete c;
    c = nullptr;
    } else {
    break;
    }
    }
    }

    如何查看RocksDB内部状态?

    一般情况下内部状态会定时dump出来存放到LOG文件里,这个时间可以通过:stats_dump_period_sec 来控制这个dump内部状态的频率,如果是TRedis V1.2.9 版本以上可以通过 rocksprop rocksdb.cfstats 得到这些信息:

    关于这些参数的解释如下:

    列名解释
    Level Level0~N、或者合计值、或者Int
    Files SST文件数量/待进行compact的SST文件数
    Size(MB) SST文件总大小
    Score Read(GB) 代表进行compact的优先级,分数越高越会优先进行compact
    Rn(GB) 进行compact时,读当前层文件的大小
    Rnp1(GB) 进行compact时,读取下一层文件的大小
    Write(GB) compact完成时,写入文件的大小
    Wnew(GB) 新产生的数据大小: 写入到Level-(N+1)层的大小 - 从Level-(N+1)层读的大小
    RW-Amp 读写放大比例 : 总的读写 / 从Level-N层读的大小
    W-Amp 写放大比例: 写入Level-(N+1)层大小/从Level-N层的大小
    Rd(MB/s) 读文件速度: (bytes_readn + bytes_readnp1 )/((micros + 1) / 1000000.0)
    Wr(MB/s) 写文件速度: bytes_written / ((micros + 1) / 1000000.0)
    Rn(cnt) Files read from level N during compaction between levels N and N+1
    Rnp1(cnt) Files read from level N+1 during compaction between levels N and N+1
    Wnp1(cnt) Files written during compaction between levels N and N+1
    Wnew(cnt) Wnp1 - Rnp1
    Comp(sec) Compact 累计耗时:micros / 1000000.0
    Comp(cnt) Compact累计的次数
    Avg(sec) 平均每次Compact耗时
    Stall(sec) level0_slowdown 耗时
    Stall(cnt) level0_slowdown 累计次数
    Avg(ms) 平均每次Stall耗时
    RecordIn Compact 进行时,所有Level-N,Level-(N+1) 输入的entries数
    RecordDrop Compact 进行时: RecordIn - 输出到Level-(N+1)
  • 相关阅读:
    动态规划之最大子序和(53)
    退出系统
    请维护容差码的容差限制-OMR6
    SAP561该物料不可能有库存记帐
    虚拟机锁定文件失败,disk启动失败
    该物料不可能有库存记账
    其他收货入库
    有关业务 事件类型wa 在 的号码范围不存在
    给供应商付款
    T169V表目:不存在
  • 原文地址:https://www.cnblogs.com/svan/p/7047251.html
Copyright © 2011-2022 走看看