InnoDB是通用的,非常强大的,是世界上使用最广泛的开源关系数据库。InnoDB在大多数工作负载上运行良好,但有一些用例MyRocks可以胜过。 对于所有工作负载类型,MyRocks不打算击败InnoDB。在这个页面中,我描述了与InnoDB相比的MyRocks优势。
如果在磁盘上运行数据库,则空间无关紧要,但是如果你在闪存上运行,减少空间非常重要,因为每GB成本远高于硬盘。
当你试图减少空间时,InnoDB有一些问题。首先,InnoDB使用B+Tree索引。如果没有顺序插入,B+Tree索引会碎片化。碎片增加30%-50%的额外空间并不罕见。
第二个问题是InnoDB压缩有空间开销,InnoDB每页压缩。默认情况下,未压缩的页面大小为16KB。压缩后,页面大小在MySQL 5.7之前对齐为4KB单位,
在5.7之后对齐OS/设备扇区大小单位(如果使用Punch-Hole压缩),在现代闪存设备上,扇区大小为4KB。
这意味着InnoDB仅压缩到25%,50%或100%(和5.7%中的75%)
例如,即使InnoDB压缩可以将数据从16KB压缩到5KB(减少68.75%),它实际上使用8KB,因此压缩效率从68.75%降低到50%。
图1:InnoDB中的空间放大(图片资源/一、概览/3.MyRocks优于InnoDB/图1.png)
另一方面,RocksDB是LSM数据库,非常适合减少空间。
RocksDB按照页面压缩,与InnoDB相同,但压缩页面未与OS扇区对齐。如果页面可以压缩到30%,它恰好使用30%的存储空间,而不是对齐到50%
RocksDB将数据存储到SST(排序字符串表)文件中。RocksDB有块(可以通过rocksdb_block_size配置,默认为4KB) 但块不与OS扇区大小对齐,
但SST文件与OS扇区大小对齐,但SST大小远大于页面大小(默认为2MB),因此对齐开销可忽略不计。
副作用,单块读取I/O请求可能最终读取两个连续块,如果仔细查看iostat r/s 与 rMB/s,您会发现I/O单元的大小略大于块大小,希望这不会导致HDD和Flash的性能问题
图2:MyRocks中的压缩(图片资源/一、概览/3.MyRocks优于InnoDB/图2.png)
除了可忽略的对齐开销之外,RocksDB还实现了两个主要功能来减少空间.
* 前缀秘钥编码
索引条目在RocksDB中排序(与许多其他数据库一样)。使用多列索引时,通常前N个字节与先前的索引条目相同。然后RocksDB通过不存储重复的前缀字节流来优化空间。
图3:RocksDB中的前缀键编码(图片资源/一、概览/3.MyRocks优于InnoDB/图3.png)
* 零填充行元数据
InnoDB和MyRocks每行都有一些空间开销。InnoDB每行存储6字节事务id和7字节回滚指针。他们存储在主键中,但不存储在二级索引中。即使使用压缩格式,它们也不会被压缩。
因此,无论压缩设置如何,总开销为每行13个字节。
MyRocks每行存储7字节序列id和1字节操作类型,他们存储在主键索引和辅助索引上。如果您有一个主键索引和两个辅助索引,则总开销为每行24个字节。这听起来很大,
但在实践中,空间开销要小的多。当在最底层写入SST文件时,RocksDB会对零填充序列ID进行特殊优化,该文件有90%的数据。零填充序列ID压缩后使用非常小的空间。
图4:零填充行元数据(图片资源/一、概览/3.MyRocks优于InnoDB/图4.png)
在纯闪存上,减少写入量(写入放大)很重要,因为如果写入太多的数据,闪存会烧坏。降低写入量还有助于提高闪存的整体吞吐量。
InnoDB采用"就地更新"架构,即使仅更新1条记录,行所属的整个页面也会变脏,而且必须将脏页写回存储区。
在典型的OLTP系统上,修改单元(行)大小远小于I/O单元(页面)大小。这使得写入放大非常高。
图5: InnoDB中的写入放大(图片资源/一、概览/3.MyRocks优于InnoDB/图5.png)
另一方面,RocksDB(LSM)数据库使用"仅追加"模型,编辑写入WAL(预写日志),然后定期与SST文件合并。
图6: MyRocks中的写入放大(图片资源/一、概览/3.MyRocks优于InnoDB/图6.png)
* 1.5B IDs,32个查询线程,48小时运行,闪存
* 空间:
InnoDB 1172GB
MyRocks 574GB (49%)
* QPS:
InnoDB 22227/s
MyRocks 33094/s
* 写 KB/s:
InnoDB 152,422
MyRocks 66,932 (44%)