本文是转自@hoterran同学的一篇博文http://www.hoterran.info/mydumper_usage,对Mydumper稳定版v0.23源码做了一次分析,以及一些常用的使用命令,很有含金量的一篇博文,继续往下看吧。
编译安装
cmake . make sudo make install
源码分析
conf.queue = g_async_queue_new(); conf.ready = g_async_queue_new(); conf.unlock_tables= g_async_queue_new();产生指定的线程个数,–threads可以指定,默认是4个。
GThread **threads = g_new(GThread*,num_threads);
struct thread_data *td= g_new(struct thread_data, num_threads);
for (n=0; n<num_threads; n++) {
td[n].conf= &conf;
td[n].thread_id= n+1;
threads[n] = g_thread_create((GThreadFunc)process_queue,&td[n],TRUE,NULL);
g_async_queue_pop(conf.ready);
}
query= g_strdup_printf(“SELECT TABLE_NAME, ENGINE, TABLE_TYPE as COMMENT FROM DATA_DICTIONARY.TABLES WHERE TABLE_SCHEMA=’%s’”, database);
….
innodb_tables= g_list_append(innodb_tables, dbt);
….
non_innodb_table= g_list_append(non_innodb_table, dbt);
….
table_schemas= g_list_append(table_schemas, dbt);
for (non_innodb_table= g_list_first(non_innodb_table); non_innodb_table; non_innodb_table= g_list_next(non_innodb_table)) {
dbt= (struct db_table*) non_innodb_table->data;
dump_table(conn, dbt->database, dbt->table, &conf, FALSE);
g_atomic_int_inc(&non_innodb_table_counter);
}
for (innodb_tables= g_list_first(innodb_tables); innodb_tables; innodb_tables= g_list_next(innodb_tables)) {
dbt= (struct db_table*) innodb_tables->data;
dump_table(conn, dbt->database, dbt->table, &conf, TRUE);
}
for (table_schemas= g_list_first(table_schemas); table_schemas; table_schemas= g_list_next(table_schemas)) {
dbt= (struct db_table*) table_schemas->data;
dump_schema(dbt->database, dbt->table, &conf);
g_free(dbt->table);
g_free(dbt->database);
g_free(dbt);
}
for(;;) {
….
job=(struct job *)g_async_queue_pop(conf->queue);
….
switch (job->type) {
case JOB_DUMP:
….
dump_table_data_file(thrconn, tj->database, tj->table, tj->where, tj->filename);
….
case JOB_DUMP_NON_INNODB:
….
dump_table_data_file(thrconn, tj->database, tj->table, tj->where, tj->filename);
case JOB_SCHEMA:
….
dump_schema_data(thrconn, sj->database, sj->table, sj->filename);
}
case JOB_SHUTDOWN:
g_message(“Thread %d shutting down”, td->thread_id);
if (thrconn)
mysql_close(thrconn);
g_free(job);
mysql_thread_end();
return NULL;
break;
使用
mydumper -h 127.0.0.1 -u root –database test
mydumper -h 127.0.0.1 -u root –outputdir=.
mydumper -h 127.0.0.1 -u root –no-schema
mydumper -h 127.0.0.1 -u root –build-empty-files
mydumper -h 127.0.0.1 -u root –long-query-guard 200 –kill-long-queries
mydumper -h 127.0.0.1 -u root –tables-list=ddd,zzz
mydumper -h 127.0.0.1 -u root –regex=test.z
mydumper -h 127.0.0.1 -u root –rows 10000
mydumper -h 127.0.0.1 -u root -B test –ignore-engines=innodb
mydumper -h 127.0.0.1 -u root -B test -v 3
几个注意点
因为对myisam表有有表锁,所有先处理myisam表,记录myisam表个数,每处理一个myisam都原子操作数量减一。并在myisam表都处理完毕后,立即解锁,尽量减少锁定的时间,而不是在导出innodb表数据的时候还在lock myisam表。
for (non_innodb_table= g_list_first(non_innodb_table); non_innodb_table; non_innodb_table= g_list_next(non_innodb_table)) {
dbt= (struct db_table*) non_innodb_table->data;
dump_table(conn, dbt->database, dbt->table, &conf, FALSE);
g_atomic_int_inc(&non_innodb_table_counter);
}
if (g_atomic_int_dec_and_test(&non_innodb_table_counter) && g_atomic_int_get(&non_innodb_done)) {
g_async_queue_push(conf->unlock_tables, GINT_TO_POINTER(1));
}
g_async_queue_pop(conf.unlock_tables);
g_message(“Non-InnoDB dump complete, unlocking tables”);
mysql_query(conn, “UNLOCK TABLES”);
mydumper -h 127.0.0.1 -u root –regex=test.z1 –outputdir=. –rows=10000 -v 3 -e –tables-list=z2,z1
** Message: Thread 1 dumping data for `test`.`z1`
** Message: Thread 2 dumping schema for `test`.`z1`
首先mydumper会选择一个索引,顺序是pk、uk或者show index from table里Cardinality最高的一个索引,再通过explain select index from table的rows字段获得总行数total_nums(可能不准确),于是第一个文件就是从select * from table where index >=1 and index < total_nums/ (int(total_nums/ rows) – 1) + 1。每个分块可以分到不同的线程,所以即便同一个表dump都可以很快加速。
Mydumper: 高性能多线程MySQL备份恢复工具
Mydumper的主要特性
- 轻量级C语言写的代码
- 比mysqldump接近快10倍的速度
- 事务性和非事务性表一致的快照(适用于0.22+)
- 快速的文件压缩(官网用on-the-fly来形容)
- 可以导出binlog
- 实用的多线程恢复
- 可以用守护进程的工作方式,定时的扫描和输出连续的二进制日志
- 当然还有个就是开源咯~
wget http://launchpad.net/mydumper/0.5/0.5.0/+download/mydumper-0.5.0.tar.gz
tar zxvf mydumper-0.5.0.tar.gz
cmake .
make
make install
mydumper -u root -p ” -P 3307 -S /tmp/mysql.3307.sock -B zs -T movie_databases -o /home/zhangsheng/dumper
zs.movie_databases-schema.sql #schema语句
zs.movie_databases.sql #insert的数据语句,如果指定–rows的话,会将数据分成指定的份数
myloader -u root -p ” -P 3307 -S /tmp/mysql.3307.sock -d /home/zhangsheng -B zs
MySQL 日志文件
1.error log
启动mysqld –log-error=指定,或者cnf配置文件mysqld节点中用log-error指定,默认没指定是自己的hostname.err文件,如下:
2.bin log
下次总结replication是再聊.
3.update log
启动mysqld 指定–log-update=指定
mysql5.0以前版本update log和bin log功能类似,只不过不是用二进制文件记录而是用文本格式记录,mysql5.0以上的版本不支持更新日志。
4.query log
启动mysqld 指定–log=指定
包括了所有query日志,体积比较大,除非需要定位和跟踪特殊query的时候可以短暂打开使用,其他情况慎用。
5.slow query log
纪录所有查询时间超过long_query_time或不使用索引的查询动作。你可以在mysqld的的数据目录中找到所有的纪录档。
slow_query_log = 1
slow_query_log_file = slow_log_location
慢查询日志文件如果较大的话,用mysqldumpslow工具来分析日志文件,可参考实例:http://my.chinaunix.net/space.php?uid=9950859&do=blog&id=122259
6.innodb redo log
innodb是一个事务安全存储引擎,redo log通过记录redo,undo信息,来确保在任何情况下事务的安全性。详细配置在后续总结innodb时再聊.
自己写脚本快速连接mysql和mysqladmin
user = root
password = password
socket = /tmp/mysql.3308.sock
port = 3308
user = root
password = password
socket = /tmp/mysql.3308.sock
port = 3308
/usr/local/mysql/bin/mysql –defaults-file=/data/mysql/cnf/my.3308.cnf
/usr/local/mysql/bin/mysqladmin –defaults-file=/data/mysql/cnf/my.3308.cnf processlist
/usr/local/mysql/bin/mysqladmin –defaults-extra-file=/data/config/my.3308.txt processlist #自定义配置文件,格式和上述一致即可
比如目录:/home/yourdir
/usr/local/mysql/bin/mysql –defaults-file=/data/mysql/cnf/my.$1.cnf
===================
#!/bin/bash
/usr/local/mysql/bin/mysqladmin –defaults-file=/data/mysql/cnf/my.$1.cnf $2
写到这里,类似mysql、mysqladmin的mysql自带工具都可以做成这样的快速连接方式。Have fun~
同一服务器运行多个mysql
这种方式需要注意的是确保不同的安装目录,不同的端口号,不同的Unix套接字文件(.sock文件),如编译时可以这样指定:
./configure –with-tcp-port=3307 \
–with-unix-socket-path=/tmp/mysql.3307.sock\
–prefix=/usr/local/mysql
./bin/mysql_install_db –user=mysql \
–basedir=/usr/local/mysql \
–datadir=/data/mysql/data/3307
./mysqld_safe –defaults-file=/data/mysql/cnf/mysql.3307.cnf &
[mysqld]
user = mysql
port = 3307
socket = /tmp/mysql.3307.sock
basedir = /usr/local/mysql
datadir = /data/mysql/data/3307
log-error = /data/mysql/logs/3307/mysql_error.log
pid-file = /data/mysql/logs/3307/mysql.pid
不过是在一个配置文件完成,如果不同的服务需要不同的配置,最好把不同mysql服务的配置文件单独出来,特别是有些服务正在运行的情况下,容易影响,像第二种方式中单独配置文件一样.
[mysqld_multi]
mysqld = /usr/local/mysql/bin/mysqld_safe
mysqladmin = /usr/local/mysql/bin/mysqladmin
user = root
password = password
log = /data/mysql/logs/mysqld_multi.log
defaults-file = /data/mysql/cnf/my.3306.cnf
defaults-file = /data/mysql/cnf/my.3307.cnf
./mysqld_multi –defaults-extra-file=/data/mysql/cnf/my.cnf start
那到底为什么会这样呢? ./mysqld_multi –example里面也是推荐将各个[mysqldN]列举出来,为什么读配置文件加载方式只能启动,不能停止,难道mysqld_multi是调用mysqld_safe和mysqladmin命令的方式不一样造成的?另外命令行传递参数defaults-extra-file或者defaults-file时,必须放在最前面,难道是受这个这个地方的影响?有点不解?
运行mysqld_multi遇到提示错误: WARNING! my_print_defaults command not found!
解决办法:#export PATH=$PATH:/usr/local/mysql/bin