mysql给我们提供了很多有用的日志有mysql服务层提供的,有innodb引擎层提供的,下表是mysql服务层给我们提供的:
日志类型 | 写入日志的信息 |
---|---|
二进制日志 | 记录了对MySQL数据库执行更改的所有操作 |
慢查询日志 | 记录所有执行时间超过 long_query_time 秒的所有查询或不使用索引的查询 |
错误日志 | 记录在启动,运行或停止mysqld时遇到的问题 |
通用查询日志 | 记录建立的客户端连接和执行的语句 |
中继日志 | 从复制主服务器接收的数据更改 |
二进制日志(binnary log)以【事件形式】记录了对MySQL数据库执行更改的所有操作。
binlog:
binlog是mysql server层维护的,跟采用何种引擎没有关系,记录的是所有的更新操作的日志记录。
binlog是在事务最终commit前写入的。
我们执行SELECT等不涉及数据更新的语句是不会记binlog的,而涉及到数据更新则会记录。要注意的是,对支持事务的引擎如innodb而言,必须要提交了事务才会记录binlog。
binlog 文件写满后,会自动切换到下一个日志文件继续写,而不会覆盖以前的日志,这个也区别于 redo log,redo log 是循环写入的,即后面写入的可能会覆盖前面写入的。
binlog有两个常用的使用场景:
mysql8中的binLog默认是开启的,5.7默认是关闭的,可以通过参数log_bin
控制;
show variables like '%log_bin%';
flush logs;
show master logs;
先创建表,并插入一些数据:
DROP TABLE IF EXISTS my_student;
CREATE TABLE `my_student` (
`id` int(11) NOT NULL,
`name` varchar(255) DEFAULT NULL,
`score` int(255) DEFAULT NULL,
`grade` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
INSERT INTO `my_student`(`id`, `name`, `score`, `grade`) VALUES (1, 'lucy', 80, 'a');
INSERT INTO `my_student`(`id`, `name`, `score`, `grade`) VALUES (2, 'lily', 90, 'a');
INSERT INTO `my_student`(`id`, `name`, `score`, `grade`) VALUES (3, 'jack', 60, 'c');
INSERT INTO `my_student`(`id`, `name`, `score`, `grade`) VALUES (4, 'hellen', 40, 'd');
INSERT INTO `my_student`(`id`, `name`, `score`, `grade`) VALUES (5, 'tom', 60, 'c');
INSERT INTO `my_student`(`id`, `name`, `score`, `grade`) VALUES (6, 'jerry', 10, 'd');
INSERT INTO `my_student`(`id`, `name`, `score`, `grade`) VALUES (7, 'sily', 20, 'd');
执行删除操作,假装误删除,直接全部删除也可以,把表删了都行,一样的道理:
delete from my_student;
因为 binlog 的日志文件是二进制文件,不能用文本编辑器直接打开,需要用特定的工具来打开,MySQL 提供了 mysqlbinlog 来帮助我们查看日志文件内容:
cmd打开输入
mysqlbinlog
:
进入到binlog的目录内,打开cmd输入下列命令,查看全部的日志信息
# 进入到binlog的目录内,打开cmd输入下列命令,查看全部的日志信息
mysqlbinlog -v SAYHELLO-bin.000096
指定位置/时间查看binlog:
# 指定位置范围
mysqlbinlog -v SAYHELLO-bin.000096 --start-position=0 --stop-position=1000
# 指定时间范围
mysqlbinlog -v SAYHELLO-bin.000096 --start-datetime="2023-03-21 21:47:08" --stop-datetime="2023-03-21 21:50:08"
真实的情况下,我们的日志文件比较复杂,内容比较多使用时间范围查询后任然可能需要花费时间去排查问题,这里我们找到了误删除的位置:
在这里插入图片描述
mysqlbinlog -v SAYHELLO-bin.000096 --stop-position=3972 -v | mysql -uroot -p
报错:ERROR 1007 (HY000) at line 36: Can't create database 'bin_test'; database exists
,因为它会将我们binlogw文件里面的数据再从头执行一遍到3972的位置,所以我们可以先备份数据库,再删除数据库。
恢复成功。
binlog的数据恢复的本质:
binlog的数据恢复的本质就是将之前执行过的sql,从开始到指定位置全部执行一遍,如果报错【当前表已经存在】,就将数据库的表删除,重新恢复。
当然,也可以指定位置/时间段进行恢复。
binlog 有三种格式, 使用变量
binlog_format
查看当前使用的是哪一种:
例子:
我们举一个例子来说明row和statement的区别,在下面的插入语句中我们有一个函数uuid(),如果日志文件仅仅保存sql语句,下一次执行的结果可能不一致,所以Row格式的文件,他保存的是具体哪一行,修改成了什么数据,记录的是数据的变化,不是简单的sql:
#下图是statement格式,uuid()每次执行得到的结果不一样-》结果不一致问题
insert into my_student values (8,UUID(),45,'d');
::: warning Statement和row的优劣:
:::
常见的事件类型有:
一个event的结构如下,我们在恢复数据的时候已经看到了:
rotate event
用于说明下一个binlog文件。二进制日志文件并不是每次写的时候同步到磁盘。
因此当数据库所在操作系统发生宕机时,可能会有最后一部分数据没有写入二进制日志文件中,这给恢复和复制带来了问题。
参数sync_binlog=[N]
表示每写多少次就同步到磁盘:
::: danger 数据库单点部署的问题:
:::
那么我们就可以使用mysql的binlog搭建一个一主多从的mysql集群服务。
这样的服务可以帮助我们异地备份数据、进行读写分离,提高系统的可用性。
环境准备
安装两个mysql,使用vmvare安装两个linux系统就可以:
mysql1(master): 42.192.181.133:3306
mysql2(slave): 124.220.197.17:3306
mysql 配置文件配
mysql1(master): 配置文件设置,开启bin_log(已经开启的可以忽略)且需要配置一个server-id
#mysql master1 config
[mysqld]
server-id = 1 # 节点ID,确保唯一
# log config
log-bin = master-bin #开启mysql的binlog日志功能
mysql2(slave): 需要开启中继日志
[mysqld]
server-id=2
relay-log=mysql-relay-bin
replicate-wild-ignore-table=mysql.%
replicate-wild-ignore-table=sys.%
replicate-wild-ignore-table=information_schema.%
replicate-wild-ignore-table=performance_schema.%
重启两个mysql,让配置生效。
第三步 在master数据库创建复制用户并授权
1.进入master的数据库,为master创建复制用户
CREATE USER 'repl'@'124.220.197.17' IDENTIFIED BY 'Root12345_';
2.赋予该用户复制的权利
grant replication slave on *.* to 'repl'@'124.220.197.17'
FLUSH PRIVILEGES;
3.查看master的状态
show master status;
mysql> show master status;
+------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000005 120| | mysql | |
+------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)
4,配置从库
CHANGE MASTER TO
MASTER_HOST = '42.192.181.133',
MASTER_USER = 'repl',
MASTER_PASSWORD = 'Root12345_',
MASTER_PORT = 3306,
MASTER_LOG_FILE='mysql-bin.000020',
MASTER_LOG_POS=2735,
MASTER_HEARTBEAT_PERIOD = 10000;
# MASTER_LOG_FILE与主库File 保持一致
# MASTER_LOG_POS=120 , #与主库Position 保持一致
解释:MASTER_HEARTBEAT_PERIOD表示心跳的周期。当MASTER_HEARTBEAT_PERIOD时间之内,master没有binlog event发送给slave的时候,就会发送心跳数据给slave。
5.启动从库slave进程
mysql> start slave;
Query OK, 0 rows affected (0.04 sec)
6.查看是否配置成功
show slave status \G;
Slave_IO_Running:从库的IO线程,用来接收master发送的binlog,并将其写入到中继日志relag log
Slave_SQL_Running:从库的SQL线程,用来从relay log中读取并执行binlog。
Slave_IO_Running、Slave_SQL_Running:这两个进程的状态需全部为 YES,只要有一个为 NO,则复制就会停止。
Master_Log_File:要同步的主库的binlog文件名。
Read_Master_Log_Pos:已同步的位置,即同步的 binlog 文件内的字节偏移量,该值会随着主从同步的进行而不断地增长。
Relay_Log_File:从库的中继日志文件,对接收到的主库的 binlog 进行缓冲。从库的SQL线程不断地从 relay log 中读取 binlog 并执行。
Relay_Log_Pos:relay log 中已读取的位置偏移量。
Seconds_Behind_Master: 主从同步延时, 值为 0 为正常情况,正值表示已经出现延迟,数字越大从库落后主库越多。
7.在主库创建一个数据库、创建一张表,执行一些sql语句进行测试。
在配置mysql主从复制的时候可能出现一下错误:
Fatal error: The slave I/O thread stops because master and slave have equal MySQL server UUIDs; these UUIDs must be different for replication to work.
原因
如果你使用了两台虚拟机,一主一从,从库的mysql是直接克隆的。在mysql 5.6的复制引入了uuid的概念,各个复制结构中的server_uuid得保证不一样,但是查看到直接克隆data文件夹后server_uuid是相同的。
解决
找到data文件夹下的auto.cnf文件,修改里面的server_uuid值,保证各个db的server_uuid不一样,重启db即可。
cd /www/server/data
修改server_uuid的值
使用
select uuid();
生成一个uuid即可,重启数据库。