背景:
TokuDB引擎是有Tokutek开发的一个数据库存储引擎,在设计之初便引入了独特的索引算法,在其官网测试的文章中看到TokuDB性能比InnoDB高出很多。
MySQL是一个插件式的数据库,在MySQL5.5版本之前MyISAM是MySQL的默认存储引擎,在之后的版本中默认的存储引擎变成了InnoDB。其特点是它支持事务,具有完善的崩溃恢复机制,具体的特点这里不说明,可以自行的寻找资料。这里介绍的TokuDB和InnoDB有很多相似之处:一个高性能,支持事务、MVCC、聚簇索引等。最大的不同在于TokuDB采用了一种叫做Fractal Tree的索引结构,使其在随机写数据的处理上有很大提升。一般来说数据库的索引结构都采用B+Tree或则类似的数据结构,InnoDB也是如此。InnoDB是以主键组织的B+Tree结构,数据按照主键顺序排列。对于顺序的自增主键有很好的性能,但是不适合随机写入,大量的随机I/O会使数据页分裂产生碎片,索引维护开销很多大。而TokuDB的Fractal Tree的索引结构很好的解决了这个问题。
TokuDB解决随机写入的问题得益于其索引结构,Fractal Tree 和 B-Tree的差别主要在于索引树的内部节点上,B-Tree索引的内部结构只有指向父节点和子节点的指针,而Fractal Tree的内部节点不仅有指向父节点和子节点的指针,还有一块Buffer区。当数据写入时会先落到这个Buffer区上,该区是一个FIFO结构,写是一个顺序的过程,和其他缓冲区一样,满了就一次性刷写数据。所以TokuDB上插入数据基本上变成了一个顺序添加的过程。
TokuDB另一个特点是压缩性能和低CPU消耗,TokuDB存储引擎默认的块大小是4M,这使其有更好的压缩效率。默认支持压缩功能,不需要配置其他的东西。压缩选项有:TokuDB_Quicklz、TokuDB_Lzma、TokuDB_Zlib,同时也支持非压缩选项。TokuDB_Zlib支持的默认压缩格式。一般压缩都需要消耗更多的CPU。但TukuDB消耗的CPU资源较少。
TokuDB:https://www.percona.com/doc/percona-server/5.7/index.html
安装
为了方便安装,直接在percona版本的MySQL上安装TokuDB存储引擎。Ubuntu下apt安装percona MySQL:http://www.percona.com/doc/percona-server/5.6/installation/apt_repo.html
vi /etc/apt/sources.list.d/percona.list
deb http://repo.percona.com/apt trusty main
其他:添加其他软件的更新,和本次安装无关
vi /etc/apt/sources.list
deb http://mirrors.aliyun.com/ubuntu trusty main restricted universe multiverse deb http://mirrors.aliyun.com/ubuntu trusty-updates main restricted universe multiverse deb http://security.ubuntu.com/ubuntu trusty-security main restricted universe multiverse
源添加完毕之后更新:
apt-get update
最后apt安装percona MySQL:
apt-get install percona-server-server-5.6 percona-server-client-5.6
以上percona MySQL安装完毕,接着就开始安装TokuDB。
参考官网的安装说明:https://www.percona.com/doc/percona-server/5.6/tokudb/tokudb_installation.html
安装TokuDB的前提条件是需要支持jemalloc,需要关闭 Transparent huge pages ,执行:
echo never > /sys/kernel/mm/transparent_hugepage/enabled echo never > /sys/kernel/mm/transparent_hugepage/defrag
效果:
root@ptest:~# cat /sys/kernel/mm/transparent_hugepage/enabled always madvise [never] root@ptest:~# cat /sys/kernel/mm/transparent_hugepage/defrag always madvise [never]
开始apt安装TokuDB:
root@ptest:~# apt-get install percona-server-tokudb-5.6
安装好检查:
root@ptest:~# ps_tokudb_admin --enable -uroot -p Enter password: Continuing without password... Checking if Percona server is running with jemalloc enabled... grep: /proc/5440/environ: Permission denied >> Percona server is running with jemalloc enabled. Checking transparent huge pages status on the system... >> Transparent huge pages are currently disabled on the system. Checking if thp-setting=never option is already set in config file... >> Option thp-setting=never is not set in the config file. >> (needed only if THP is not disabled permanently on the system) Checking TokuDB plugin status... >> TokuDB plugin is installed. Adding thp-setting=never option into /etc/mysql/my.cnf >> Successfuly added thp-setting=never option into /etc/mysql/my.cnf #把参数thp-setting=never加载到了my.cnf的[mysqld_safe]的选项组下
通过show engines、show plugins 查看存储引擎,是否安装成功,要是没有成功则检查上面是否有错误。要是通过show engines没有TokuDB,但通过show plugins有则需要手动install:
INSTALL PLUGIN tokudb SONAME 'ha_tokudb.so'; INSTALL PLUGIN tokudb_file_map SONAME 'ha_tokudb.so'; INSTALL PLUGIN tokudb_fractal_tree_info SONAME 'ha_tokudb.so'; INSTALL PLUGIN tokudb_fractal_tree_block_map SONAME 'ha_tokudb.so'; INSTALL PLUGIN tokudb_trx SONAME 'ha_tokudb.so'; INSTALL PLUGIN tokudb_locks SONAME 'ha_tokudb.so'; INSTALL PLUGIN tokudb_lock_waits SONAME 'ha_tokudb.so';
查看版本:
>SELECT @@tokudb_version; +------------------+ | @@tokudb_version | +------------------+ | tokudb-7.5.6 | +------------------+
以上就完成了TokuDB的安装。详细信息请见官网。
测试:针对插入、压缩、存储引擎转换、事务、复制等日常用到的功能进行测试。
1)插入和压缩性能:压缩参数:tokudb_row_format
zjy@127.0.0.1 : test 10:58:58>show create table login_log_Toku\G; *************************** 1. row *************************** Table: login_log_Toku Create Table: CREATE TABLE `login_log_Toku` ( `userID` varchar(255) NOT NULL, `tryIP` varchar(255) DEFAULT NULL, `tryTime` datetime DEFAULT NULL, `tryResult` tinyint(1) DEFAULT '0', `refferUrl` varchar(255) DEFAULT NULL, `sID` int(10) unsigned NOT NULL AUTO_INCREMENT, `authType` tinyint(1) DEFAULT '1', `type` tinyint(1) DEFAULT '1', `deviceType` varchar(64) DEFAULT '', PRIMARY KEY (`sID`), KEY `idx_tryip` (`tryIP`), KEY `idx_userid` (`userID`), KEY `idx_tryTime` (`tryTime`) ) ENGINE=TokuDB DEFAULT CHARSET=utf8 1 row in set (0.01 sec) ERROR: No query specified zjy@127.0.0.1 : test 10:59:45>insert into login_log_Toku select * from login_log; Query OK, 49534274 rows affected (18 min 35.63 sec) Records: 49534274 Duplicates: 0 Warnings: 0 zjy@127.0.0.1 : test 11:18:40>create table login_log_innodb like login_log; Query OK, 0 rows affected (0.11 sec) zjy@127.0.0.1 : test 11:27:58>insert into login_log_innodb select * from login_log; Query OK, 49534274 rows affected (2 hours 1 min 34.06 sec) Records: 49534274 Duplicates: 0 Warnings: 0 zjy@127.0.0.1 : test 01:29:38>create table login_log_myisam like login_log; Query OK, 0 rows affected (0.15 sec) zjy@127.0.0.1 : test 08:56:30>alter table login_log_myisam engine = myisam; Query OK, 0 rows affected (0.10 sec) Records: 0 Duplicates: 0 Warnings: 0 zjy@127.0.0.1 : test 08:56:51>insert into login_log_myisam select * from login_log; Query OK, 49534274 rows affected (14 min 25.44 sec) Records: 49534274 Duplicates: 0 Warnings: 0
上面看到写入TokuDB表的时间远远小于InnoDB,MyISAM(堆表)的写入也比InnoDB好很多。
-rw-rw---- 1 mysql mysql 8.7K 5月 7 23:27 login_log_innodb.frm -rw-rw---- 1 mysql mysql 9.7G 5月 8 03:12 login_log_innodb.ibd -rw-rw---- 1 mysql mysql 8.7K 5月 8 08:56 login_log_myisam.frm -rw-rw---- 1 mysql mysql 3.8G 5月 8 09:00 login_log_myisam.MYD -rw-rw---- 1 mysql mysql 1.7G 5月 8 09:11 login_log_myisam.MYI -rw-rw---- 1 mysql mysql 8.7K 5月 8 16:43 login_log_Toku.frm
查看文件,看到InnoDB所占的空间比MyISAM大,9.7>5.5。TokuDB在数据库目录下面只保存.frm表结构定义文件,其数据保存在数据库的目录的上一层(可以通过tokudb_data_dir,tokudb_log_dir指定位置):
ls -lh *toku* -rw------- 1 mysql mysql 12K 5月 12 17:00 log000000000005.tokulog27 -rw-rw---- 1 mysql mysql 64K 5月 8 16:43 _test_sql_c80_2a_status_34_1_1b.tokudb -rw-rw---- 1 mysql mysql 265M 5月 8 16:43 _test_login_log_Toku_key_idx_tryip_3c_1_1b_B_1.tokudb -rw-rw---- 1 mysql mysql 229M 5月 8 16:43 _test_login_log_Toku_key_idx_tryTime_3c_1_1b_B_3.tokudb -rw-rw---- 1 mysql mysql 282M 5月 8 16:43 _test_login_log_Toku_key_idx_userid_3c_1_1b_B_2.tokudb -rw-rw---- 1 mysql mysql 1.4G 5月 8 18:25 _test_login_log_Toku_main_3c_1_1b_B_0.tokudb -rw-rw---- 1 mysql mysql 17K 5月 7 17:10 _test_ttt_main_5_1_1b_B_0.tokudb -rw-rw---- 1 mysql mysql 16K 5月 7 17:10 _test_ttt_status_3_1_1b.tokudb -rw-rw---- 1 mysql mysql 32K 5月 8 16:43 tokudb.directory -rw-rw---- 1 mysql mysql 16K 5月 7 17:09 tokudb.environment -rw------- 1 mysql mysql 0 5月 7 17:09 __tokudb_lock_dont_delete_me_data -rw------- 1 mysql mysql 0 5月 7 17:09 __tokudb_lock_dont_delete_me_environment -rw------- 1 mysql mysql 0 5月 7 17:09 __tokudb_lock_dont_delete_me_logs -rw------- 1 mysql mysql 0 5月 7 17:09 __tokudb_lock_dont_delete_me_recovery -rw------- 1 mysql mysql 0 5月 7 17:09 __tokudb_lock_dont_delete_me_temp -rw-rw---- 1 mysql mysql 32K 5月 8 16:43 tokudb.rollback
从上面看出,TokuDB的索引文件和数据文件是分开的,一个索引一个文件。总共大小为2.2G,最小。其他为TokuDB的日志文件和一些元数据。
2)存储引擎转换和事务支持:
1:存储引擎转换
zjy@127.0.0.1 : test 06:08:48>show create table log\G; *************************** 1. row *************************** Table: log Create Table: CREATE TABLE `log` ( `userID` varchar(255) NOT NULL, `tryIP` varchar(255) DEFAULT NULL, `tryTime` datetime DEFAULT NULL, `tryResult` tinyint(1) DEFAULT '0', `refferUrl` varchar(255) DEFAULT NULL, `sID` int(10) unsigned NOT NULL DEFAULT '0', `authType` tinyint(1) DEFAULT '1', `type` tinyint(1) DEFAULT '1', `deviceType` varchar(64) DEFAULT '', KEY `idx_userid` (`userID`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 1 row in set (0.01 sec) ERROR: No query specified zjy@127.0.0.1 : test 06:08:50>alter table log engine = tokudb; Query OK, 100 rows affected (0.02 sec) Records: 100 Duplicates: 0 Warnings: 0 zjy@127.0.0.1 : test 06:08:56>select * from log; 有数据,数据未丢失。 zjy@127.0.0.1 : test 06:09:34>show create table log\G; *************************** 1. row *************************** Table: log Create Table: CREATE TABLE `log` ( `userID` varchar(255) NOT NULL, `tryIP` varchar(255) DEFAULT NULL, `tryTime` datetime DEFAULT NULL, `tryResult` tinyint(1) DEFAULT '0', `refferUrl` varchar(255) DEFAULT NULL, `sID` int(10) unsigned NOT NULL DEFAULT '0', `authType` tinyint(1) DEFAULT '1', `type` tinyint(1) DEFAULT '1', `deviceType` varchar(64) DEFAULT '', KEY `idx_userid` (`userID`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 1 row in set (0.12 sec) ERROR: No query specified zjy@127.0.0.1 : test 06:09:37>alter table log engine = tokudb; Query OK, 100 rows affected (0.02 sec) Records: 100 Duplicates: 0 Warnings: 0 zjy@127.0.0.1 : test 06:15:24>select * from log; 有数据,数据未丢失。 反推把TokuDB转换成InnoDB和MyISAM也没有问题。
2:事务支持
zjy@127.0.0.1 : test 03:20:19>create table tmp_innodb(id int,name varchar(10))engine = innodb default charset utf8; Query OK, 0 rows affected (0.44 sec) zjy@127.0.0.1 : test 03:20:57>create table tmp_myisam(id int,name varchar(10))engine = myisam default charset utf8; Query OK, 0 rows affected (0.01 sec) zjy@127.0.0.1 : test 03:21:07>create table tmp_tokudb(id int,name varchar(10))engine = tokudb default charset utf8; Query OK, 0 rows affected (0.05 sec) zjy@127.0.0.1 : test 03:21:17>start transaction; Query OK, 0 rows affected (0.01 sec) zjy@127.0.0.1 : test 03:21:47>insert into tmp_innodb values(1,'a'),(2,'b'),(3,'c'); Query OK, 3 rows affected (0.11 sec) Records: 3 Duplicates: 0 Warnings: 0 zjy@127.0.0.1 : test 03:22:10>insert into tmp_myisam values(1,'a'),(2,'b'),(3,'c'); Query OK, 3 rows affected (0.01 sec) Records: 3 Duplicates: 0 Warnings: 0 zjy@127.0.0.1 : test 03:22:17>insert into tmp_tokudb values(1,'a'),(2,'b'),(3,'c'); Query OK, 3 rows affected (0.01 sec) Records: 3 Duplicates: 0 Warnings: 0 zjy@127.0.0.1 : test 03:22:22>commit; Query OK, 0 rows affected (0.02 sec) zjy@127.0.0.1 : test 03:22:26>select * from tmp_innodb; +------+------+ | id | name | +------+------+ | 1 | a | | 2 | b | | 3 | c | +------+------+ 3 rows in set (0.16 sec) zjy@127.0.0.1 : test 03:22:52>select * from tmp_myisam; +------+------+ | id | name | +------+------+ | 1 | a | | 2 | b | | 3 | c | +------+------+ 3 rows in set (0.01 sec) zjy@127.0.0.1 : test 03:22:56>select * from tmp_tokudb; #和innodb一样,数据提交写入 +------+------+ | id | name | +------+------+ | 1 | a | | 2 | b | | 3 | c | +------+------+ 3 rows in set (0.01 sec) zjy@127.0.0.1 : test 03:23:04>start transaction; Query OK, 0 rows affected (0.16 sec) zjy@127.0.0.1 : test 03:23:17>insert into tmp_innodb values(11,'aa'),(22,'bb'),(33,'cc'); Query OK, 3 rows affected (0.01 sec) Records: 3 Duplicates: 0 Warnings: 0 zjy@127.0.0.1 : test 03:23:39>insert into tmp_myisam values(11,'aa'),(22,'bb'),(33,'cc'); Query OK, 3 rows affected (0.12 sec) Records: 3 Duplicates: 0 Warnings: 0 zjy@127.0.0.1 : test 03:23:51>insert into tmp_tokudb values(11,'aa'),(22,'bb'),(33,'cc'); Query OK, 3 rows affected (0.00 sec) Records: 3 Duplicates: 0 Warnings: 0 zjy@127.0.0.1 : test 03:24:30>rollback; Query OK, 0 rows affected, 1 warning (0.01 sec) #myisam不支持事务引发的warning zjy@127.0.0.1 : test 03:24:40>select * from tmp_innodb; +------+------+ | id | name | +------+------+ | 1 | a | | 2 | b | | 3 | c | +------+------+ 3 rows in set (0.29 sec) zjy@127.0.0.1 : test 03:24:49>select * from tmp_myisam; +------+------+ | id | name | +------+------+ | 1 | a | | 2 | b | | 3 | c | | 11 | aa | | 22 | bb | | 33 | cc | +------+------+ 6 rows in set (0.18 sec) zjy@127.0.0.1 : test 03:24:55>select * from tmp_tokudb; #和innodb一样,数据被回滚。 +------+------+ | id | name | +------+------+ | 1 | a | | 2 | b | | 3 | c | +------+------+ 3 rows in set (0.00 sec)
3)复制相关
MySQL的复制是通过Master利用binlog IO线程把修改数据库的SQL推送到Slave上,Slave通过本地的binlog IO线程把SQL写入到中继日志里(relay log)里,再通过SQL线程回放这些SQL,应用到数据库。复制的核心在于binlog,而binlog和存储引擎是没有关系,所以从理论上说主从的存储引擎不一样也不影响复制。
MASTER:主上建表写入 rep@192.168.200.25 : test 08:55:58>create table tmp_engine(id int,name varchar(10))default charset utf8; Query OK, 0 rows affected (0.24 sec) rep@192.168.200.25 : test 08:56:57>insert into tmp_engine values(1,'a'),(2,'b'); Query OK, 2 rows affected (0.15 sec) Records: 2 Duplicates: 0 Warnings: 0 rep@192.168.200.25 : test 08:59:18>insert into tmp_engine values(11,'aa'),(22,'bb'); Query OK, 2 rows affected (0.37 sec) Records: 2 Duplicates: 0 Warnings: 0 rep@192.168.200.25 : test 08:59:25>select * from tmp_engine; +------+------+ | id | name | +------+------+ | 1 | a | | 2 | b | | 11 | aa | | 22 | bb | +------+------+ 4 rows in set (0.24 sec) SLAVE:从上同步数据,并修改存储引擎 zjy@127.0.0.1 : test 09:00:01>select * from tmp_engine; +------+------+ | id | name | +------+------+ | 1 | a | | 2 | b | | 11 | aa | | 22 | bb | +------+------+ 4 rows in set (0.19 sec) zjy@127.0.0.1 : test 09:00:04>alter table tmp_engine engine = tokudb; Query OK, 4 rows affected (0.02 sec) Records: 4 Duplicates: 0 Warnings: 0 MASTER:主上继续写入 rep@192.168.200.25 : test 09:00:24>insert into tmp_engine values(1111,'aaaa'),(2222,'bbbb'); Query OK, 2 rows affected (0.02 sec) Records: 2 Duplicates: 0 Warnings: 0 rep@192.168.200.25 : test 09:00:29>select * from tmp_engine; +------+------+ | id | name | +------+------+ | 1 | a | | 2 | b | | 11 | aa | | 22 | bb | | 111 | aaa | | 222 | bbb | | 1111 | aaaa | | 2222 | bbbb | +------+------+ 8 rows in set (0.05 sec) SLAVE:从上修改完存储引擎之后,数据继续正常同步。 zjy@127.0.0.1 : test 09:00:13>select * from tmp_engine; +------+------+ | id | name | +------+------+ | 1 | a | | 2 | b | | 11 | aa | | 22 | bb | | 111 | aaa | | 222 | bbb | | 1111 | aaaa | | 2222 | bbbb | +------+------+ 8 rows in set (0.23 sec)
从上面看出,主从复制和存储引擎无关,从上修改成和主上不同的存储引擎,正常同步。
4)备份相关
TokuDB 有自己的热备份方案:tokudb-hot-backup-part-1、tokudb-hot-backup-part-2,和其他存储引擎一样也可以使用mysqldump进行备份。
-- MySQL dump 10.13 Distrib 5.6.19, for osx10.7 (x86_64) -- -- Host: 192.168.200.240 Database: test -- ------------------------------------------------------ -- Server version 5.6.23-72.1 /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; /*!40101 SET NAMES utf8 */; /*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; /*!40103 SET TIME_ZONE='+00:00' */; /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; -- -- Table structure for table `tmp_engine` -- DROP TABLE IF EXISTS `tmp_engine`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `tmp_engine` ( `id` int(11) DEFAULT NULL, `name` varchar(10) DEFAULT NULL ) ENGINE=TokuDB DEFAULT CHARSET=utf8; /*!40101 SET character_set_client = @saved_cs_client */; -- -- Dumping data for table `tmp_engine`