日志
MySQL日志记录了MySQL数据库日常操作和错误信息,MySQL有不同类型的日志文件(各自存储了不同类型的日志),从日志当中可以查询到MySQL数据库的运行情况、用户操作、错误信息等
MySQL日志主要分为四类,使用这些日志文件可以查看MySQL内部发生的事情:
- 二进制日志,记录所有更改数据的语句,可以用于主从数据库复制,数据恢复等
- 错误日志,记录MySQL服务的启动、运行或停止MySQL服务出现的问题
- 查询日志,记录建立的客户端连接和执行的语句
- 慢查询日志,记录所有执行时间超过long_query_time的所有查询或不使用索引的查询
默认情况下,所有日志创建于MySQL数据目录中,启动日志会降低MySQL数据库性能,例如查询频繁的数据库系统,开启通用查询和慢查询日志将会花费时间用于记录,同时,日志会占据磁盘空间。
四种日志详细介绍
MySQL的日志默认保存在数据库文件的存储目录(一般为/usr/local/mysql/data/)。也可以修改配置文件,自定义日志文件的保存位置。
错误日志
错误日志,用来记录当MySQL启动、停止或运行时发生的错误信息,默认已开启。
vim /etc/my.cnf
[mysqld]
log-error=/usr/local/mysql/data/mysql_error.log #指定日志的保存位置
通用查询日志
通用查询日志,用来记录MySQL的所有连接和语句,默认是关闭的。
vim /etc/my.cnf
[mysqld]
general_log=ON
general_log_file=/usr/local/mysql/data/mysql_general.log
二进制日志
二进制日志(binlog),用来记录所有更新了数据或者已经潜在更新了数据的语句,记录了数据的更改,可用于数据恢复,默认已开启。
vim /etc/my.cnf
[mysqld]
log-bin=mysql-bin #也可以log_bin=mysql-bin
#使用相对路径,则文件存储在默认目录/usr/local/mysql/data/中
慢查询日志
慢查询日志,用来记录所有执行时间超过long_query_time秒的语句,可以找到哪些查询语句执行时间长,以便于优化,默认是关闭的。
vim /etc/my.cnf
[mysqld]
slow_query_log=ON
slow_query_log_file=/usr/local/mysql/data/mysql_slow_query.log
long_query_time=5 #慢查询时间,设置超过5秒执行的语句被记录,缺省时为10秒
配置四种日志:
步骤一:修改配置文件/etc/my.cnf
vim /etc/my.cnf
[mysqld]
##错误日志,用来记录当MySQL启动、停止或运行时发生的错误信息,默认已开启
log-error=/usr/local/mysql/data/mysql_error.log
##通用查询日志,用来记录MySQL的所有连接和语句,默认是关闭的
general_log=ON
general_log_file=/usr/local/mysql/data/mysql_general.log
##二进制日志(binlog),用来记录所有更新了数据或者已经潜在更新了数据的语句,记录了数据的更改,可用于数据恢复,默认已开启
log-bin=mysql-bin #也可以log_bin=mysql-bin
#使用相对路径,则文件存储在默认目录/home/mysql/中
##慢查询日志,用来记录所有执行时间超过long_query_time秒的语句,可以找到哪些查询语句执行时间长,以便于优化,默认是关闭的
slow_query_log=ON
slow_query_log_file=/usr/local/mysql/data/mysql_slow_query.log
long_query_time=5 #慢查询时间,设置超过5秒执行的语句被记录,缺省时为10秒
步骤二:重启服务
systemctl restart mysqld
查询日志是否已开启
mysql -u root -p[密码]
#查看错误日志存放位置
show variables like 'log_error';#查看通用查询日志是否开启
show variables like 'general%';#查看二进制日志是否开启
show variables like 'log_bin%';#查看慢查询日志功能是否开启
show variables like '%slow%';#查看慢查询时间设置
show variables like 'long_query_time';#在数据库中设置开启慢查询的方法,即以修改变量值的方式开启。但重启服务后会失效。
set global slow_query_log=ON;
分割二进制日志
mysql-bin.index 文件会对二进制日志进行分割。
每次重启 mysql 或 在数据库中 "flush logs"刷新日志之后,会生成一个新的二进制日志。
数据库备份
一、数据备份的重要性
在生产环境中我们数据库可能会遭遇各种各样的不测从而导致数据丢失, 大概分为以下几种.
- 备份的主要目的是灾难恢复。
- 在生产环境中,数据的安全性至关重要。
- 任何数据的丢失都可能产生严重的后果。
- 造成数据丢失的原因:
- 程序错误
- 人为操作错误
- 运算错误
- 磁盘故障
- 灾难(如火灾、地震)和盗窃
须知在生产环境中,服务器的硬件坏了可以维修或者换新,软件崩溃可以修复或重新安装, 但是如果数据没了那可就毁了,生产环境中最重要的应该就是数据了。所以, 为了在数据丢失之后能够恢复数据, 我们就需要定期的备份数据。
二、数据库备份的分类和备份策略
一般情况下, 我们需要备份的数据分为以下几种
- 数据
- 二进制日志, InnoDB事务日志
- 代码(存储过程、存储函数、触发器、事件调度器)
- 服务器配置文件
数据库备份的分类: 物理备份、逻辑备份
- 物理备份
物理备份:对数据库操作系统的物理文件(如数据文件、日志文件等)的备份。
物理备份方法:
- 冷备份(脱机备份) :是在关闭数据库的时候进行的
- 热备份(联机备份) :数据库处于运行状态,依赖于数据库的日志文件
- 温备份:数据库锁定表格(不可写入但可读)的状态下进行备份操作
MySQL中进行不同类型的备份还要考虑存储引擎是否支持
-
MyISAM
热备 ×
温备 √
冷备 √ -
InnoDB
热备 √
温备 √
冷备 √
- 逻辑备份
逻辑备份:对数据库逻辑组件(如:表等数据库对象)的备份。
- 即以sql语句的形式,把库、表结构、表数据保存下来。
数据库的备份策略
- 完全备份(全量备份):每次对数据库进行完整的备份。
- 差异备份:备份自从上次完全备份之后被修改过的文件。
- 增量备份:只有在上次完全备份或者增量备份后被修改的文件才会被备份。
常见的备份方法
物理冷备: (完全备份)
- 备份时数据库处于关闭状态,直接打包数据库文件
- 备份速度快,恢复时也是最简单的
专用备份工具mydump或mysqlhotcopy (完全备份,逻辑备份)
- mysqldump常用的逻辑备份工具 (导出为sql脚本)
- mysqlhotcopy仅拥有备份MyISAM和ARCHIVE表
启用二进制日志进行增量备份 (增量备份)
- 进行增量备份,需要刷新二进制日志
第三方工具备份
- 免费的MySQL热备份软件Percona XtraBackup
(阿里云的工具:dts,支持热迁移)
备份的工具
| 备份工具 | 备份速度 | 恢复速度 | 便捷性 | 适用存储引擎 | 支持的备份类型 | 功能 | 应用场景 |
|---|
此外,如果考虑到增量备份,还需要结合binlog日志(binlog只属于增量恢复),需要用到工具mysqlbinlog,相当于逻辑备份的一种
设计备份策略
备份策略设计的参考值
备份数据的策略要根据不同的应用场景进行定制, 大致有几个参考数值, 我们可以根据这些数值从而定制符合特定环境中的数据备份策略
- 能够容忍丢失多少数据
- 恢复数据需要多长时间
- 需要恢复哪一些数据
三种备份策略及应用场景
针对不同的场景下, 我们应该制定不同的备份策略对数据库进行备份, 一般情况下, 备份策略一般为以下三种
- 直接cp,tar复制数据库文件
- mysqldump+复制BIN LOGS
- lvm2快照+复制BIN LOGS
- xtrabackup+复制BIN LOGS**
以上的几种解决方案分别针对于不同的场景
- 如果数据量较小, 可以使用第一种方式, 直接复制数据库文件
- 如果数据量还行, 可以使用第二种方式, 先使用mysqldump对数据库进行完全备份, 然后定期备份BINARY LOG达到增量备份的效果
- 如果数据量一般, 而又不过分影响业务运行, 可以使用第三种方式, 使用
lvm2的快照对数据文件进行备份, 而后定期备份BINARY LOG达到增量备份的效果 - 如果数据量很大, 而又不过分影响业务运行, 可以使用第四种方式, 使用
xtrabackup进行完全备份后, 定期使用xtrabackup进行增量备份或差异备份
MySQL完全备份介绍
什么是完全备份
- 完全备份是对整个数据库、数据库结构和文件结构的备份
- 保存的是备份完成时刻的数据库
- 是差异备份与增量备份的基础
完全备份的优缺点
优点:
- 备份与恢复操作简单方便
缺点:
- 数据存在大量的重复
- 占用大量的备份空间
- 备份与恢复时间长
完全备份的方法
物理冷备份与恢复
- 关闭MySQL数据库
- 使用tar命令直接打包数据库文件夹
- 直接替换现有MySQL目录即可
mysqldump备份与恢复
- MySQL自带的备份工具,可方便实现对MySQL的备份
- 可以将指定的库、表导出为SQL脚本
- 使用命令mysq|导入备份的数据
完全备份与恢复 操作演示
物理冷备份
完全备份
先关闭数据库,之后打包备份
systemctl stop mysqld #先关闭服务
mkdir /backup/ #创建备份目录
rpm -q xz #使用xz工具进行压缩,检查xz工具是否已安装
yum install xz -y #如果没安装,可以先yum安装
tar Jcf /backup/mysql_all_$(date +%F).tar.xz /usr/local/mysql/data
#打包数据库文件。/usr/local/mysql/data 为数据库文件存放目录
cd /backup/ #切换到备份目录
ls #查看目录内容
tar tf mysql_all_2000.tar.xz #查看tar包内的文件
完全恢复
将数据库迁移到另一台主机,测试完全恢复。
#主机A,使用scp命令将tar包传给另一台主机B
scp /backup/mysql_all_2022-10-30.tar.xz 192.168.142.20:/opt
##主机B的操作##
systemctl stop mysqld #关闭mysql
cd /opt/
mkdir /opt/bak/ #创建备份目录
tar Jxf mysql_all_2022-10-30.tar.xz -C /opt/bak/ #将tar包解压到备份目录
cd /opt/bak/ #切换到tar包的解压目录
\cp -af usr/local/mysql/data/ /usr/local/mysql #将data目录复制到/usr/local/mysql/目录下,覆盖原有文件
systemctl start mysqld #启动mysql
mysql -u root -p #登录数据库查看
show databases;
use yuanshen;
show tables;
select * from liyue;
逻辑备份(使用mysqldump工具)
mysqldump是常用的逻辑备份工具。
mysqldump可以将指定的库、表导出为SQL脚本。
mysqldump完全备份
完全备份一个或多个完整的库(包括库中所有的表)
mysqldump -uroot -p[密码] --databases 库名1 [库名2].. >/备份路径/备份文件名.sql
#导出的就是数据库脚本文件eg:
mysqldump -u root -p --databases yuanshen > /opt/mysql_bak/liyu.sql #完全备份一个库liyu
mysqldump -u root -p --databases yuanshen xuezhong > /opt/mysql_bak/liyu-xuezhong.sql #完全备份多个库,
完全备份MySQL服务器中所有的库(包括库中所有的表)
mysqldump -u root -p[密码] --all-databases > / 备份路径/备份文件名.sql
eg: mysqldump -u root -p --all-databases > /opt/mysql_bak/all.sql #完全备份所有的库
完全备份指定库中的部分表
注意:只备份表,sql语句中只有对表的操作,没有对库的操作。恢复时需要人为确认库存在。
mysqldump -u root -p[密码] [-d] 库名 表名1 [表名2] ... > /备份路径/备份文件名.sql
#使用“-d"选项,说明只保存数据库的表结构
#不使用“-d”选项,说明表数据也进行备份eg:
mysqldump -u root -p yuanshen liyue xumi > /opt/mysql_bak/yuan-li-xu.sql
#完全备份market库中的location表和store表
查看备份文件
备份文件中保存的是sql语句。即以sql语句的形式,把库、表结构、表数据保存下来。
cd /opt/mysql_bak
cat yuan-li-xu.sql | grep -v "^--" | grep -v "^/" | grep -v "^$"
mysqldump完全恢复
先启动mysql
systemctl start mysqld
恢复数据库
先删除数据库,之后进行恢复。
##删除数据库yuanshen##
mysql -u root -p -e 'drop database yuanshen;'
#"-e"选项,用于指定连接MySQL后执行的命令,命令执行完后自动退出
mysql -u root -p -e 'SHOW DATABASES;' #查看当前有哪些数据库
##恢复数据库liyu##
mysql -u root -p < /opt/mysql_bak/liyu.sql #重定向输入库文件
mysql -u root -p -e 'SHOW DATABASES;' #查看当前有哪些数据库
恢复数据表
当备份文件中只包含表的备份,而不包含创建的库的语句时,执行导入操作时必须指定库名,且目标库必须存在。
##备份yuanshen库中的liyue表##
mysqldump -uroot -p yuanshen liyue > /opt/mysql_bak/liyue.sql
##删除yuanshen库中的liyue表##
mysql -u root -p -e 'drop table yuanshen.liyue;'
mysql -u root -p -e 'show tables from liyue;' #查看yuanshen库中的表,已无liyue表
##恢复yuanshen库中的liyue表##
mysql -u root -p yuanshen < /opt/mysql_bak/liyue.sql #重定向导入备份文件,必须指定库名,且目标库必须存在
mysql -u root -p -e 'show tables from liyue;'
MySQL增量备份与恢复
MySQL增量备份介绍
使用mysqldump进行完全备份存在的问题
- 备份数据中有重复数据
- 备份时间与恢复时间过长
增量备份是什么:
- 是自上一次备份后增加/变化的文件或者内容
增量备份的特点
- 没有重复数据,备份量不大,时间短
- 恢复需要上次完全备份及完全备份之后所有的增量备份才 能恢复,而且要对所有增量备份进行逐个反推恢复
MySQL增量备份的方法
-
MySQL没有提供直接的增量备份方法
-
可通过MySQL提供的二进制日志间接实现增量备份
-
MySQL二进制日志对备份的意义
- 二进制日志保存了所有更新或者可能更新数据库的操作
- 二进制日志在启动MySQL服务器后开始记录,并在文件达到 max_binlog_size所设置的大小或者接收到flush logs命令后重新 创建新的日志文件
- 只需定时执行flush logs方法重新创建新的日志,生成二进制文 件序列,并及时把这些日志保存到安全的地方就完成了一个时间 段的增量备份
MySQL数据库增量恢复
-
一般恢复
- 将所有备份的二进制日志内容全部恢复
-
基于位置恢复
- 数据库在某一时间点可能既有错误的操作也有正确的操作
- 可以基于精准的位置跳过错误的操作
-
基于时间点恢复
- 跳过某个发生错误的时间点实现数据恢复
增量备份与恢复 操作演示
增量备份
1、开启二进制日志功能
vim /etc/my.cnf
[mysqld]
log-bin=mysql-bin #开启二进制日志。如果使用相对路径,则保存在/usr/local/mysql/data/目录下
binlog_format = MIXED #可选,指定二进制日志(binlog)的记录格式为MIXED
server-id = 1
systemctl restart mysqld
ls -l /usr/local/mysql/data/mysql-bin.*
注:
#二进制日志(binlog)有3种不同的记录格式:
STATEMENT (基于SQL语句)、ROW(基于行)、MIXED(混合模式),默认格式是STATEMENT\STATEMENT (基于SQL语句):记录修改的sql语句。高并发的情况下,记录操作的sql语句时可能顺序会有错误,导致恢复数据时,数据丢失或有误差。效率高,但数据可能有误差。
ROW(基于行):记录每一行数据,准确,但恢复时效率低。
MIXED(混合模式):正常情况下使用STATEMENT,高并发的情况下会智能地切换到ROW。
2、可每周对数据库或表进行完全备份
mysqldump -u root -p yuanshen liyue > /bak/yuan_li_$(date +%F).sql
mysqldump -u root -p --databases yuanshen > /bak/yuan_$(date +%F).sql
3、可每天进行增量备份操作,生成新的二进制日志文件(例如mysql-bin.000005)
mysqladmin -u root -p flush-logs
4、插入新数据,以模拟数据的增加或变更
use yuanshen;
insert into xumi values(5,'琴','单手剑','风','') ;
5、再次生成新的二进制日志文件(例如mysql -bin.000006)
mysqladmin -u root -p flush-logs
#之前的步骤4的数据库操作会保存到mysql-bin.000005文件中,之后数据库数据再发生变化则保存在mysql-bin.000006文件中
6、查看二进制日志文件的内容
cp /usr/local/mysql/data/mysql-bin.000006 /opt/bak
mysqlbinlog --no-defaults --base64-output=decode-rows -v /bak/mysql-bin.000006
#--base64-output=decode-rows:使用64位编码机制去解码并按行读取
#-v:显示详细内容
增量恢复
-
一般恢复
- 将所有备份的二进制日志内容全部恢复
-
基于位置恢复
- 数据库在某一时间点可能既有错误的操作也有正确的操作
- 可以基于精准的位置跳过错误的操作
-
基于时间点恢复
- 跳过某个发生错误的时间点实现数据恢复
一般恢复
将所有备份的二进制日志内容全部恢复。
1、模拟丢失更改的数据的恢复步骤。
use yuanshen;
delete from class where id=5; #删除新增加的数据
#增量恢复(今天新增加的两条数据记录保存在mysql-bin.000002日志中)
mysqlbinlog --no-defaults /opt/bak/mysql-bin.000004 | mysql -u root -p
mysql -u root -p -e 'select * from yuanshen.xumi;' #查看表中数据
2、模拟丢失表中所有数据的恢复步骤。
mysql -u root -p -e 'drop table yuanshen.xumi;' #删除整个xumi表
mysql -u root -p -e 'show tables from yuanshen;' #查看yuanshen库中的表
#先完全恢复历史数据
mysql -u root -p yuanshen < /bak/yuan_2022-10-31.sql
#再进行增量恢复今天新增的数据(mysql-bin.000004日志中保存了新增加的数据记录)
mysqlbinlog --no-defaults /bak/mysql-bin.000004 | mysql -u root -p
mysql -u root -p -e 'select * from yuanshen.xumi;' #查看表中数据
断点恢复
向xumi表中插入4条数据,之后刷新二进制日志,移动前一个日志:
use yuanshen;
insert into www values(4,'d',400);
insert into www values(5,'e',500);
insert into www values(6,'f',600);
mysqladmin -u root -p flush-logs #刷新日志,生成新的二进制日志
cp /usr/local/mysql/data/mysql-bin.000006 /opt/bak/ #将前一个日志复制到/bak/目录下
mysqlbinlog --no-defaults --base64-output=decode-rows -v /bak/mysql-bin.000006 > /bak/binlog.txt #将二进制文件内容重定向到binlog.txt文件中
基于位置的断点恢复
mysqlbinlog --no-defaults --start-position='位置点' 文件名 | mysql -u root -p
#从某一个位置点开始恢复,一直到日志结尾mysqlbinlog --no-defaults --stop-position='位置点' 文件名 | mysql -u root -p
#从日志开头,一直恢复到某一个位置点前结束mysqlbinlog --no-defaults --start-position='xxx'--stop-position='位置点' 文件名 | mysql -u root -p
#从某一个位置点开始恢复,一直到某一个位置点前结束
示例1:
只想恢复"5"和"6"(即恢复最后两行,第5、6行)
use yuanshen;
delete from www where cid between 4 and 6; #删除id为4到6的数据记录
cat /bak/binlog.txt #查看二进制文件内容,找到5的位置点
#从5的位置点605一直恢复到结尾
mysqlbinlog --no-defaults --start-position='605' /bak/mysql-bin.000006 | mysql -u root -p
mysql -u root -p -e 'select * from yuanshen.www;' #查看表数据
示例2:
想恢复"4、5"(即恢复前两行4、5行)
use yuanshen;
delete from www where id between 5 and 6; #删除id为5到6的数据记录
cat /bak/binlog.txt #查看二进制文件内容,找到5后面的位置点
#从头开始恢复,在"5"的SQL语句后面截止
mysqlbinlog --no-defaults --stop-position='752' /bak/mysql-bin.000006 | mysql -u root -p
mysql -u root -p -e 'select * from yuanshen.xumi;' #查看表数据
示例3:
只想恢复"5"(即只恢复第5行)
use yuanshen;
delete from www where id between 4 and 5; #删除id为4到5的数据记录
cat /bak/binlog.txt #查看二进制文件内容,找到"5"的位置点
#从“5”前面的位置点开始恢复,一直到"5"后面的位置点
mysqlbinlog --no-defaults --start-position='605' --stop-position='752' /bak/mysql-bin.000006 | mysql -u root -p
mysql -u root -p -e 'select * from yuanshen.xumi;' #查看表数据
基于时间点的断点恢复
注意:日期必须是"yyyy-mm-dd"的格式。
mysqlbinlog --no-defaults --start-datetime='时间点' 文件名 | mysql -u root -p
#从某一个时间点开始恢复,一直到日志结尾mysqlbinlog --no-defaults --stop-datetime='时间点' 文件名 | mysql -u root -p
#从日志开头,一直恢复到某一个时间点前结束mysqlbinlog --no-defaults --start-datetime='起始时间点' --stop-datetime'结束时间点' 文件名 | mysql -u root -p
#从某一个时间点开始恢复,一直到某一个位置点前结束
示例:
只想恢复"5"(即只恢复第5行)
use yuanshen;
delete from www where id=5; #删除id为5的数据记录
cat /bak/binlog.txt #查看二进制文件内容,找到"5"的时间点
#从“5”前面的时间点开始恢复,一直到"5"后面的时间点
mysqlbinlog --no-defaults --start-datetime='2022-10-31 19:15:51' --stop-datetime='2022-10-31 19:16:00' /bak/mysql-bin.000006 | mysql -u root -p
mysql -u root -p -e 'select * from yuanshen.xumi;' #查看表数据
使用脚本备份
-
使用脚本每周三进行一次完全备份,之后每天进行增量备份。
- 如果数据量很大,可以一周做2次完全备份,比如星期一和星期四各一次。
-
增量备份减少磁盘空间的占用,但恢复起来比较麻烦。需要一个一个恢复。
-
一般使用crontab在凌晨进行备份。
获取最新的二进制文件名称
查看索引文件,可获取最新的二进制文件。
tail -1 /usr/local/mysql/data/mysql-bin.index
或者
sed -n '$p' /usr/local/mysql/data/mysql-bin.index
完全备份脚本:
完全备份要求 : 每周三完全备份一次
vim /opt/wanbak.sh #编写脚本
#!/bin/bash
mysqldump -u root -p123456 --all-databases > /bak/all_$(date +%F).sql
chmod 700 /opt/wanbak.sh
crontab -e #定时任务执行脚本
00 1 * * 3 /opt/wanbak.sh #每周三凌晨1点备份一次
增量备份脚本:
增量备份要求 : 每天凌晨3点备份一次
vim /opt/zengbak.sh
#!/bin/bash
#使用sed命令打印二进制日志文件最后一行内容作为filename变量的值
filename=$(sed -n '$p' /usr/local/mysql/data/mysql-bin.index | awk -F '/' '{print $2}')
#将二进制日志移动到备份目录下,并将移动后的文件名称加上日期
mv /usr/local/mysql/data/$filename /bak/binlog_$(date +%F)
#生成新的二进制日志文件
mysqladmin -uroot -p123456 flush-logs
chmod 700 /opt/binlog.sh
crontab -e
00 1 * * 3 /opt/wanbak.sh #完全备份,每周三凌晨1点备份一次
00 3 * * * /opt/zengbak.sh #增量备份,每天凌晨3点备份一次