本文出自 “断了的×××” 博客,请务必保留此出处http://90sec.blog.51cto.com/7404127/1602364


mysql数据库备份与恢复



 一、备份数据库
1.备份单个数据库
mysqldump -u 用户 –p’密码’ --default-character-set=latin1 数据库名 > 备份文件名(数据库默认编码是latin1)
普通备份:
mysqldump -uroot -p'oldboy123' oldboy > /server/bak/oldboy.sql
压缩备份:
mysqldump -uroot -p'oldboy123' oldboy |gzip > /server/bak/oldboy.sql.gz
设置字符集备份:
mysqldump -uroot -p'oldboy123' oldboy --default-character-set=gbk |gzip > /server/bak/oldboy.sql.gz
执行结果:
[root@oldboy ~]# mkdir /server/bak -p
[root@oldboy ~]# mysqldump -uroot -p'oldboy123' oldboy > /server/ba
backup/ bak/   
[root@oldboy ~]# mysqldump -uroot -p'oldboy123' oldboy > /server/bak/oldboy.sql
[root@oldboy ~]# mysqldump -uroot -p'oldboy123' oldboy |gzip > /server/bak/oldboy.sql.gz
[root@oldboy ~]# ls -l /server/bak/
total 8
-rw-r--r-- 1 root root 1991 Apr  9 00:51 oldboy.sql
-rw-r--r-- 1 root root  801 Apr  9 00:51 oldboy.sql.gz


2.mysqldump在做啥?
mysqldump实际上就是把数据从mysql库里以逻辑的sql语句的形式导出。
备份的数据过滤掉注释:
[root@oldboy ~]# egrep -v "\*|--|^$" /server/bak/oldboy.sql
DROP TABLE IF EXISTS `test`;

CREATE TABLE `test` (
  `id` int(4) NOT NULL AUTO_INCREMENT,
  `name` char(20) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=12 DEFAULT CHARSET=gbk;
LOCK TABLES `test` WRITE;
INSERT INTO `test` VALUES (1,'zhaoyue'),(2,'jesse'),(4,'elain'),(5,'wodi'),(6,'yingsui'),(7,'zhangyang'),(8,'zaixiangpan'),(9,'??????'),(10,'鑰佺敺瀛?),(11,'?); <==这里是乱码,是因为导出时的格式没加字符集,而系统当前字符集又是zh_cn.gb18030格式,一般恢复到数据库里会正常,只是系统外查看不正常而已。另外insert是批量插入的方式,这样在恢复时效率很高。
UNLOCK TABLES;
提示:看到了吧,就是我们曾经插入的表和数据。
[root@oldboy ~]# mysqldump -uroot -p'oldboy123' oldboy --default-character-set=gbk > /server/bak/oldboy-gbk.sql
[root@oldboy ~]# egrep -v "\*|--|^$" /server/bak/oldboy-gbk.sql
DROP TABLE IF EXISTS `test`;
CREATE TABLE `test` (
  `id` int(4) NOT NULL AUTO_INCREMENT,
  `name` char(20) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=12 DEFAULT CHARSET=gbk;
LOCK TABLES `test` WRITE;
INSERT INTO `test` VALUES (1,'zhaoyue'),(2,'jesse'),(4,'elain'),(5,'wodi'),(6,'yingsui'),(7,'zhangyang'),(8,'zaixiangpan'),(9,'??????'),(10,'
老男孩'),(11,''); <==。其他乱码是当初插入时就有问题的。
UNLOCK TABLES;


3.备份多个库
[root@oldboy ~]# mysqldump -uroot -p'oldboy123' -B oldboy mysql --default-character-set=gbk > /server/bak/oldboy-gbk-muli.sql
提示:-B参数是关键,表示接多个库。

 

※※※※※(生产环境常用)
  -B, --databases     To dump several databases. Note the 
difference in usage;
                      In this case no tables are given. All name arguments are
                      regarded as databasenames. 'USE db_name;' will be
                      included in the output.
参数说明:该参数用于导出若干个数据库,在备份结果中会加入USE db_nameCREATE DATABASE `db_name`;
      -B后的参数都将被作为数据库名。该参数比较常用。当-B后的数据库列全时 同 -A参数。请看-A的说明。


4.备份单个表
mysqldump -u 用户名 -p 数据库名 表名备份的文件名
mysqldump -u root -p oldboy test> oldboy_oldboy.sql

执行结果:
[root@oldboy ~]# mysqldump -uroot -p'oldboy123' oldboy test --default-character-set=gbk > /server/bak/oldboy-gbk-single.sql
提示:无-B参数,库oldboy后面就是test表了。


5.备份多个表
[root@oldboy ~]# mysqldump -uroot -p'oldboy123' oldboy test ett --default-character-set=gbk > /server/bak/oldboy-gbk-muti-tables.sql
[root@oldboy ~]# egrep -v "\*|--|^$" /server/bak/oldboy-gbk-muti-tables.sql
DROP TABLE IF EXISTS `test`;

CREATE TABLE `test` (
  `id` int(4) NOT NULL AUTO_INCREMENT,
  `name` char(20) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=12 DEFAULT CHARSET=gbk;
LOCK TABLES `test` WRITE;
INSERT INTO `test` VALUES (1,'zhaoyue'),(2,'jesse'),(4,'elain'),(5,'wodi'),(6,'yingsui'),(7,'zhangyang'),(8,'zaixiangpan'),(9,'??????'),(10,'老男孩'),(11,'');
UNLOCK TABLES;
DROP TABLE IF EXISTS `ett`;
CREATE TABLE `ett` (

  `id` int(11) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=gbk;
LOCK TABLES `ett` WRITE;
UNLOCK TABLES;


6.备份数据库结构(不包含数据)
mysqldump -uroot -d -p'oldboy' oldboy oldboy> oldboy_oldboy.sql
-d 只备份表结构
[root@oldboy ~]# mysqldump -uroot -p'oldboy123' -d oldboy >/tmp/desc.sql                         
[root@oldboy ~]# egrep -v "\*|--|^$" /tmp/desc.sql            
DROP TABLE IF EXISTS `ett`;
CREATE TABLE `ett` (
  `id` int(11) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=gbk;
DROP TABLE IF EXISTS `test`;
CREATE TABLE `test` (
  `id` int(4) NOT NULL AUTO_INCREMENT,
  `name` char(20) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=12 DEFAULT CHARSET=gbk;
更多用法可以 执行 mysqldump –help 查询。有关mysqlmysqldump同学们要详细总结。


二、恢复数据库
1. source命令恢复
进入mysql数据库控制台,mysql -u root -p
mysql>use 数据库
然后使用source命令,后面参数为
脚本文件(如这里用到的.sql)
mysql>source oldboy_db.sql #这个文件是系统路径。
[root@oldboy bak]# mysql -uroot -p'oldboy123'
Welcome to the MySQL monitor.  Commands end with ; or \g.
...skip...
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

 
mysql> use oldboy
Database changed
mysql> show tables;
+------------------+
| Tables_in_oldboy |
+------------------+
| ett              |
| test             |
+------------------+
2 rows in set (0.00 sec)
 
mysql> drop tables test;
Query OK, 0 rows affected (0.01 sec)
 
mysql> system ls .
oldboy-gbk-muli.sql         oldboy-gbk-single.sql  oldboy.sql
oldboy-gbk-muti-tables.sql  oldboy-gbk.sql         oldboy.sql.gz
mysql> source ./oldboy.sql <==还是用第一版没加字符集的备份,就是备份后查看乱码的备份。
Query OK, 0 rows affected (0.00 sec)
...skip...
Query OK, 0 rows affected (0.00 sec)
Q...skip...
Query OK, 0 rows affected (0.00 sec)
 
mysql> select * from test;
+----+-------------+
| id | name        |
+----+-------------+
|  1 | zhaoyue     |
|  2 | jesse       |
|  4 | elain       |

|  5 | wodi        |
|  6 | yingsui     |
|  7 | zhangyang   |
|  8 | zaixiangpan |
|  9 | ??????      |
| 10 | ???         |<==乱码
| 11 | ?           |
+----+-------------+
10 rows in set (0.00 sec)
 
mysql> set names gbk;
Query OK, 0 rows affected (0.00 sec)
 
mysql> select * from test;
+----+-------------+
| id | name        |
+----+-------------+
|  1 | zhaoyue     |
|  2 | jesse       |
|  4 | elain       |
|  5 | wodi        |
|  6 | yingsui     |
|  7 | zhangyang   |
|  8 | zaixiangpan |
|  9 | ??????      |
| 10 | 老男孩      | <==仍然是正常的,就是说备份不加字符集导出,将来恢复不会影响恢复的数据,但是备份后查看文件会乱码。
| 11 |           |
+----+-------------+
10 rows in set (0.00 sec)


2. mysql命令恢复(标准)
mysql -u oldboy -p'oldboy' oldboy < oldboy.sql
mysql> system mysql -uroot -p'oldboy123' oldboy < oldboy-gbk.sql <==导入

的是备份时加字符集的版本。
mysql> select * from test;
+----+-------------+
| id | name        |
+----+-------------+
|  1 | zhaoyue     |
|  2 | jesse       |
|  4 | elain       |
|  5 | wodi        |
|  6 | yingsui     |
|  7 | zhangyang   |
|  8 | zaixiangpan |
|  9 | ??????      |
| 10 | 老男孩      |<==因为上文source导入时已经set names gbk了, 所以此处不是乱码。
| 11 |           |
+----+-------------+
10 rows in set (0.00 sec)
 
 
2.1.1.MyISAM引擎备份
    由于MyISAM引擎为表级锁,因此,在备份时需要防止在备份期间数据写入而导致不一致,所以,在备份时使用--lock-all-tables加上读锁
mysqldump -A -F -B --lock-all-tables |gzip >/data/backup/$(date +%F).tar.gz
特别提示:有关MyISAMInnoDB引擎的差别和在工作中如何选择,在前面的文章已经详细讲解过了,这里就不在讲了。

2.1.2 InnoDB引擎备份
InnoDB引擎为行锁,因此,备份时可以不对数据库加锁的操作,可以加选项--single-transaction进行备份:

mysqldump -A -F -B --single-transaction |gzip >/data/backup/$(date +%F).tar.gz
特别注意:
1--single-transaction仅适用于InnoDB引擎。
 
生产环境mysqldump备份命令
mysqldump –u root –p –S /data/3306/mysql.sock –default-character-set=gbk –single-transaction –F –B oldboy|gzip > /server/backup/mysql_$(date +%F).sql.gz
 
:
-F:刷新bin-log参数,数据库备份完以后,会刷新bin-log
 
增量备份:
更新bin-log:
mysqladmin –uroot –p –S /data/3306/mysql.sock flush-logs
如生成mysql-bin.000004文件
把生成的最新mysql-bin.000004文件,CP/var/backup/
把二进制的日志生成 sql语句:
mysqlbinlog mysql-bin.000004>bin04.sql
如果有多个库,我们应该用-d来指定恢复单个库
mysqlbinlog mysql-bin.000004 –d oldboy >binlog.sql  (当然对于库也要分库备,否则恢复还是麻烦)
还原数据:先还原全备,再还原增备
先还原全备:mysql –u root –p  <mysql
file.sql
还原增备:mysql –u root –p  <binlog.sql(恢复增备的时候,需要把误操作的语句删掉后,再还原,否则,还原后,还是会和误操作后一样)
 
基于时间点的增量恢复
mysqlbinlog mysql-bin.000004 –start-datetime=’2011-03-19 025854’—stop-datetime=’2011-03-19 032244’ –r time.sql
上面语句将显示2011.03-19 02:58:54-----2011-03-19 03:22:44时间段的binlog,并输出到time.sql

拽定开始时间到文件结束
mysqlbinlog mysql-bin.000004 –start-datetime=’ 2011-03-19 025854’ –d oldboy –r time.sql
这个语句只有开始时间,那么就是从2011-03-19 025854时刻到日志结尾,lodboy数据库的binlog输出到time.sql
 
基于位置点的增量恢复
指定开始位置和结束位置
mysqlbinlog mysql-bin.000004 –start-position=510 –stop-position=1312 –r pos.sql
输出初始位置510,结束位置1312的所有binlog日志到pos.sql
注意:结尾的日志点细弱特殊不会被包含。即输出1312pos以前的binlog
指定开始位置到文件结束
mysqlbinlog mysql-bin.000004 –start-position=510 –r pos510-end.sql
输出初始位置510,结束位置到文件结尾的所有binlogpos510-end.sql。当然,你也可以指定库名输出binlog。如:
mysqlbinlog mysql-bin.000004 --start-position=510 –r pos510-end-oldboy.sql –d oldboy
从文件开头到指定结束位置
mysqlbinlog mysql-bin.000004 --stop-position=954 -r start-954.sql
输出从文件开始位置,到954位置截止的所有binlog

掌握和查找打开的文件
lsof(列出打开的文件)实用程序会显示打开的文件名。其选项仅显示某些进程,只有一个进程的某些文件描述符,或只有某些网络连接(网络连接使用文件描述符,就像普通文件一样,lsof 也显示这些)。使用 ps – ef 确定了可疑进程后,输入以下命令:

 # lsof -s -p pid

服务器最大设置的连接数:151
mysql> show variables like'max_connections';
+-----------------+-------+
| Variable_name   | Value |
+-----------------+-------+
| max_connections | 151   |
+-----------------+-------+
1 row in set (0.00 sec)
 

服务器响应的最大连接数:152
mysql> show global status like 'Max_used_connections';
+----------------------+-------+
| Variable_name        | Value |
+----------------------+-------+
| Max_used_connections | 152   |
+----------------------+-------+
1 row in set (0.00 sec)

查看服务器key_buffer_size数值:402653184
mysql> show variables like 'key_buffer_size';
+-----------------+-----------+
| Variable_name   | Value     |
+-----------------+-----------+
| key_buffer_size | 402653184 |
+-----------------+-----------+

1 row in set (0.00 sec)
 

查看服务器现在使用的key_buffer_size使用情况:
key_read_requests: 879600044
key-reads: 830525
mysql> show global status like 'key_read%';
+-------------------+-----------+
| Variable_name     | Value     |
+-------------------+-----------+
| Key_read_requests | 879600044 |
| Key_reads         | 830525    |
+-------------------+-----------+
2 rows in set (0.00 sec)

计算索引未命中的概率:
key_cache_miss_rate =  key_reads / key_read_requests * 100%
达到0.1%以下(即每1000个请求有一个直接读硬盘)以下都很好,如果key_cache_miss_rae0.01%以下的话,则说明key_buffer_size分配得过多,可以适当减少。
 
Key_blocks_unused表示未使用的缓存簇数,Key_blocks_used表示曾经用到的最大的blocks数,比如这台服务器,所有的缓存都用到了,要么增加key_buffer_size,要么就是过度索引,把缓存占满了。比较理想的设置是:
key_blocks_used / ( key_blocks_unused + key_blocks_used ) * 100 % = 80%
 
mysql> show global status like 'key_blocks_u%';
+-------------------+--------+
| Variable_name     | Value  |
+-------------------+--------+
| Key_blocks_unused | 317003 |
| Key_blocks_used   | 6439   |
+-------------------+--------+
2 rows in set (0.00 sec)
 
 

临时表:
当执行语句时,关于已经被创造了的隐含临时表的数量,我们可以用如下命令查询其具体情况:
mysql> show global status like 'created_tmp%';

+-------------------------+--------+
| Variable_name           | Value  |
+-------------------------+--------+
| Created_tmp_disk_tables | 343326 |
| Created_tmp_files       | 172    |

| Created_tmp_tables      | 675795 |
+-------------------------+--------+
3 rows in set (0.00 sec)
 
每次创建临时表时,created_tmp_tables都会增加,如果是在磁盘上创建临时表,created_tmp_disk_tables也会增加。created_tem_files表示MYSQL服务创建的临时文件数,比较理想的配置是:
Created_Tmp_disk_tables / Created_tmp_tables * 100% <= 25%
比如上面服务器Created_Tmp_disk_tables / Created_tmp_tables * 100% = 50%,比较差了。
我们再看一下
MYSQL服务器对临时表的配置:
mysql> show variables where Variable_name in ('tmp_table_size','max_heap_table_size');
+---------------------+----------+
| Variable_name       | Value    |
+---------------------+----------+
| max_heap_table_size | 16777216 |
| tmp_table_size      | 16777216 |
+---------------------+----------+
2 rows in set (0.00 sec)
只有16M以下的临时表才能全部放在内存中,超过的就会用到硬盘临时表。
 
 

打开表的情况
Open_tables表示打开表的数量,Opend_tables表示打开过的表数量,我们可以用如下命令查看其具体情况:
mysql> show global status like 'open%tables%';
+---------------+--------+
| Variable_name | Value  |
+---------------+--------+
| Open_tables   | 512    |
| Opened_tables | 234200 |
+---------------+--------+
2 rows in set (0.00 sec)
如果Opened_tables数量过大,说明配置中tables_caceh(MYSQL 5.1.3 之后这个值叫做table_open_cache)的值可能太小。我们查询一下服务器table_cache值:
mysql> show variables like 'table_open_cache';          
+------------------+-------+
| Variable_name    | Value |
+------------------+-------+
| table_open_cache | 614   |
+------------------+-------+
1 row in set (0.00 sec)

比较合适的值为:
Open_tables / Opened_tables * 100% >= 85%
Open_tables / table_open_cache * 100% <= 95%
 
 

进程使用情况
如果我们在MYSQL服务器的配置文件中设置了thread-cache_size,当客户端断开之时,服务器处理此客户请求的线程将会缓存起来以响应下一个客户而不是销毁(前提是缓存数未达上限)。Threads_created表示创建过的线程数,我们可以用如下命令查看:
mysql> show global status like 'Thread%';

+-------------------+-------+
| Variable_name     | Value |
+-------------------+-------+
| Threads_cached    | 7     |
| Threads_connected | 2     |
| Threads_created   | 2124  |
| Threads_running   | 2     |
+-------------------+-------+
4 rows in set (0.00 sec)
如果发现Threads_created的值过大的话,表明MYSQL服务器一直在创建线程,这也是比较耗费资源的,可以适当增大配置文件中的thread_cache_size的值。查询服务器thread_cahce_size配置,如下所示:
mysql> show variables like 'thread_cache_size';

+-------------------+-------+
| Variable_name     | Value |
+-------------------+-------+
| thread_cache_size | 8     |
+-------------------+-------+
1 row in set (0.00 sec)
 
 
查询缓存
它涉及的主要有两个参数,query_cache_size是设置MYSQL的Query_Cache大小,query_cache_size是设置使用查询缓存的类型,我们可以用如下命令查看其具体情况:
mysql> show global status like 'qcache%';

+-------------------------+----------+
| Variable_name           | Value    |
+-------------------------+----------+
| Qcache_free_blocks      | 130      |
| Qcache_free_memory      | 31557680 |
| Qcache_hits             | 15838885 |
| Qcache_inserts          | 2391041  |
| Qcache_lowmem_prunes    | 0        |

 
| Qcache_not_cached       | 671718   |
| Qcache_queries_in_cache | 676      |
| Qcache_total_blocks     | 1798     |
+-------------------------+----------+
8 rows in set (0.00 sec)
 
我们再查询一下服务器上关于query-cache的配置命令如下:
mysql> show variables like 'query_cache%';

+------------------------------+----------+
| Variable_name                | Value    |
+------------------------------+----------+
| query_cache_limit            | 1048576  |
| query_cache_min_res_unit     | 4096     |
| query_cache_size             | 33554432 |
| query_cache_type             | ON       |
| query_cache_wlock_invalidate | OFF      |
+------------------------------+----------+
5 rows in set (0.00 sec)
 
 

排序使用情况
它表示系统中对数据进行排序时所使用的Buffer,我们可以用如下命令查看:
mysql> show global status like 'sort%';

+-------------------+-----------+
| Variable_name     | Value     |
+-------------------+-----------+
| Sort_merge_passes | 84        |
| Sort_range        | 393425    |
| Sort_rows         | 751581502 |
| Sort_scan         | 324383    |
+-------------------+-----------+
4 rows in set (0.00 sec)
 
Sort_merge_passes包括如下步骤:MYSQL首先会尝试在内存中做排序,使用的内存大小由系统变量sort_buffer_size来决定,如果它不够大则把所有的记录都读到内存中,而MYSQl则会把每次在内存中排序的结果存到临时文件中,等 MYSQL找到所有记录之后,再把临时文件中的记录做一次排序。这次再排序就会增加sort_merge_passes。实际上,MYSQL会用另一个临时文件来存储再次排序的结果,所以我们通常会看到sort_merge_passes增加的数值是建临时文件数的两倍。因为用到了临时文件,所以速度可能会比较慢,增大sort_buffer_size会减少sort_merge_passes和创建临时文件的次数,但盲目地增加sort_buffer_size并不一定能提高速度。
 

 
文件打开数(open_files
我们在处理MYSQL故障时,发现当open_files大于open_files_limit值时,MYSQL数据库就会发生卡住的现象,导致APACHE服务器打不开相应页面。这个问题大家在工作中应注意,我们可以用如下命令查看其具体情况:
mysql> show global status like 'open_files';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| Open_files    | 901   |
+---------------+-------+
1 row in set (0.00 sec)
 
mysql> show variables like'open_files_limit';
+------------------+-------+
| Variable_name    | Value |
+------------------+-------+
| open_files_limit | 1185  |
+------------------+-------+

1 row in set (0.00 sec)
 
比较适合的设置是:open_files / open_files_limit * 100% <= 75%
 
 

带宽的大小
通常我们在架构网站的时候,会设定一些目标,比如网站每天要能承受千万PV的访问量,这时我们要估算一下大概需要多大的带宽。计算带宽大小主要的有2个主要指标(峰值流量和页面大小),我们先做出必要的假设:
1.   峰值流量是平均流量的3倍;
2.   每次访问平均的页面大小是100KB左中。
如果
1000PV的访问量在一天内平均分布,每秒大约120次访问,如果按平均每次访问页面大小是100KB字节计算,120次访问总计大约就是12000KB。字节的单位是Byte,而带宽单位是bit,它们之间的关系是1Byte=8bit,所以12000k Byte大致就相当于96000k bit,也就是90Mbps的样子。实际上,我们的网站必须能在峰值流量时保持正常运行状态,所以按照假设的峰值流量计算,真实带宽的需求应该在270Mbps左右。

 

当然,这个结论是根据前面提到的两点假设得出来的,具体值则需要根据公司实际情况来计算。
 
 
数据库服务器是重中之重,因为网站的瓶颈问题大多出在数据库身上。现在一般的中小网站多使用MYSQL数据库。一般而言,使用MYSQL数据库的时候,我们应该配置为一个主从(一方多从)结构,主数据库服务器使用InnoDB表结构,从数据服务器使用MyiSAM表结构。这样充分发挥它们各大自的优势,而且这样的方从分离了读写操作,降低了读操作的压力。我们还可以设定一个专门的从服务器作为备份服务器,有时候还需要借助
mcached/' target='_blank'>Memcached之类的第三方软件,以便适应更大访问量的要求。