Rocksdb引擎记录格式
Rocksdb是一个kv引擎,由facebook团队基于levelDB改进而来,Rocksdb采用LSM-tree存储数据,良好的读写特性以及压缩特性使得其非常受欢迎。此外,Rocksdb引擎作为插件已经集成在facebook维护的MySQL分支,用户可以通过SQL来访问rocksDB。本文主要通过分析Rocksdb引擎的记录格式,并通过对比innodb,来让大家了解Rocksdb。Rocksdb作为一个kv引擎,用户通过put(key,value)来写入key,或者通过get(key)接口来获取value,对rocksdb本身而言,每条记录都是一个key-value。当Rocksdb作为一个存储引擎接入到MySQL时,key-value结构如何存储表中各个索引,以及如何记录中各个列的信息是本文要具体讨论的。rocksdb引擎与innodb引擎类似,也是采用索引组织表,无论是表(主键索引)还是二级索引都是以LSM tree方式组织,rocksdb记录主要包括三部分,key,value和meta三部分内容,具体见下表,然后我通过介绍一条具体记录在rocksdb引擎中的存储格式来说明问题。
rocksdb基本记录存储格式
key_size |
key |
value_size |
value |
|
PK/SecKey |
Columns data |
SeqenceId,flag |
create table row_format(
id int not null,
c1 int,
c2 char(10) not null,
c3 char(10),
c4 varchar(10),
c5 varchar(10) not null,
c6 blob,
c7 binary(10) not null,
c8 varbinary(10)) engine=rocksdb;
insert into row_format(id,c2,c4,c5,c7) values(1,'abc','abc','efg','')
key部分:
Index_id |
key |
4bytes |
8bytes |
0x7fdfa4278ea0: 0x00 0x00 0x01 0x7b 0x00 0x00 0x00 0x00
0x7fdfa4278ea8: 0x00 0x00 0x00 0x05
Index_id:索引的编号,全局唯一。
rowid:由于表没有主键,系统会产生一个bigint类型的rowid作为主键,占用8个字节,而innodb引擎的rowid占6个字节,需要注意的是rowid存储采用的大端的存储(高位存储低字节),这里主要是为了memcompare。
Value部分:
Null-flag |
ID |
C1 |
C2 |
C3 |
C4 |
C5 |
C6 |
C7 |
C8 |
|
Length |
1B |
4B |
---- |
30B |
---- |
4B |
4B |
---- |
10B |
---- |
Value |
1 |
abc0x20… |
len+value |
len+value |
1110x00… |
0x7fdfa4251e50: 0x1b 0x01 0x00 0x00 0x00 0x61 0x62 0x63
0x7fdfa4251e58: 0x20 0x20 0x20 0x20 0x20 0x20 0x20 0x20
0x7fdfa4251e60: 0x20 0x20 0x20 0x20 0x20 0x20 0x20 0x20
0x7fdfa4251e68: 0x20 0x20 0x20 0x20 0x20 0x20 0x20 0x20
0x7fdfa4251e70: 0x20 0x20 0x20 0x03 0x61 0x62 0x63 0x03
0x7fdfa4251e78: 0x65 0x66 0x67 0x31 0x31 0x31 0x00 0x00
0x7fdfa4251e80: 0x00 0x00 0x00 0x00 0x00
说明:
- Value的最前面部分(0x1b)就是存放记录的null信息。根据记录中可以为null字段的个数,确认需要占用的字节数,如果小于8个,则只需要一个字节。例子中,c1,c3,c4,c6,c8均可以为null,因此需要5个bit,所以用1个byte表示Null-flag即可,由于插入记录中,c4不为null,则对应的bit为0,也就是0x00011011。
- 对于null,无论是定长还是非定长数据类型,都不占用真实的存储空间,只需要一个bit位来表示为null即可。
- 空串’’与null,上面提到了null需要占一个标记位,而对于’’,如果是变长字段仍然需要存储长度信息,对于定长字段,则会补全。
- 对于变长字段,比如varchar,0x03 0x61 0x62 0x63数据有len+data组成,如果数据长度小于256,len只需要占用一个byte;如果len大于255,且小于65536,则需要占用2个字节,对于longblob类型,则需要占4个字节。
- 对于定长字段,不需要存长度信息直接存储data,如果不足则补充。补充字符有点诧异,对于char类型,补充0x20,对于binary类型,补充0x00。
- 对于lob类型,比如tinyblob,blob,mediumblob,longblob,以及对应的text类型,处理策略与varchar类似,存储长度的字节数根据数据类型的范围确定,比如blob长度占用2个字节,而longblob的长度占4个字节。所以在rocksdb里面,没有innodb中所谓“溢出页”的概念。对于innodb引擎,如果blob字段内容超过768字节,多余的data存储在溢出页,页内通过20个字节指向溢出页,主要包括第一个blob页的space_id,page_no和起始偏移,如果存在多个blob页,则页与页之间通过类似的方式进行关联。具体可以参考btr0cur.h文件中关于BTR_EXTERN_xxx相关的宏定义,以及接口btr_copy_externally_stored_field_prefix_low。
- 有关value部分的存储实现可以参考rocksdb引擎接口convert_record_to_storage_format,convert_record_from_storage_format和innodb引擎接口row_mysql_store_col_in_innobase_format,row_sel_field_store_in_mysql_format。
Meta部分:
Meta部分主要是SequenceID,这个SequenceID在事务提交时产生,主要用于rocksDB实现MVCC,用于可见性判断,此外Meta中还包含flag信息,由于标示记录类型,put,delete,singleDelete等,具体而言Sequence占7个字节,flag占1个字节。
rocksdb索引格式
Rocksdb中,所有的数据都是通过索引来组织,与Innodb类似,也是索引组织表,每个索引有一个全局唯一的index_id。索引主要包括两类:主键索引和二级索引,前面介绍的记录格式,也就是主键索引的格式,包括key,value和meta三部分。二级索引也包含key,value和meta三部分,但是value中不包含任何数据,只是包含checksum信息。
主键索引
key |
Value |
Meta |
|||
Index_id |
PK |
NULL标记位 |
列数据 |
Checksum(可选) |
SeqId,flag |
二级索引
key |
Value |
Meta |
||
Index_id |
SecondaryKey |
PK |
Checksum(可选) |
SeqId,flag |
对比innodb引擎(innodb_file_format=Barracuda,row_format=compact)
innodb记录格式
变长字段长度列表 |
NULL标记位 |
record_header |
Trxid |
Roll_ptr |
列数据 |
create table row_format(
id int not null,
c1 int,
c2 char(10) not null,
c3 char(10),
c4 varchar(10),
c5 varchar(10) not null,
c6 blob,
c7 binary(10) not null,
c8 varbinary(10)) engine=innodb;
insert into row_format(id,c2,c4,c5,c7) values(1,'','ab','efg','');
记录内容:
0000c0b0 00 00 03 02 0a 1b 00 00 18 ff b5 00 00 00 00 28 |...............(|
0000c0c0 00 00 00 00 01 01 03 83 00 00 01 36 01 10 80 00 |...........6....|
0000c0d0 00 01 31 32 33 34 20 20 20 20 20 20 61 62 65 66 |..1234 abef|
0000c0e0 67 31 31 31 00 00 00 00 00 00 00 00 00 00 00 00 |g111............|
说明:
1. 03 02 0a,这里存的是长度信息,所有非null的变长列信息都逆序存在一起,这里按先后顺序是c5,c4,c2,这里innodb将char(10)也当作变长字段处理了。
2. 1b存储的是null信息,与rocksdb对null处理一致。00 00 18 ff b5存储的是record-header。
3. 00 00 00 00 28 00 00 00 00 01 01 03 83 00 00 01 36 01 10, 这三部分别是rowid,trxid和roll_ptr,分别占6个字节,6个字节和7个字节。
4. 最后一部分是数据,null不占任何存储空间,与rocksdb处理类似。区别在于对于char类型的处理,innodb将字段c2类型char(10)补齐到10个字节,存储为31 32 33 34 20 20 20 20 20 20,将其作为varchar处理,记录了长度信息;而Rocksdb则是补齐到30个字节(utf8字符集),作为char处理,不记录长度信息。
整体而言,innodb记录格式包含了record_header(记录头信息),占5个字节,主要包括记录号(heap_no),列数目,下一条记录的位置以及是否删除等信息。rocksdb则相对简单,只有整体的value-size,以及通过Meta中flag标示记录的状态put 或者是delete。innodb将变长列长度信息集中存放在一起,使得查找任意列的代价都差不多,而rocksdb的变长列信息则是放在每列的前面,访问最后一列需要逐一计算前面的列,才能定位。此外,由于innodb引擎与rocksdb引擎由于实现MVCC的机制不同,导致innodb引擎和rocksdb引擎需要存储的额外信息也不同。Innodb实现MVCC依赖于回滚段信息,记录需要额外存储trxid和roll_ptr两个字段,分别是6个字节和7个字节(type,rsegid,pageNO,offset),其中type占一个bit位,标示insert 或者是update类型,rsegid回滚段id占7bit位,pageNo占4个字节,页内偏移占2个字节。Rocksdb实现MVCC则是依赖于SequenceID,通过SequenceID来判断记录的可见性,SequenceID占7个字节。
细节上来说,RocksDB引擎和innodb引擎在处理null,char和varchar的方式类似,但innodb对于char类型做了优化,统一作为varchar处理。另外rocksdb引擎没有对blob做特殊处理。你可能会有疑问,rocksdb不是也有block_size吗,如果设置为16k,blob数据超过16k怎么办?对于innodb而言,由于表实质是以一个个page通过B-tree组织起来的,每个page是固定大小,当记录非常大时,就需要借助溢出页,通过链接的方式关联起来。而rocksdb中block_size只是一个压缩单位,并没有严格约束,文件内容以block组织,由于文件中block可能是压缩过的,因此每个block的大小不固定,通过偏移来定位具体某个block的位置。如果遇到大的blob数据,则可能这个block比较大,记录所有数据存储在一起,不会跨block。
对于索引长度限制也有所不同,对于innodb引擎来说,索引中单列长度不能超过767个字节,而rocksdb引擎单列长度不超过2048个字节,具体可以参考max_supported_key_part_length各自的实现;整个索引的长度,rocksdb和innodb都限制在3072个字节,实际上是server层的限制,因为它们的各自限制的长度都比server层的大。具体可以参考各自max_supported_key_length的实现。
参考文档
http://dev.mysql.com/doc/refman/5.7/en/innodb-physical-record.html
http://www.cnblogs.com/zhoujinyi/articles/2726462.html
Rocksdb引擎记录格式的更多相关文章
- SSDB 数据库如何换用 rocksdb 引擎?
牧童遥指杏花村,一枝红杏出墙来… SSDB 数据库如何换用 rocksdb 引擎? idea's blog 2014-04-12 71 阅读 rocksdb NoSQL SSDB 数据库使用的是 G ...
- 2014-08-07 SSDB 使用 rocksdb 引擎
http://www.ideawu.net/blog/archives/824.html 为了满足各位对 Facebook 出品的 rocksdb 的爱好, SSDB 数据库也可以使用 rocksdb ...
- myrocks记录格式分析
概况 rocksdb作为KV存储引擎,那么myrocks记录最终会以kv的形式存储在rocksdb中.MySQL中的表一般由若干索引组成, 在innodb存储引擎中,每个索引对应一颗B树,而在rock ...
- 腾讯工程师教你玩转 RocksDB
欢迎大家前往云+社区,获取更多腾讯海量技术实践干货哦~ 作者:腾讯云数据库内核团队 原文标题:[腾讯云CDB]教你玩转MyRocks/RocksDB-STATISTICS与后台线程篇 0. Intro ...
- myrocks复制中断问题排查
背景 mysql可以支持多种不同的存储引擎,innodb由于其高效的读写性能,并且支持事务特性,使得它成为mysql存储引擎的代名词,使用非常广泛.随着SSD逐渐普及,硬件存储成本越来越高,面向写优化 ...
- 2016 DTCC(中国数据库技术大会)
上周去参加了2016 DTCC(数据库技术大会),会议总共持续3天,议题非常多,我这里搜集了最新的公开的PPT内容,有兴趣的同学可以下载看看,PPT合集下载链接为:http://pan.baidu.c ...
- b2c项目基础架构分析(一)b2c 大型站点方案简述 已补充名词解释
我最近一直在找适合将来用于公司大型bs,b2b b2c的基础架构. 实际情况是要建立一个bs架构b2b.b2c的网站,当然还包括wap站点.手机app站点. 一.现有公司技术人员现状: 1.熟悉asp ...
- MyRocks DDL原理
最近一个日常实例在做DDL过程中,直接把数据库给干趴下了,问题还是比较严重的,于是赶紧排查问题,撸了下crash堆栈和alert日志,发现是在去除唯一约束的场景下,MyRocks存在一个严重的bug, ...
- 在centos环境下编译安装myrocksdb
rocksdb(https://rocksdb.org.cn/)是脸书(facebook)公司开源的一个key-value存储引擎,基于leveldb开发.rocksdb使用的是LSM存储引擎,纯c+ ...
随机推荐
- android内部培训视频_第五节(1)_OA实战之登录界面
第五节(1):OA实战之登录界面 一.登录界面布局 1.背景图片 2.文本框 3.checkbox 4.按钮 暂未实现点击切换图片效果 <RelativeLayout xmlns:androi ...
- 【说解】在shell中通过mkfifo创建命名管道来控制多个进程并发执行
背景: 工作中有两个异地机房需要传数据,数据全名很规范,在某个目录下命名为统一的前缀加上编号.如/path/from/file.{1..100}.而机房间的专线对单个scp进程的传输速度是有限制的,比 ...
- quartz.net 时间表达式----- Cron表达式详解
序言 Cron表达式:就是用简单的xxoo符号按照一定的规则,就能把各种时间维度表达的淋漓尽致,无所不在其中,然后在用来做任务调度(定时服务)的quart.net中所认知执行,可想而知这是多么的天衣无 ...
- T-sql语句查询执行顺序
前言 数据库的查询执行,毋庸置疑是程序员必备技能之一,然而数据库查询执行的过程绚烂多彩,却是很少被人了解,今天哥哥要带你装逼带你飞,深入一下这sql查询的来龙去脉,为查询的性能优化处理打个基础,或许面 ...
- 高性能JavaScript--加载和执行(简要学习笔记一)
1.多数浏览器使用单一进程来处理用户界面刷新和JavaScript脚本的执行.所以同一时刻只能做同一件事.JavaScript执行过程耗时越久,浏览器等待相应的时间就越长. 2.<scrip ...
- 使用SuperSlide 实现标签切换
小颖之前还写过一篇jquery实现标签切换的文章 jquery实现Tab选项卡菜单 今天小颖逛博客园时看到了用SuperSlide 实现标签切换的文章,所以小颖就自己试了下,试了后发现SuperSl ...
- CSS3属性 box-shadow 向框添加一个或多个阴影
CSS3属性 利用box-shadow制作网页页眉背景 box-shadow 浏览器支持 IE9+.Firefox 4.Chrome.Opera 以及 Safari 5.1.1 支持 box-shad ...
- c#编程基础之ref、out参数
引例: 先看这个源码,函数传递后由于传递的是副本所以真正的值并没有改变. 源码如下: using System; using System.Collections.Generic; using Sys ...
- ASP.NET MVC5 ModelBinder
什么是ModelBinding ASP.NET MVC中,所有的请求最终都会到达某个Controller中的某个Action并由该Action负责具体的处理和响应.为了能够正确处理请求,Action的 ...
- 【那些年关于java多态应用】
1.多态:具有表现多种形态的能力的特征 父类: public abstract class Animal { public abstract void Say();} 子类: public class ...