为了降低用户数据存储成本,2015年4月份,云数据库(aliyun rds)增加了tokudb引擎支持(mysql5.6版本),也是第一家支持tokudb的rds。
我们知道,当一个实例的数据空间超过tb级别时,空间存储和运维成本都是非常高的,尤其是做实例迁移和备份,整个过程耗时会非常长。
我们对线上一些大的innodb实例(tb级)平滑迁移到tokudb后,数据空间从 2tb+ 直接降到 400gb ,空间成本仅为原来的五分之一,而且读写性能没有任何降低(写性能反而提升不少)。通过线上几个大实例(tb级)的使用,tokudb的压缩比均在5倍以上,同样的空间大小,使用tokudb后可以存5倍的容量!
tokudb的另外一个特点就是低io消耗,相同数据量下,io花销基本是innodb的1/8,io成本也降低了不少,同样的iops限制下,tokudb写性能会更高。因为iops消耗较少,rds已经在线上部署tokudb+廉价sata盘集群,配合“方寸山”(分库分表proxy)来提供低成本高性能的pb级日志存储能力。
这个集群使用廉价的sata盘(iops能力~120),单台物理机基本可提供30,000 tps的写能力(tokudb_fsync_log_period=0和sync_binlog=1,针对类如日志型应用,对数据安全性要求不是很高的话,调整tokudb_fsync_log_period=1000,sync_binlog=1000,性能会更高),利用tokudb的大页(page size 4mb)压缩优势,尤其是对日志内容,压缩比基本在1/8以上,单机可提供160tb+的的存储能力,整个集群可轻松支持pb级。
使用tokudb,让你随便任性!
本篇来探讨下tokudb内部的一个重要机制: checkpoint。
tokudb的checkpoint只有一种方式:sharp checkpoint,即做checkpoint的时候,需要把内存中所有的”脏页”都刷回磁盘。本篇就来介绍下tokudb的sharp checkpoint的一些具体细节,使看官们对tokudb的checkpoint有个大概了解。
tokudb引擎里,数据存在于3个地方:
redo log (disk)
buffer pool (memory)
data file (disk)
为了性能,对“页”级的操作会先被cache到buffer pool里,当触发某些条件后,才会把这些“脏页”刷到磁盘进行持久化,这样就带来一个问题:
对于tokudb来说,整个fractal-tree元素有两部分的“页”组成:(buffer pool里的“页” ) + (data file里已持久化的”页”),如果tokudb crash后,buffer pool里的“页”丢失,只剩data file的“页”,此时的fractal-tree处于“混沌“状态(不一致状态)。
为了避免出现这种“混沌“状态,tokudb需要定期(默认60s)做checkpoint操作,把buffer pool里的“脏页”刷到磁盘的data file里。
当tokudb crash后,只需从上次的一致性状态点开始“回放” redo log里的日志即可,恢复的数据量大概就是60s内的数据,快吧?嗯。
tokudb checkpoint分2个阶段:begin_checkpoint 和 end_checkpoint
大体逻辑如下:
begin_checkpoint:
end_checkpoint:
以上就是整个checkpoint大概的逻辑,整个过程中,只有c6的任务最“繁重”,在这里面有几个“大活”:
clone的时候如果是leaf“页”,会对原“页”重做数据均分(leaf里包含多个大小均匀的子分区) –cpu消耗
刷盘前做大量压缩 –cpu消耗
多线程并发的把page刷到磁盘 –io操作
以上3点会导致checkpoint的时候出现一点点的性能抖动,下面看组数据:
以上为sysbench测试数据(读写混合),仅供参考,可以看到在[255s]和[315s]checkpoint的时候,性能有个抖动。
喵,另外一个问题来了:如果tokudb在end_checkpoint c6的时候crash了呢,只有部分“脏页”被写到磁盘?此时的数据库(fractal-tree)状态岂不是不一致了?
tokudb在这里使用了copy-on-write模型,本次checkpoint的“脏页”在刷到磁盘的时候,不会覆写上次checkpoint的文件区间,保证在整个checkpoint过程中出现crash,不会影响整个数据库的状态。