一、备份的意义
从数据安全的角度来说,数据库服务器磁盘都会做RAID,Mariadb本身也有主从等容灾机制,但它们都无法完全取代备份。容灾和高可用能帮我们有效的应对物理的、硬件的、机械的故障,但是由我们手工操作导致的逻辑错误、系统本身内生性BUG、恶意攻击等方式破坏了你的数据却无能为力。每一种逻辑错误发生的概率都极低,但是当多种可能性叠加的时候,小概率事件就放大成很大的安全隐患,这时候备份的必要性就凸显了。
-
冷备:cold backup
-
温备:warm backup
-
热备:hot backup
-
完全备份:full backup
-
部分备份: partial backup
-
物理备份:直接复制(归档)数据文件的备份方式;physical backup
-
逻辑备份:把数据从库中提出出来保存为文本文件;logical backup
-
完全备份:full backup
-
增量备份:incremental backup
-
差异备份:differential backup
-
选择备份方式
-
选择备份时间
-
考虑到恢复成本
-
恢复时长
-
备份成本
-
锁时间
-
备份时长
-
备份负载
-
数据
-
配置文件
-
代码:存储过程,存储函数,触发器
-
OS相关的配置文件,如crontab配置计划及相关的脚本,跟复制相关的配,二进制日志文件
三、常见的备份工具
mariadb本身为我们提供了mysqldump、mysqlbinlog备份工具,percona也为我们提供了强大的Xtrabackup,加上开源的mydumper,还有基于主从同步的延迟备份、从库冷备等方式,以及基于文件系统快照的备份,其实将这些方式合理搭配已经能够满足我们的需要了。而备份本身是为了恢复,所以能够让我们在出现故障后迅速、准确恢复的备份方式,就是最适合我们的,当然,同时能够省钱、省事,那就非常完美。下面就几种备份工具进行一些比较,探讨下它们各自的适用场景,及简单的使用做一下说明
1、mysqldump
⑴、mysqldump优缺点
mysqldump是最简单的逻辑备份方式(工作方式单线程)。在备份myisam表的时候,如果要得到一致的数据,就需要锁表,简单而粗暴。而在备份innodb表的时候,加上–master-data=2 –single-transaction 选项,在事务开始时刻,记录下binlog-pos点,然后利用mvcc(多版本并发控制)来获取一致的数据,由于是一个大事务,在写入和更新量很大的数据库上,将产生非常多的undo,显著影响性能,所以要慎用。
优点:简单,可针对单表备份,在完全导出表结构的时候尤其有用。可以做到对不同的存储引擎进行备份(InnoDB热备、MyISAM温备、Aria温备)
缺点:简单粗暴,单线程,备份慢而且恢复,不支持差异或增量备份,如果要进行差异或增量备份要结合binlog日志文件
mydumper是mysqldump的加强版。相比mysqldump:
内置支持压缩,可以节省2-4倍的存储空间。
支持并行备份和恢复,因此速度比mysqldump快很多,但是由于是逻辑备份,仍不是很快,如果要进行差异或增量备份要结合binlog日志文件
部分备份工具
SELECT clause INTO OUTFILE '/path/to/somefile'
逻辑备份工具,快于mysqldump。
⑵、mysqldump命令介绍及简单使用
①命令介绍
mysqldump [options] [db_name [tbl_name ...]]
备份单个库:
mysqldump [options] db_name
恢复时:如果目标库不存在,需要事先手动创建
options说明
注意
备份部分
mysqldump+二进制日志文件;
②、实例
要求如下:
③解决方案(此方法不唯一)
备份阶段
第一步,先远程登录到数据库上,事先看一下现有的数据库。
由上图可见,除了hellodb数据库,其它的数据库都是系统自带的,看一下hellodb中有那些表,及当前binlog日志的记录的位置。
由于当前数据库只有一个用户数据库,所以我们在乎其表的存储引擎来判断使用什么方式来备份。(是申请锁或是单事务)
查看表状态发现hellodb中的表全部都是MyISAM的存储引擎,那么就可以使用申请全局锁来备份了。
1
|
# mysqldump -uroot -p
--all-databases --lock-all-tables --flush-logs --master-data=2 >/tmp/all.sql
|
这时数据库全部备份完毕(此方法只适用于数据量不是很大,挑选一个相对并发的写请求不是特别多的时间或午夜备份。如果数据量特别大,此方法将不做参考范围)。
假如在这之后我们又在原来的库中建立新的表或插入数据,而在某一次我误操作删除了此数据库。将如何恢复?
由上图可见,原来的hellodb数据库中多了一张表,为不演示恢复效果我将hellodb删除,看怎么样恢复
现在hellodb己经删除,看如何恢复。
恢复部分
第一步,将服务器离线,导出现在正在使用的binlog日志,还原之前的完全备份
查看完全备份中binlog日志的起始位置。
1
2
|
#vim /tmp/all.sql
-- CHANGE MASTER TO MASTER_LOG_FILE=
'mysql-bin.000002'
, MASTER_LOG_POS=365;
|
将此日志中到删除数据库drop database hellodb之前的数据导出到存放起来,以供时间点还原之用
1
|
# mysqlbinlog --start-position=365 --stop-position=863 mysql-bin.000002 >/tmp/binlogbakup.sql
|
登录数据库
1
2
3
4
5
6
7
|
[root@localhost bin]# mysql
Welcome
to
the MariaDB monitor. Commands
end
with
;
or
\g.
Your MariaDB
connection
id
is
4
Server version: 10.0.10-MariaDB-log Source distribution
Copyright (c) 2000, 2014, Oracle, SkySQL Ab
and
others.
Type
'help;'
or
'\h'
for
help. Type
'\c'
to
clear the
current
input statement.
MariaDB [(none)]>
|
注:此时要临时关闭二进制日志,关闭其它用户连接;
1
2
|
MariaDB [(none)]>
set
session sql_log_bin=0;
Query OK, 0
rows
affected (0.00 sec)
|
导入之前的备份
1
|
MariaDB [(none)]> source /tmp/
all
.sql
|
查看数据库中的表,里面没有我们备份之后建立的表,这时就用到了之前备份的binlog日志了
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
MariaDB [test]> show databases;
+
--------------------+
|
Database
|
+
--------------------+
| hellodb |
| information_schema |
| mysql |
| performance_schema |
| test |
+
--------------------+
5
rows
in
set
(0.05 sec)
MariaDB [test]> use hellodb
Database
changed
MariaDB [hellodb]> show tables;
+
-------------------+
| Tables_in_hellodb |
+
-------------------+
| classes |
| coc |
| courses |
| scores |
| students |
| teachers |
| toc |
+
-------------------+
7
rows
in
set
(0.00 sec)
|
导入binlog日志,完全恢复数据。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
MariaDB [hellodb]> source /tmp/binlogbakup.sql
MariaDB [hellodb]> show tables;
+
-------------------+
| Tables_in_hellodb |
+
-------------------+
| addressbook |
| classes |
| coc |
| courses |
| scores |
| students |
| teachers |
| toc |
+
-------------------+
8
rows
in
set
(0.00 sec)
MariaDB [hellodb]>
select
*
from
addressbook;
+
--------+---------+----------+----------+-----------------+
| fname | lname | phone | fax | email |
+
--------+---------+----------+----------+-----------------+
| France | D'Souza | 123 4567 | 000 7574 | fdz@
some
.domain |
+
--------+---------+----------+----------+-----------------+
1 row
in
set
(0.01 sec)
|
这回数据就完整了。
附上一个基于mysqldump简单复制单库的myisam的脚本
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
#!/bin/sh
###############################
#此脚本用来单库完全份
#每个星期日做一次完全备份
###############################
#设置用户名和密码
v_user=
"root"
v_password=
"mysql"
#mysql安装可执行程序所在位置
MysqlDir=
/usr/local/mari/bin
#备份数据库
database=
"hellodb"
#设置备份路径,创建备份文件夹
BackupDir=
/maria_bak
Full_Backup=$BackupDir
/Full_backup
mkdir
-p $Full_Backup/$(
date
+%Y%m%d)
#开始备份,记录备份开始时间
echo
'###'
$(
date
+
"%Y-%m-%d %H:%M:%S"
)
'###'
"备份开始"
>>$Full_Backup
/full_buckup
.log
$MysqlDir
/mysqldump
-u$v_user -p$v_password --lock-all-tables --flush-logs --master-data=2 --databases $database>$Full_Backup/$(
date
+%Y%m%d)
/full_backup
.sql
#压缩备份文件
gzip
$Full_Backup/$(
date
+%Y%m%d)
/full_backup
.sql
echo
'###'
$(
date
+
"%Y-%m-%d %H:%M:%S"
)
'###'
"备份完成"
>>$Full_Backup
/full_buckup
.log
|
2. 基于文件系统的快照
基于文件系统的快照,是物理备份的一种。在备份前需要进行一些复杂的设置,在备份开始时刻获得快照并记录下binlog pos点,然后采用类似copy-on-write的方式,把快照进行转储。转储快照本身会消耗一定的IO资源,而且在写入压力较大的实例上,保存被更改数据块的前印象也会消耗IO,最终表现为整体性能的下降。而且服务器还要为copy-on-write快照预留较多的磁盘空间,这本身对资源也是一种浪费。因此这种备份方式在生产环境使用的不多。
注:
当刚为数数据文件所在的卷(源卷)创建快照时,此时的快照卷是空的。
当源卷中的数据发生变化后,则将发生变化的那部分数据复制到快照卷上,此时通过快照访问则是未发生变化的数据来自于源卷,变化后的数据来自于快照卷。
快照不是备份,它是仅是提供访问文件的一条通路,当源卷变化的量超出快照卷的大小时,快照卷将崩溃失效。
实例
前提:
首先,mariadb的数据文件在逻辑卷上,如果使用的是支持事务的存储引擎的话,那么要将事务日志与数据文件放在同一个卷上,这样才能保证数据的完整性。
看一下数据文件的属性
步骤:
备份部分
第一步,如果对源卷创建快照,那么首先要对数据库申请全局锁,滚动二进制日志,记录二进制日志位置标记
⑴、申请全局锁
1
2
3
4
5
6
7
8
9
10
11
12
|
MariaDB [(none)]> flush tables
with
read
lock;
Query OK, 0
rows
affected (0.00 sec)
MariaDB [(none)]> flush logs;
Query OK, 0
rows
affected (0.02 sec)
MariaDB [(none)]> show master status;
+
------------------+----------+--------------+------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+
------------------+----------+--------------+------------------+
| mysql-bin.000012 | 365 | | |
+
------------------+----------+--------------+------------------+
1 row
in
set
(0.02 sec)
MariaDB [(none)]>
|
将此二进制日志信息记录下来
1
2
3
4
|
# mysql -e 'show master status;'>/maribak/binlog_pos/binlog_$(date +%F_%T).txt
# cat /maribak/binlog_pos/binlog_2014-04-14_04\:17\:13.txt
File Position Binlog_Do_DB Binlog_Ignore_DB
mysql-bin.000012 365
|
此时可以创建快照了
1
2
|
# lvcreate -L 200M -s -n databak_snap -p r /dev/mydata/lv1
Logical volume
"databak_snap"
created
|
第二步,创建完快照后解锁
当快照卷创建完成后,可以对数据库解锁(创建锁与解锁必须是同一会话,也就是说,当创建完锁之后,这个会话不可退出,之后还要在这个会话中对数据库解锁,一但退出,此会话的全局锁将失效)
1
2
|
MariaDB [(none)]> unlock tables;
Query OK, 0 rowsaffected (0.00 sec)
|
这时数据库又可以正常进行写入操作了
第三步,备份快照
挂载备份之后的快照
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
[root@bogon mnt]
# mount /dev/mydata/databak_snap -o ro /mnt
[root@bogon mnt]
# cd /mnt
[root@bogon mnt]
# ll
total 176172
-rw-rw---- 1 mysql mysql 16384 Apr 14 04:11 aria_log.00000001
-rw-rw---- 1 mysql mysql 52 Apr 14 04:11 aria_log_control
-rw-r----- 1 mysql root 1099 Apr 14 04:11 bogon.err
-rw-rw---- 1 mysql mysql 5 Apr 14 04:11 bogon.pid
drwx------ 2 mysql mysql 4096 Apr 14 04:12 employees
-rw-rw---- 1 mysql mysql 79691776 Apr 14 04:14 ibdata1
-rw-rw---- 1 mysql mysql 50331648 Apr 14 04:14 ib_logfile0
-rw-rw---- 1 mysql mysql 50331648 Apr 14 04:14 ib_logfile1
-rw-rw---- 1 mysql mysql 0 Apr 14 04:11 multi-master.info
drwx------ 2 mysql root 4096 Apr 14 04:11 mysql
drwx------ 2 mysql mysql 4096 Apr 14 04:11 performance_schema
drwx------ 2 mysql root 4096 Apr 14 04:11
test
|
复制快照中的内容
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
[root@bogon mnt]
# cp -a * /maribak/databak/
[root@bogon mnt]
# cd /maribak/databak/
[root@bogon databak]
# ll
total 176172
-rw-rw---- 1 mysql mysql 16384 Apr 14 04:11 aria_log.00000001
-rw-rw---- 1 mysql mysql 52 Apr 14 04:11 aria_log_control
-rw-r----- 1 mysql root 1099 Apr 14 04:11 bogon.err
-rw-rw---- 1 mysql mysql 5 Apr 14 04:11 bogon.pid
drwx------ 2 mysql mysql 4096 Apr 14 04:12 employees
-rw-rw---- 1 mysql mysql 79691776 Apr 14 04:14 ibdata1
-rw-rw---- 1 mysql mysql 50331648 Apr 14 04:14 ib_logfile0
-rw-rw---- 1 mysql mysql 50331648 Apr 14 04:14 ib_logfile1
-rw-rw---- 1 mysql mysql 0 Apr 14 04:11 multi-master.info
drwx------ 2 mysql root 4096 Apr 14 04:11 mysql
drwx------ 2 mysql mysql 4096 Apr 14 04:11 performance_schema
drwx------ 2 mysql root 4096 Apr 14 04:11
test
|
删除快照卷
1
|
#lvremove /dev/mydata/databak_snap
|
里源卷的数据库employees中添入一些数据。
1
2
3
|
MariaDB [employees]>
insert
employees
values
(99,
'1998-09-21'
,
'JEYY'
,
'jose'
,
'M'
,
'2012-12-24'
);
MariaDB [employees]>
insert
employees
values
(999999,
'1995-09-21'
,
'king'
,
'tom'
,
'M'
,
'2012-12-24'
);
MariaDB [employees]>
insert
employees
values
(5211345,
'1995-09-21'
,
'king'
,
'tom'
,
'F'
,
'2012-12-24'
);
|
当备份过完成后,过了几个小时,数据库误删除了一些数据,这时就可用到此次完全备份与即时点还原日志。
1
2
3
|
MariaDB [employees]>
delete
from
employees
where
gender=
'M'
-> ;
Query OK, 179975
rows
affected (3
min
52.82 sec)
|
还原部分
第一步,停止数据库服务,将备份后的数据中的某一张表或整个库替换此数据库中误删除的表或整个库。
1
2
|
[root@bogon employees]
# service mari stop
Shutting down MySQL............... [ OK ]
|
替换
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
[root@bogon employees]
# cp -a /maribak/databak/employees/employees.* .
cp
: overwrite `.
/employees
.frm'? y
cp
: overwrite `.
/employees
.ibd'? y
[root@bogon employees]
# ll
total 237840
-rw-rw---- 1 mysql mysql 61 Apr 14 04:12 db.opt
-rw-rw---- 1 mysql mysql 1571 Apr 14 04:12 departments.frm
-rw-rw---- 1 mysql mysql 114688 Apr 14 04:12 departments.ibd
-rw-rw---- 1 mysql mysql 1999 Apr 14 04:12 dept_emp.frm
-rw-rw---- 1 mysql mysql 31457280 Apr 14 05:03 dept_emp.ibd
-rw-rw---- 1 mysql mysql 1999 Apr 14 04:12 dept_manager.frm
-rw-rw---- 1 mysql mysql 131072 Apr 14 04:55 dept_manager.ibd
-rw-rw---- 1 mysql mysql 1164 Apr 14 04:12 employees.frm
-rw-rw---- 1 mysql mysql 23068672 Apr 14 04:12 employees.ibd
-rw-rw---- 1 mysql mysql 1501 Apr 14 04:12 salaries.frm
-rw-rw---- 1 mysql mysql 146800640 Apr 14 05:03 salaries.ibd
-rw-rw---- 1 mysql mysql 1647 Apr 14 04:12 titles.frm
-rw-rw---- 1 mysql mysql 41943040 Apr 14 05:03 titles.ibd
|
注:此时文件的属性要与原文件的一致
第二步,启动服务
1
2
|
[root@bogon employees]
# service mari start
Starting MySQL.. [ OK ]
|
查看完全备份信息
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
MariaDB [employees]>
select
*
from
employees
where
hire_date >
'2000-01-01'
;
+
--------+------------+------------+------------+--------+------------+
| emp_no | birth_date | first_name | last_name | gender | hire_date |
+
--------+------------+------------+------------+--------+------------+
| 47291 | 1960-09-09 | Ulf | Flexer | M | 2000-01-12 |
| 60134 | 1964-04-21 | Seshu | Rathonyi | F | 2000-01-02 |
| 72329 | 1953-02-09 | Randi | Luit | F | 2000-01-02 |
| 205048 | 1960-09-12 | Ennio | Alblas | F | 2000-01-06 |
| 222965 | 1959-08-07 | Volkmar | Perko | F | 2000-01-13 |
| 226633 | 1958-06-10 | Xuejun | Benzmuller | F | 2000-01-04 |
| 227544 | 1954-11-17 | Shahab | Demeyer | M | 2000-01-08 |
| 422990 | 1953-04-09 | Jaana | Verspoor | F | 2000-01-11 |
| 424445 | 1953-04-27 | Jeong | Boreale | M | 2000-01-03 |
| 428377 | 1957-05-09 | Yucai | Gerlach | M | 2000-01-23 |
| 463807 | 1964-06-12 | Bikash | Covnot | M | 2000-01-28 |
| 499553 | 1954-05-06 | Hideyuki | Delgrande | F | 2000-01-22 |
+
--------+------------+------------+------------+--------+------------+
|
并没有备份后插入的数据,所以在用到binlog日志了,查看当前的binlog的位置
1
2
3
4
5
6
7
|
MariaDB [employees]> show master status;
+
------------------+----------+--------------+------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+
------------------+----------+--------------+------------------+
| mysql-bin.000013 | 326 | | |
+
------------------+----------+--------------+------------------+
1 row
in
set
(0.00 sec)
|
跨文件了~~~,没关系统,先还原同一个日志文件中的数据,再恢复这个日志中的数据,在mysql-bin.000012中找到delect之前的位置,并使用mysqlbinlog将其导出,临时性关闭binlog日志功能,恢复此间数据。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
# mysqlbinlog /mysql/binlog/mysql-bin.000012
..........省略中........
# at 1108
#140414 4:53:25 server id 1 end_log_pos 1146 GTID 0-1-7138
/*!100001 SET @@session.gtid_seq_no=7138*
//
*!*/;
BEGIN
/*!*/;
# at 1146
#140414 4:53:25 server id 1 end_log_pos 1254 Query thread_id=6 exec_time=233 error_code=0
SET TIMESTAMP=1397422405/*!*/;
delete from employees where gender=
'M'
/*!*/;
..........省略中........
|
从日志中看标识到1108即可恢复到删除之前,将此区间导出
1
2
3
|
[root@bogon binlog_pos]
# mysqlbinlog --start-position=365 --stop-position=1108 /mysql/binlog/mysql-bin.000012 >zengliang.sql
[root@bogon binlog_pos]
# ls
binlog_2014-04-14_04:17:13.txt zengliang.sql
|
在数据中临时关闭binlog日志功能。
1
2
3
|
MariaDB [employees]>
set
session sql_log_bin=0;
Query OK, 0
rows
affected (0.01 sec)
MariaDB [employees]> source /maribak/binlog_pos/zengliang.sql;
|
查看一下原来的数据
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
MariaDB [employees]>
select
*
from
employees
where
hire_date >
'2000-01-01'
;
+
---------+------------+------------+------------+--------+------------+
| emp_no | birth_date | first_name | last_name | gender | hire_date |
+
---------+------------+------------+------------+--------+------------+
| 99 | 1998-09-21 | JEYY | jose | M | 2012-12-24 |
| 47291 | 1960-09-09 | Ulf | Flexer | M | 2000-01-12 |
|