MyRocks写入分析

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
云数据库 RDS MySQL,高可用系列 2核4GB
简介: --- title: MySQL · myrocks · myrocks写入分析 author: 张远 --- # 写入流程 myrocks的写入流程可以简单的分为以下几步来完成 1. 将解析后的记录(kTypeValue/kTypeDeletion)写入到WriteBatch中 2. 将WAL日志写入log文件 3. 将WriteBatch中的内容写到memtabl

title: MySQL · myrocks · myrocks写入分析

author: 张远

写入流程

myrocks的写入流程可以简单的分为以下几步来完成

  1. 将解析后的记录(kTypeValue/kTypeDeletion)写入到WriteBatch中
  2. 将WAL日志写入log文件
  3. 将WriteBatch中的内容写到memtable中,事务完成

其中第2,3步在提交时完成

WriteBatch与Myrocks事务处理密切相关,事务中的记录提交前都以字符串的形式存储在WriteBatch->rep_中,要么都提交,要么都回滚。 回滚的逻辑比较简单,只需要清理WriteBatch->rep_即可。详见TransactionImpl::Rollback

一个简单的insert 写入WriteBatch堆栈如下

#0  rocksdb::WriteBatchInternal::Put
#1  rocksdb::WriteBatch::Put
#2  myrocks::ha_rocksdb::update_pk
#3  myrocks::ha_rocksdb::update_indexes
#4  myrocks::ha_rocksdb::update_write_row
#5  myrocks::ha_rocksdb::write_row
#6  handler::ha_write_row
#7  write_record
#8  mysql_insert
#9  mysql_execute_command
#10 mysql_parse
#11 dispatch_command
#12 do_command
#13 do_handle_one_connection

一个简单的insert commit堆栈如下

#0  rocksdb::InlineSkipList<rocksdb::MemTableRep::KeyComparator const&>::Insert
#1  rocksdb::(anonymous namespace)::SkipListRep::Insert
#2  rocksdb::MemTable::Add
#3  rocksdb::MemTableInserter::PutCF
#4  rocksdb::WriteBatch::Iterate
#5  rocksdb::WriteBatch::Iterate
#6  rocksdb::WriteBatchInternal::InsertInto
#7  rocksdb::DBImpl::WriteImpl
#8  rocksdb::DBImpl::Write 
#9  rocksdb::TransactionImpl::Commit
#10 myrocks::Rdb_transaction_impl::commit_no_binlog
#11 myrocks::Rdb_transaction::commit
#12 myrocks::rocksdb_commit
#13 ha_commit_low
#14 TC_LOG_MMAP::commit 
#15 ha_commit_trans
#16 trans_commit_stmt
#17 mysql_execute_command
#18 mysql_parse
#19 dispatch_command
#20 do_command
#21 do_handle_one_connection

提交流程及优化

这里只分析rocksdb引擎的提交流程,实际MyRocks提交时还需先写binlog(binlog开启的情况).

rocksdb引擎提交时就完成两个事情

  1. 写WAL日志(WAL开启的情况下rocksdb_write_disable_wal=off)
  2. 将之前的WriteBatch写入到memtable中

然而,写WAL是一个串行操作。为了提高提交的效率, rocksdb引入了group commit机制。

待提交的事务都依次加入到提交的writer队列中,这个writer队列被划分为一个一个group. 每个group有一个leader, 其他为follower,leader负责批量写WAL。每个group由双向链表link_older, link_newer链接。如下图所示

屏幕快照 2017-07-11 下午7.46.22.png

每个writer可能的状态如下

  • Init: writer的初始状态
  • Header: writer被选为leader
  • Follower: writer被选为follower
  • LockedWating: writer在等待自己转变为指定的状态
  • Completed:writer操作完成

writer的状态变迁跟group是否并发写memtable有关
当开启并发写memtable(rocksdb_allow_concurrent_memtable_write=on)且group中的writer至少有两个时,group才会并发写。

group并发写时writer的状态变迁图如下:

屏幕快照 2017-07-14 下午1.25.27.png

group非并发写时writer的状态变迁图如下:

屏幕快照 2017-07-11 下午7.46.50.png

源码结构图如下(图片来自林青)
屏幕快照 2017-07-14 下午1.44.46.png

上面的图是在group内writer并发写memtable的情形。

非并发写memtable时,没有LaunchParallelFollowers/CompleteParallelWorker, Insertmemtable是由leader串行写入的。

这里group commit有以下要点

  1. 同一时刻只有一个leader, leader完成操作后,才设置下一个leader
  2. 需要等一个group都完成后,才会进行下一个group
  3. group中最后一个完成的writer负责完成提交和设置下一个leader
  4. Leader 负责批量写WAL
  5. 只有leader才会去调整双向链表link_older,link_newer.

注意这里2,3 应该可以优化改进为

  • 不需要等一个group完成再进行下一个group
  • 不同group的follower可以并发执行
  • 只有leader负责完成提交和设置下一个leader

写入控制

rocksdb在提交写入时,需考虑以下几种情况,详见PreprocessWrite

  • WAL日志满,WAL日志超过rocksdb_max_total_wal_size,会从所有的colomn family中找出含有最老日志(the earliest log containing a prepared section)的column family进行flush, 以释放WAL日志空间
  • Buffer满,全局的write buffer超过rocksdb_db_write_buffer_size时,会从所有的colomn family中找出最先创建的memtable进行切换,详见HandleWriteBufferFull
  • 某些条件会触发延迟写

    • max_write_buffer_number > 3且 未刷immutable memtable总数 >=max_write_buffer_number-1
    • 自动compact开启时,level0的文件总数 >= level0_slowdown_writes_trigger
  • 某些条件会触发停写

    • 未刷immutable memtable总数 >=max_write_buffer_number
    • 自动compact开启时,level0的文件总数 >= level0_stop_writes_trigger

具体可参考RecalculateWriteStallConditions

总结

rocksdb写入流程还有优化空间,Facebook也有相关的优化。

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
SQL MySQL 关系型数据库
MySQL · 引擎分析 · InnoDB行锁分析
前言 理解InnoDB行锁,分析一条SQL语句会加什么样的行锁,会锁住哪些数据范围对业务SQL设计和分析线上死锁问题都会有很大帮助。对于InnoDB的行锁,已经有多篇月报进行了介绍,这里笔者借鉴前面月报的内容,综合自己的理解,对源码的基础实现做一个介绍(会包含部分表锁介绍),然后结合具体SQL语句分析加锁类型和加锁范围。
2185 0
|
存储 关系型数据库 MySQL
myrocks统计信息
--- title: MySQL ・ myrocks ・ myrocks统计信息 author: 张远 --- # 概述 mysql查询优化主要是在代价统计分析的基础上进行的。合理的代价模型和准确的代价统计信息决定了查询优化的优劣。myrocks基于mysql5.6, 目前的代价模型依赖的主要因素是IO和CPU,mysql5.7及以上的版本代价模型做了较多改进,具体可以参考[这里](
2284 0
|
存储 关系型数据库 索引
myrocks记录格式分析
--- title: MySQL · myrocks · myrocks记录格式分析 author: 张远 --- # 概况 rocksdb作为KV存储引擎,那么myrocks记录最终会以kv的形式存储在rocksdb中。MySQL中的表一般由若干索引组成, 在innodb存储引擎中,每个索引对应一颗B树,而在rocksdb存储引擎中,索引对应于rocksdb中一段连续范围的数据。
3912 0
|
存储 NoSQL 安全
存储引擎常见batchwrite写优化
# 引言 做有竞争力的存储系统迟早会遇到需要性能瓶颈,本文简单记录一些batchwrite常见朴素优化思想,以防哪天我们需要完成这方面的工作,可以翻出来看看,借鉴一下人家的思想 本文不做代码层面探讨,可自行阅读链接中给出的代码。
1063 0
存储引擎常见batchwrite写优化
|
存储 监控 关系型数据库
myrocks之事务处理
--- title: MySQL · myrocks · myrocks之事务处理 author: 张远 --- # 前言 mysql目前支持的事务引擎有innodb,tokudb. rocksdb加入mysql阵营后,mysql支持的事务引擎增长至3个。 myrocks目前支持的事
3073 0
|
存储 关系型数据库 索引
myrocks 之数据字典
--- title: MySQL · myrocks · data dictionary 分析 author: 济天 --- # data dictionary rocksdb作为mysql的一个新的存储引擎,在存储引擎层,会维护自动的元数据信息。在innodb存储引擎中,我们通过information_schema下的INNODB_SYS_DATAFILES,INNODB_SY
3013 0
|
存储 关系型数据库 MySQL
MySQL优化系列(五)--数据库存储引擎(主要分析对比InnoDB和MyISAM以及讲述Mrg_Myisam分表)
MySQL优化系列(五)--数据库存储引擎(主要分析对比InnoDB和MyISAM以及讲述Mrg_Myisam分表) 之前一直是使用默认MySQL的InnoDB存储引擎,没有思考过为什么使用,也没思考过其优缺和其他数据库存储引擎。
2333 0
|
存储 算法 关系型数据库
关于innodb和tokudb存储引擎的压缩能力测试
新手上路,有不确切的地方,请指正~
7547 0
|
Java 关系型数据库 MySQL
RocksDB TransactionDB事务实现分析
## 基本概念 #### 1. LSN (log sequence number) RocksDB中的每一条记录(KeyValue)都有一个LogSequenceNumber(后面统称lsn),从最初的0开始,每次写入加1。该值为逻辑量,区别于InnoDB的lsn为redo log物理写入字节量。 这个lsn在RocksDB内部的memtable中是`单调递增`的,在WriteA
4354 0
|
关系型数据库 Java MySQL
RocksDB事务实现TransactionDB分析
本文主要对RocksDB中事务实现TransactionDB做分析,设计事务并发、隔离级别、MVCC等实现细节
9359 0