微信号:InsideMySQL

介绍:MySQL数据库发烧友群;《MySQL技术内幕》系列书籍官方帐号;不谈小道消息,只关注MySQL相关技术

最快创建一个MySQL从机的姿势

2017-01-09 23:37 欧阳锋 姜承尧

1. 一个运维小故事

小明是公司的菜鸟MySQL DBA,凌晨接到报警说一台MySQL从机发生故障,检查后发现是CPU坏了,机器再也起不来了。这个库是生产上面很重要的订单库,如果此时主库再挂,后果不堪设想。

小明很着急,既想早点解决故障,又想早点搞完去睡觉。这时恰好发现还有一台机器可以用来暂时顶替这台机器。小明已经知道关于开源备份工具percona-xtrabackup的基本操作,于是小明做了如下一系列操作:

(1)在主库上面运行innobackupex命令,将MySQL备份到bak目录

innobackupex --user=backup \ 
--password=backup \
--socket=/tmp/mysql.sock \
--no-timestamp bak

(2)把备份好的bak目录scp拷贝到另外一台机器的/dbdata/bak目录

scp -rp bak another_server:/dbdata/bak

(3)去备机上把备份的目录prepare好

innobackupex --apply-log bak

(4)把prepare好的备份目录拷贝回数据目录

innobackupex --copy-back bak

(5)修改数据目录权限,启动MySQL

chown -R mysql:mysql /dbdata/mysql
service mysql start

(6)change master追主库

mysql> change master to ...
mysql> start slave;
mysql> show slave status\G

(7)报告领导恢复工作已完成

(8)终于可以睡觉了...

因为数据目录有500G,小明每做一步都等啊等,整个过程花了3个小时,小明等的很不耐烦,但是也没办法,以为只能这么一步一步操作,好在恢复任务也算完成了。

2. 思考和测试准备

小明傻傻地在电脑前等了3个小时,相信很多人对MySQL做备份还原时也是这么干的。有必要吗?怎么做才能在最短时间内备份MySQL并还原出一台从机呢?可以做哪些优化呢?

这里我找来了2台测试的云主机用来做测试,配置如下:

先用sysbench往4张表里面分别写入500W数据,共4.8G:

sysbench --test=sysbench-0.5/sysbench/tests/db/oltp.lua \
--mysql-user=sysbench \
--mysql-password=sysbench \
--num-threads=4 \
--oltp-tables-count=4 \
--oltp-table-size=5000000 \
--report-interval=3 \
--max-time=1000 \
--max-requests=0 prepare

出于准确考虑,以下每次测试前都执行如下操作:

(1) 清理MySQL日志,腾出一些磁盘空间(云主机磁盘太小了);

mysql> reset master;

(2) 干净的关闭MySQL;

service mysql stop

(3) 删除MySQL数据目录下的ib_buffer_pool文件,以防止MySQL重启时warm up;

rm ib_buffer_pool

(4) 清理操作系统缓存;

echo 3 > /proc/sys/vm/drop_caches

(5) 启动MySQL(MySQL配置在my.cnf中的[mysqld1]下面)

service mysql start

每次测试过程中,为了保证MySQL有压力,这里用sysbench开4个线程执行oltp操作;

sysbench --test=sysbench-0.5/sysbench/tests/db/oltp.lua \
--mysql-user=sysbench \
--mysql-password=sysbench \
--num-threads=4 \
--oltp-tables-count=4 \
--oltp-table-size=5000000 \
--report-interval=3 \
--max-time=1000 \
--max-requests=0 run

3. 测试

(1)最原始的方法

整个过程如下:

备份到本地-->scp到远程-->prepare-->copyback(可省略)-->启动追复制

备份命令如下:

innobackupex --user=backup \
--password=backup \
--socket=/tmp/mysql.sock \
--no-timestamp bak

所花时间(s):


注:

  • 这里追上复制的时间为0表示主库这段时间写的数据还不多,因为备份花的时间不长,从库几乎瞬间就追上了。

  • xtrabackup备份完之后不需要copy-back,直接把还原后 的目录mv成数据目录,然后直接启动MySQL即可,mv操作是瞬间的,否则还得多花约20秒时间。

(2)能不能并行备份?

答案是肯定的。大家都知道数据库并发的比串行的性能要好很多,备份也是这样。xtrabackup自带参数 --parallel=N,指定拷贝InnoDB文件的并行线程数。

整个过程如下:

并行备份到本地-->scp到远程-->prepare-->启动追复制

备份命令如下:

innobackupex --user=backup \
--password=backup \
--socket=/tmp/mysql.sock \
--parallel=4 \
--no-timestamp bak

所花时间(s):


好了,我们使用并发已经把备份的这个过程所花的时间减少了一半还多,效果非常明显。

注:从这里往后的测试都把copyback换成了mv。

(3)能不能压缩备份,然后再拷贝到远程?因为网络传输速度有限,如果在本地压缩完再传输到远程应该会快。

可以。xtrabackup自带参数--compress和--compress-threads=N,分别开启压缩以及指定压缩的线程数。值得注意的是,指定--compress后,xtrabackup把.ibd、.frm等文件分别压缩成.ibd.qp、.frm.qp文件,解压时需要用qpress这个解压工具去解压,这个工具不在xtrabackup安装包里面(说真的,用起来好麻烦....)。

不过,这里有一点非常需要注意,就是数据本身的重复性对压缩的性能影响很大。在真实的生产环境中,MySQL的数据是有很多重复的,基本上用普通等级的gzip压缩都能压缩到20%左右,由于sysbench生成的数据随机性非常大,数据重复率很低,所以这里手工做了update,把MySQL里面的数据搞成有比较大的重复,测试发现gzip能压缩到15%左右

整个过程如下:

并行备份并压缩-->scp到远程-->把压缩文件用qpress解压-->prepare-->启动追复制

备份命令如下:

innobackupex --user=backup \
--password=backup \
--socket=/tmp/mysql.sock \
--parallel=4 \
--compress \
--compress-threads=4 \
--no-timestamp bak

并行解压命令如下(有点复杂,有没有?):

find /dbdata/mysql -name *.qp \
| xargs -I? -n 1 -P 4 sh -c 'qpress -fd ? `dirname ?`'

所花时间(s):


压缩总算没让我们失望,虽然备份的时间增加了些,但是由于数据的压缩比比较高,网络传输的时间少了很多。

(4)吐槽下,percona这个压缩太难用了,qpress想并行解压好麻烦,有没有更好的压缩及解压方法呢?

答案肯定是有的。安装lz4这个压缩工具,这个工具号称压缩能达到300M+/s,解压能达到1G/s。配合xtrabackup自带的--stream=[tar|xbstream]参数,该参数可以把备份的数据输出到标准输出,而lz4支持标准输出,这样也可以实现和测试(3)一样的效果。由于lz4的压缩性能比诸如gzip、bzip2之流快太多,这里就不对比了,留给读者做gzip和bzip2的测试,会发现慢太多。

整个过程如下:

并行备份同时lz4压缩-->scp到远程-->把压缩文件用lz4解压-->prepare-->启动追复制

备份命令如下:

innobackupex --user=backup \
--password=backup \
--socket=/tmp/mysql.sock \
--parallel=4 \
--no-timestamp \
--stream=xbstream . | lz4 -B4 > bak

解压命令如下:

mkdir /dbdata/mysqlcat bak | lz4 -d B7 | xbstream -x -C /dbdata/mysql

所花时间(s):


(5)直接备份到远程服务器

既然lz4支持管道操作,那么能不能直接压缩并备份到远程呢?当然可以。

这样整个的操作过程如下:

并行备份同时lz4压缩并直接传输到远程-->把压缩文件用lz4解压-->prepare-->启动追复制

备份命令如下:

innobackupex --user=backup \
--password=backup \
--parallel=4 \
--socket=/tmp/mysql.sock \
--no-timestamp \
--stream=xbstream . |\
lz4 -B4 |\ ssh server2 \ "cat - > /dbdata/bak"

还原命令如下:

mkdir /dbdata/mysql
cat /dbdata/bak | lz4 -d -B7 | xbstream -x -C /dbdata/mysql

所花时间(s):


(6)直接备份到远程服务器同时还原

innobackupex --user=backup \
--password=backup \
--parallel=4 \
--socket=/tmp/mysql.sock \
--no-timestamp \
--stream=xbstream . |\
lz4 -B4 |\ ssh server2 \ "cat - | lz4 -d -B7 | xbstream -x -C /dbdata/mysql"

这里所有的备份、压缩和传输到远程以及解压缩都在几个管道连起来,可以理解为这些操作都是在并行执行。

所花时间(s):


这里可以看到在一系列管道中并行这些操作在速度上有很大的提高。

4 结论

最后总结以下上述方案,描述和总时间如下表:


对比上述备份方案,方案1、2、4、5都不够直接了当。用xtrabackup自带压缩备份的方式(方案3)和用管道直接备份、压缩并直接还原的方式(方案6)速度几乎相当,都比最初的备份还原总时间减少了约三分之二,我个人比较喜欢方案6,主要有以下3个原因:

  • 方案6不占用远程更多的空间,而方案4在远程服务器解压完成后才能删除压缩文件;

  • 方案6充分利用了Linux的管道操作,如果备份没有写成自动化脚本,那么方案6要少敲好几次命令;

  • 如果把备份文件备份到远程的存储,那么在还原时,方案6也能利用管道操作做到直接解压并还原到本地,而方案4只能从远程把压缩文件拷贝到本地后再去解压;

注:以上的实际备份以及还原时间和服务器网络、磁盘以及数据库中的数据本身关系较大,如果要在上面测试,请大家先做好测试。

5 还能更快吗?

还能更快吗?

其实还是有一些细节方面可以优化的,这个问题留给聪明的你来思考。


猜你喜欢



 
InsideMySQL 更多文章 MySQL运维之神奇的参数 网易蜂巢云数据库新版本发布,除了DB,我们还有诗与远方 一触即发,2017年,数据库世界的诸神之战 MySQL Group Replication性能测试,星辰大海还是前路茫茫? 年薪50万?那你得先知道每天凌晨三点的样子
猜您喜欢 微信APP支付Android Demo详解 安卓易学,爬坑不易——腾讯老司机的RecyclerView局部刷新爬坑之路 写作的本源 ARM开发比51开发高级吗—嵌入式就业技能分类 使用Electron创建跨平台桌面应用