TokuDB 引擎 (Percona Server)

Percona Server可以看做是Linux上优化过的MySQL,Percona团队都是MySQL专家,比如Percona针对InnoDB优化的XtraDB 引擎是兼容InnoDB的,Percona还提供了TokuDB版本的Percona Server,TokuDB是一个面向大数据,支持事务的存储引擎,有着非常好的随机写性能,并且支持在线 DDL。

Percona Server 可以看作是 MySQL 的增强版,因为和MySQL几乎完全兼容,在使用 yum 安装的时候只是包名不一样,安装后的产物都几乎相同。

特性:

  • 高压缩比,默认使用zlib进行压缩,尤其是对字符串(varchar,text等)类型有非常高的压缩比,比较适合存储日志、原始数据等。一般有5-10倍压缩比。
  • 在线添加索引,不影响读写操作
  • HCADER 特性,支持在线字段增加、删除、扩展、重命名操作,(瞬间或秒级完成)
  • 支持完整的 ACID 事务机制
  • 非常快的写入性能(索引的原因)
  • 支持show processlist 进度查看

缺点:

  • 读响应时间比InnoDB长,因为压缩解压缩的原因。CPU占用会高2-3倍,但由于压缩后空间小,IO开销低
  • 不支持外键,据说触发器等高级特性也尽量不要使用。
  • 其他未知的坑

适用场景:

  • 访问频率不高的数据或历史数据归档
  • 数据表非常大并且时不时还需要进行DDL操作

更多介绍参见官网:https://www.percona.com/doc/percona-server/5.6/tokudb/tokudb_intro.html

与 Oracle MySQL的版本区别

# Percona Server
mysql  Ver 14.14 Distrib 5.6.30-76.3, for Linux (x86_64) using  6.0
Server version: 5.6.30-76.3 Percona Server (GPL), Release 76.3, Revision 3850db5

# Oracle MySQL
mysql  Ver 14.14 Distrib 5.6.20, for Linux (x86_64) using  EditLine wrapper
Server version: 5.6.20-log Source distribution

安装 Percona Server

官网:https://www.percona.com/

使用官方 yum 源安装:

# 安装repo
yum install http://www.percona.com/downloads/percona-release/redhat/0.1-3/percona-release-0.1-3.noarch.rpm

# 检查安装成功
yum list | grep Percona-Server

# 安装 server, client, devel
yum install Percona-Server-server-56 Percona-Server-client-56 Percona-Server-devel-56

# 直接使用默认配置启动 (个人习惯启动脚本为mysqld)
mv /etc/init.d/mysql /etc/init.d/mysqld
/etc/init.d/mysqld start

# 客户端连接检查
mysql -uroot
Server version: 5.6.30-76.3 Percona Server (GPL), Release 76.3, Revision 3850db5

实际上以上与mysql-server,mysql-devel, mysql-client正好对应

安装后推荐使用我们的配置对照修改各项配置,目录位置等:

修改完后重新启动 MySQL 服务

安装 TokuDB 引擎

# 自动依赖安装jemalloc模块,安装后需重启服务
yum install Percona-Server-tokudb-56

# 执行自动化安装脚本,要求MySQL服务在启动状态
ps_tokudb_admin --enable -uroot

# TokuDB 要求关闭操作系统透明大页面功能,我们需要加到系统启动/etc/rc.local中,同时需要审视你自己的应用
echo never > /sys/kernel/mm/transparent_hugepage/enabled
echo never > /sys/kernel/mm/transparent_hugepage/defrag

# 再次重启,登陆安装成功后查看
mysql> SHOW ENGINES;

TokuDB 引擎使用

压缩率测试

某某数据,600W+记录,属于宽表,其中主要为Text类型长文本,压缩率高达1:7,最终空间大小对比:

# MYSIAM 70G / TokuDB 8G
70G     data/test/xxxxx_myisam.MYD

ToKuDB 
8.1G    tokudata/_test_xxxxx_main_34_1_1d_B_0.tokudb

某某基本信息数据,属于高表,4000W+记录,压缩率1:2.5,空间大小对比:

# MyISAM 30G / TokuDB 12G
27G yyyyy_160525.MYD
2.8G yyyyy_160525.MYI
 
963M _test_yyyyy_tokudb_key_Key_10_1_1d_B_1.tokudb
178M _test_yyyyy_tokudb_key_Updated_10_1_1d_B_2.tokudb
11G _test_yyyyy_tokudb_main_10_1_1d_B_0.tokudb

当我们把 TokuDB 表记录插如到2.5亿,占用空间仅 46G,此时如果是 MyISAM 应该要破百G

1.7G    /opt/mysql/data/_test_sql_3f84_b_key_Key_5a_3_1d.tokudb
993M    /opt/mysql/data/_test_sql_3f84_b_key_Updated_5a_4_1d.tokudb
44G     /opt/mysql/data/_test_sql_3f84_b_main_5a_2_1d.tokudb

索引动态创建与删除

TokuDB 允许你动态创建索引,而不影响插入、查询操作,该操作会再后台进行:

SET tokudb_create_index_online=on;
CREATE INDEX index ON table (field_name);

CREATE  UNIQUE INDEX `Key` ON `yyyyy_tokudb`(`Key`);

注意:只能使用CREATE INDEX语句,而不能使用ALTER(同样会阻塞)

在线添加、删除字段、扩展字段、字段改名

该表为某某年报,600W+,8G,秒级完成:

# 新增字段
mysql> ALTER TABLE `test`.`xxxxx_tokudb` ADD COLUMN `Test` varchar(255) AFTER `Html`
Affected rows : 0, Time: 2.69sec

# 删除已存在的字段
mysql> ALTER TABLE `test`.`xxxxx_tokudb` DROP COLUMN `xxxxxEmail`;
Affected rows : 0, Time: 2.03sec
mysql> ALTER TABLE `test`.`yyyyy_tokudb` ADD COLUMN `Test` text AFTER `Updated`;
Query OK, 0 rows affected (2.74 sec)

mysql> ALTER TABLE `test`.`yyyyy_tokudb` DROP COLUMN `Test`;    
Query OK, 0 rows affected (1.53 sec)

mysql> ALTER TABLE `test`.`yyyyy_tokudb` DROP COLUMN `Boss`;
Query OK, 0 rows affected (1.54 sec)

注意:

  • 扩展字段长度,只支持char, varchar, varbinary, integer 类型,并且不能是主键与二级索引键。
  • 增加、删除、扩建字段长度,更改列名,都需要独立的单语句操作。否则会引起阻塞。(一次只进行一个操作)
  • 避免再添加、删除索引期间进行增、删、扩、更操作
  • 避免删除一个在索引中的列,这种情况需要先删除索引,再删除字段
  • 更改列名不支持以下类型:TIME, ENUM, BLOB, TINYBLOB, MEDIUMBLOB, LONGBLOB

查询测试

针对某某数据 4100W+,对MyISAM与TokuDB两种引擎,进行SELECT * FROM全表扫描,游标读取并获取数据

SELECT * FROM yyyyy_myisam
2016-05-30 10:15:11,538 INFO [main] (EnterpriseTokuDB.java:103) - Memory:max/total/free 25612/25612/24589
2016-05-30 10:22:10,629 INFO [main] (EnterpriseTokuDB.java:105) - loop 41000000 : 4329 ms

SELECT * FROM yyyyy_tokudb
2016-05-30 10:23:12,410 INFO [main] (EnterpriseTokuDB.java:103) - Memory:max/total/free 25612/25612/24589
2016-05-30 10:30:07,614 INFO [main] (EnterpriseTokuDB.java:105) - loop 41000000 : 4359 ms

两者均耗时共 7分 左右

TokuDB获取数据时候需要解压缩,所以响应时间增多,但由于数据只有MyISAM的1/3,降低了IO。整体读响应时间相差无几。

更新测试

按行读取 TokuDB 表,边读边update,update使用JDBC的addBatch与executeBatch

平均10W条更新,50秒左右。

SELECT `id`,`key` FROM yyyyy_tokudb
 UPDATE yyyyy_tokudb SET IndustryCode=?, RegisterNum=? WHERE id = ?
2016-05-30 14:51:52,542 INFO [main] (EnterpriseTokuDB.java:175) - Memory:max/total/free 24696/24696/24180
2016-05-30 14:51:52,543 INFO [main] (EnterpriseTokuDB.java:177) - loop 100000 : 59669 ms
2016-05-30 14:52:47,135 INFO [main] (EnterpriseTokuDB.java:175) - Memory:max/total/free 24696/24696/23794
2016-05-30 14:52:47,135 INFO [main] (EnterpriseTokuDB.java:177) - loop 200000 : 54592 ms
2016-05-30 14:53:37,694 INFO [main] (EnterpriseTokuDB.java:175) - Memory:max/total/free 24696/24696/23407
2016-05-30 14:53:37,694 INFO [main] (EnterpriseTokuDB.java:177) - loop 300000 : 50558 ms

按行读取 MyISAM 表,不好意思经常无法测试,服务器出现了: Waiting for table level lock
一直阻塞住。 在未阻塞的情况下还是挺快的,10W条20秒左右,没有更深入的研究了。

导入导出

尽量使用 LOAD DATA,比mysqldump要快,并且可以用 show processlist 看到进度

使用问题

  1. SELECT COUNT(*) 和 InnoDB 相同,需要全表扫描。
  2. AUTO_INCREMENT 不能通过 ALT 语句回退,比如你插入了10000 ID,AUTO_INCREMENT变为10001,这时候你删除ID=10000 记录,想将AUTO_INCRMENT 重设为10001,这不支持

参考文档

TokuDB简介:http://mysql.taobao.org/monthly/2015/04/02/

TokuDB数据文件大小计算:http://mysql.taobao.org/monthly/2015/06/10/

TokuDB索引结构--Fractal Tree:http://mysql.taobao.org/monthly/2016/04/09/

TokuDB 使用简单说明:http://highdb.com/tokudb-%E7%89%B9%E6%80%A7%E6%A6%82%E8%A7%88/

mysql从innodb到tokudb引擎时遇到的问题:http://xiaorui.cc/2016/02/02/mysql%E4%BB%8Einnodb%E5%88%B0tokudb%E5%BC%95%E6%93%8E%E6%97%B6%E9%81%87%E5%88%B0%E7%9A%84%E9%97%AE%E9%A2%98/

TokuDB的索引结构–分形树的实现:http://www.bitstech.net/?s=tokudb