2019-04-23 MySQL数据库备份与恢复基础实践(2)

1. 恢复数据库实践

1.1 数据库恢复基本事项

mysql命令以及source命令恢复数据库的原理就是在数据库里重新执行文件的SQL语句的过程。数据恢复和字符集的关联很大,如果字符集不正确则会导致恢复的数据乱码。

1.2 利用source命令恢复数据库

先备份一下:

[root@oldboy ~]# mysqldump -B --master-data=2 --single-transaction oldboy | gzip > /opt/oldboy.sql.gz
[root@oldboy ~]# ll /opt/oldboy.sql.gz 
-rw-r--r--. 1 root root 869 Feb  8 03:30 /opt/oldboy.sql.gz

恢复前解压为SQL文件:

[root@oldboy ~]# gzip -d /opt/oldboy.sql.gz 
gzip: /opt/oldboy.sql already exists; do you wish to overwrite (y or n)? y
---这里是因为之前有过同名的备份,如果不重要就覆盖,重要的话就另外找地方解压
[root@oldboy ~]# ll /opt/
total 212
-rw-r--r--. 1 root root   2204 Feb  8 03:30 oldboy.sql

登录数据库删除oldboy数据库,然后准备用source恢复:

mysql> drop database oldboy;
Query OK, 1 row affected (0.08 sec)
mysql> select * from oldboy.test;    ---查询数据是否还有
ERROR 1146 (42S02): Table 'oldboy.test' doesn't exist
mysql> source /opt/oldboy.sql
---恢复内容省略
mysql> select * from oldboy.test;    ---查询数据是否还有
+----+---------+
| id | name    |
+----+---------+
|  1 | oldboy  |
|  2 | oldgirl |
|  3 | inca    |
|  4 | zuma    |
|  5 | kaka    |
+----+---------+
5 rows in set (0.00 sec)

如果是utf8数据库,人工编辑的SQL文件,则建议使用“UTF8没有签名”格式

1.3 利用mysql命令恢复(标准)

1. 使用mysql命令恢复基本实践

mysql命令是MySQL数据库自带的重要命令之一,除了日常登录数据库之外,还可以通过mysqldump备份的文件或者人工编辑得SQL语句文件对数据库进行数据恢复:

mysql> drop database oldboy;
Query OK, 1 row affected (0.03 sec)
[root@oldboy ~]# mysql < /opt/oldboy.sql 
[root@oldboy ~]# mysql -e "select * from oldboy.test;"    ---使用-e参数,可在命令行执行MySQL命令
+----+---------+
| id | name    |
+----+---------+
|  1 | oldboy  |
|  2 | oldgirl |
|  3 | inca    |
|  4 | zuma    |
|  5 | kaka    |
+----+---------+
2. 使用开发人员提交的SQL语句恢复文件

假定开发人员让运维人员或DBA插入数据到数据库(可能是通过邮件发送的,内容可能是字符串或者SQL文件),此时的SQL文件里可能没有use db这样的字样,此时如果使用mysql命令导入就要指定数据库名了:

[root@oldboy ~]# mysql oldboy < /opt/oldboy.sql

指定库名oldboy的作用就相当于在数据库里执行use oldboy,因此如果使用mysqldump备份时不使用-B参数,那么在恢复时不但可能会提示没有数据库,还可能会提示没有选择数据库,并且在SQL语句文件里尽可能地加入字符集设置,以防止乱码。

[root@oldboy ~]# cat /opt/oldboy5.sql 
set names utf8;
insert into test(name) values('小陶');

mysql不仅可以恢复mysqldump的备份文件,只要是sql语句,都可以通过mysql命令执行到数据库中。

3. 针对压缩的备份数据进行恢复

方法1:使用gzip解压(会删除压缩文件)

gzip -d /opt/oldboy.sql.gz
mysql < /opt/oldboy.sql

方法2:使用gzip解压(不会删除压缩文件)

[root@oldboy ~]# mysqldump -B --master-data=2 --single-transaction oldboy | gzip > /opt/oldboy2.sql.gz
[root@oldboy ~]# gzip -cd /opt/oldboy2.sql.gz > /opt/oldboy2.sql    ---特殊解压方法
[root@oldboy ~]# mysql < /opt/oldboy2.sql

方法3:使用gunzip解压(不会删除压缩文件)

[root@oldboy ~]# gunzip -cd /opt/oldboy2.sql.gz > /opt/oldboy2.sql
[root@oldboy ~]# mysql < /opt/oldboy2.sql

或者:

[root@oldboy ~]# gunzip < /opt/oldboy2.sql.gz | mysql

方法4:使用zcat读取压缩包数据

[root@oldboy ~]# zcat /opt/oldboy2.sql.gz > /opt/oldboy3.sql
[root@oldboy ~]# mysql < /opt/oldboy3.sql

1.4 利用mysql -e参数查看mysql数据

1. 查看数据库oldboy库test表数据
[root@oldboy ~]# mysql -e "use oldboy;select * from test;"
+----+---------+
| id | name    |
+----+---------+
|  1 | oldboy  |
|  2 | oldgirl |
|  3 | inca    |
|  4 | zuma    |
|  5 | kaka    |
+----+---------+
2. 利用mysql -e参数查看SQL线程执行状态
[root@oldboy ~]# mysql -e "show processlist;"
+----+------+-----------+------+---------+------+-------+------------------+
| Id | User | Host      | db   | Command | Time | State | Info             |
+----+------+-----------+------+---------+------+-------+------------------+
| 19 | root | localhost | NULL | Query   |    0 | init  | show processlist |
+----+------+-----------+------+---------+------+-------+------------------+
  • 企业故障案例:
    故障原因是mysql系统的sleep线程过多,有大量的慢查询语句,导致数据库无法接受正常的请求。
mysql> show full processlist;

结果分别如下面两张图所示:

数据库里正在执行的SQL语句的列属性
数据库里正在执行的SQL语句的信息
mysql> kill 212555221;

在“mysql> kill 212555221;”语句中,212555221是ID,若使用kill(insert,update)命令则可能会丢失数据。
解决办法
先调整MySQL的如下两个超时参数配置:

mysql> show variables like '%_timeout';
+-----------------------------+----------+
| Variable_name               | Value    |
+-----------------------------+----------+
| connect_timeout             | 10       |
| delayed_insert_timeout      | 300      |
| innodb_flush_log_at_timeout | 1        |
| innodb_lock_wait_timeout    | 50       |
| innodb_rollback_on_timeout  | OFF      |
| interactive_timeout         | 28800    |
| lock_wait_timeout           | 31536000 |
| net_read_timeout            | 30       |
| net_write_timeout           | 60       |
| rpl_stop_slave_timeout      | 31536000 |
| slave_net_timeout           | 3600     |
| wait_timeout                | 28800    |
+-----------------------------+----------+
12 rows in set (0.00 sec)
set global wait_timeout = 60;
set global interactive_timeout = 60;
---把空闲连接时间缩短

然后在配置文件里修改:

[mysqld]
interactive_timeout = 120    ---此参数设置后wait_timeout自动生效
---服务器关闭交互式连接前等待活动的秒数
wait_timeout = 120
---服务器关闭非交互连接前等待活动的秒数

其他补充方法:
1)在PHP程序中,不使用持久链接,即使用mysql_connect而不是pconnect
2)PHP程序执行完毕,应该显式调用mysql_close
3)Java程序调整连接池(C3P0)或者调整JAVA服务(Tomcat有关连接池参数)
4)逐步分析MySQL的SQL查询及慢查询日志,找到查询过慢的SQL,优化之

3. 利用mysql -e参数查看mysql变量及性能状态
[root@oldboy ~]# mysql -e "show variables;"    ---查看mysql的所有参数配置

可通过以下命令查看my.cnf配置文件的配置有没有在数据库中生效:

[root@oldboy ~]# mysql -e "show variables like 'log_bin';"
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| log_bin       | ON    |
+---------------+-------+

查看mysql数据库运行状态的命令:

[root@oldboy ~]# mysql -e "show global status;" | head -5
Variable_name   Value
Aborted_clients 0
Aborted_connects    0
Binlog_cache_disk_use   0
Binlog_cache_use    9
4. 利用mysql -e参数不重启数据库修改数据库参数
[root@oldboy ~]# mysql -e "show variables;" | grep key_buffer
key_buffer_size 8388608
[root@oldboy ~]# mysql -e "set global key_buffer_size = 1024*1024*16;"
---set global为设置全局变量,命令设置是即时生效,但重启就恢复
[root@oldboy ~]# mysql -e "show variables;" | grep key_buffer
key_buffer_size 16777216
5. 利用mysql -e参数引出的重要命令
show processlist;    ---查看数据库里正在执行的SQL语句,可能无法看全完整的SQL语句
show full processlist;    ---查看正在执行的完整SQL语句,完整显示
set global key_buffer_size = 1024*1024*16    ---不重启数据库调整数据库参数,直接生效,重启后失效
show variables;    ---查看数据库的配置参数信息,例如,my.cnf里参数的生效情况
show variables like '%log_bin%';
kill ID;    ---杀掉SQL线程的命令,ID为线程号
show session status;    ---查看当前会话的数据库运行的状态信息,很重要,要分析并要做好监控
show engine innodb status;    ---显示innodb引擎的性能状态
6. mysqladmin命令常用参数
mysqladmin password oldboy123    ---设置密码
mysqladmin -uroot -poldboy123 password oldboy    ---修改密码
mysqladmin -uroot -poldboy123 status    ---查看状态,相当于show status
mysqladmin -uroot -poldboy123 -i 1 status    ---每秒查看一次状态
mysqladmin -uroot -poldboy123 extended-status    ---等同于“show global status;”
mysqladmin -uroot -poldboy123 flush-logs    ---切割日志
mysqladmin -uroot -poldboy123 processlist    ---查看执行的SQL语句信息
mysqladmin -uroot -poldboy123 processlist -i 1    ---每秒查看一次执行的SQL语句
mysqladmin -uroot -poldboy123 shutdown    ---关闭mysql服务
mysqladmin -uroot -poldboy123 variables    ---相当于show variables
7. mysql命令常用参数

-u:指定数据库用户
-p:指定数据库密码
-S:指定数据库socket文件
-h:指定数据库主机,默认localhost
-P:指定数据库端口,默认3306
-e:不登录数据库指定数据库命令
--default-cgaracter-set=name:指定字符集登录数据库或备份

2. mysqlbinlog增量恢复工具

mysqlbinlog工具的作用是解析mysql的二进制binlog的日志内容,把二进制日志解析成可以在MySQL数据库里执行的SQL语句。

2.1 mysqlbinlog工具解析binlog日志实践

默认情况下,binlog日志是二进制格式的,不能使用查看文本工具得命令查看:

[root@oldboy ~]# cd /application/mysql/data/
[root@oldboy data]# ll oldboy-bin.*
-rw-rw----. 1 mysql mysql  168 Feb  7 21:46 oldboy-bin.000001
-rw-rw----. 1 mysql mysql  168 Feb  7 21:47 oldboy-bin.000002
-rw-rw----. 1 mysql mysql 8343 Feb  8 11:19 oldboy-bin.000003    ---找一个内容大的文件做测试
-rw-rw----. 1 mysql mysql   60 Feb  7 21:47 oldboy-bin.index
[root@oldboy data]# file oldboy-bin.000003
oldboy-bin.000003: MySQL replication log
[root@oldboy data]# tail -2 oldboy-bin.000003    ---查看内容,发现很混乱,确定是非纯文本文件
#
std!!!
      oldboyoldboy/*!40000 ALTER TABLE `test` DISABLE KEYS */p󝯴𛚂S# 
                                                                 std!!!
                                                                       oldboyoldboyBEGINyϴ𛚂£ #
      std!!!
            oldboyoldboyINSERT INTO `test` VALUES (1,'oldboy'),(2,'oldgirl'),(3,'inca'),(4,'zuma'),(5,'kaka')𞪤4𛚐 ° 
                           󖵵\\x #
                                std!!!
                                      oldboyoldboy/*!40000 ALTER TABLE `test` ENABLE KEYS */P
1. 解析指定库的binlog日志
[root@oldboy data]# mysqlbinlog -d oldboy oldboy-bin.000003 -r bin.sql    --- -d指定库,-r指定生成的文件
[root@oldboy data]# grep -i insert bin.sql     ---过滤内容
/*!40019 SET @@session.max_insert_delayed_threads=0*/;
INSERT INTO `test` VALUES (1,'oldboy'),(2,'oldgirl'),(3,'inca'),(4,'zuma'),(5,'kaka')
INSERT INTO `test` VALUES (1,'oldboy'),(2,'oldgirl'),(3,'inca'),(4,'zuma'),(5,'kaka')
INSERT INTO `test` VALUES (1,'oldboy'),(2,'oldgirl'),(3,'inca'),(4,'zuma'),(5,'kaka')
INSERT INTO `test` VALUES (1,'oldboy'),(2,'oldgirl'),(3,'inca'),(4,'zuma'),(5,'kaka')
INSERT INTO `test` VALUES (1,'oldboy'),(2,'oldgirl'),(3,'inca'),(4,'zuma'),(5,'kaka')
INSERT INTO `test` VALUES (1,'oldboy'),(2,'oldgirl'),(3,'inca'),(4,'zuma'),(5,'kaka')
INSERT INTO `test` VALUES (1,'oldboy'),(2,'oldgirl'),(3,'inca'),(4,'zuma'),(5,'kaka')

结论:mysqlbinlog可以指定-d实现分库导出binlog,如果使用-d参数,那么在更新数据时,必须要有use库名,才能分出指定库的binlog,例如,写入数据库的语句必须采用如下写法:

use oldboy;    ---必须要有
insert into test values(1,'oldboy');
2. 按照位置截取binlog内容

按照位置截取binlog内容的优点是精确,但是要花费时间寻找位置,例如,要截取oldboy-bin.000009文件从位置365到位置456的日志:

mysqlbinlog oldboy-bin.000009 --start-position=365 --stop-position=456 -r pos.sql

提示:开始位置点必须存在于binlog里,结尾位置点可以不存在。
若指定了开始位置,不指定结束位置,则会截取开始处到结尾的binlog日志。若指定了结束位置,不指定开始位置,则截取最开始到最后面的全部binlog日志。
所谓的位置点,就是mysqlbinlog解析文件里的不同行行首的“# at 数字”标识的数据。

3. 按照时间戳取binlog内容

按照时间戳取binlog内容的缺点是模糊、不准确,截取的内容会丢失部分数据,精确到秒,1秒也可能会有多条语句。
下面语句标识截取得是oldboy-bin.000009文件从'2019-4-20 17:14:15'时间到'2019-4-23 17:15:15'时间的数据:

mysqlbinlog oldboy-bin.000009 --start-datetime='2019-4-20 17:14:15' --stop-datetime='2019-4-23 17:15:15' -r time.sql

2.2 mysqlbinlog命令常用参数

-d ,--database=name:根据指定库拆分binlog(拆分单表binlog可通过SQL关键字过滤)
-r ,--result-file=name:指定解析binlog输出SQL语句的文件
-R,--read-from-remote-server:从mysql服务器读取binlog日志,是下面参数的别名read-from-remote-master=BINLOG-DUMP-NON-GTIDS
-j,--start-position=#:读取binlog的起始位置点,#号是具体的位置点
--stop-position=#:读取binlog的停止位置点,#号是具体的位置点
--start-datetime=name: 读取binlog的起始位置点,name是具体的时间,格式为:2019-04-20 11:25:26
--stop-datetime=name:读取binlog的停止位置点,name是具体的时间,格式为:2019-04-23 11:25:26
--base64-output=decode-rows:解析row级别binlog日志的方法,例如:mysqlbinlog --base64-output=decode-rows -v mysqlbin.000016

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,504评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,434评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,089评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,378评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,472评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,506评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,519评论 3 413
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,292评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,738评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,022评论 2 329
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,194评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,873评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,536评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,162评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,413评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,075评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,080评论 2 352