怎么避免从删库到跑路 -- 详解 mysql binlog 的配置与使用
1. 引言
使用数据库的时候,我们每个操作都十分小心,尤其是不能直接在数据库上执行 update、delete 等操作,否则万一忘记加全 where 条件,可能就会造成无法挽回的结果。
有一句十分流行的调侃 – “从删库到跑路”就很形象的说明了误操作后的结果,那么如果你真的不小心执行了删库操作,真的就无法挽回了吗?
当然不会了,通常对于线上数据库,我们都会定时冷备,dump 导出数据库的全量备份,并且保留一段时间内的所有修改日志,进而实现在必要时回滚到这段时间内的任何一秒。
这里提到的“日志”指的就是 binlog,那么究竟什么是 binlog 呢?本文我们就来详细介绍一下。
2. binlog
binlog 即二进制日志,他记录了引起或可能引起数据库改变事件,包括事件发生的时间、开始位置、结束位置等信息,select、show 等查询语句不会引起数据库改变,因此不会被记录在 binlog 中。
对于事务的执行,只有事务提交时才会一次性写入 binlog,对于非事务操作,则每次语句执行成功后都会直接写入 binlog。
因此,基于 binlog,我们可以看到每一次对数据库的修改是在何时以何种方式执行的,从而可以实现对任意条操作的回滚,当然。
众所周知,mysql 的主从同步机制也是依赖 binlog 来实现的,binlog 让从数据库可以精准还原主库的每一个操作。
此前的文章中,我们已经介绍了如何搭建一个分布式 mysql 主从集群:
MySQL 分布式主从读写分离架构及实战
3. binlog 相关配置
mysql 默认是不开启 binlog 的,可以在启动时通过 --log-bin=[on|off|file_name] 参数来指定是否开启 binlog。
如果没有给定file_name,则默认为datadir下的主机名加"-bin",并在后面跟上一串数字表示日志序列号,如果给定的日志文件中包含了后缀(logname.suffix)将忽略后缀部分。
也可以通过在配置文件中配置下列选项来开启 binlog 及相关配置:
[mysqld]
server_id = 1234
binlog_format = MIXED // binlog 日志格式
log_bin = /data/mysql/mysql-bin.log // binlog日志文件
expire_logs_days = 7 // binlog过期清理时间
max_binlog_size = 100m // binlog每个日志文件大小,默认为 1G
binlog_cache_size = 4m // binlog缓存大小
max_binlog_cache_size = 512m // 最大binlog缓存大小
binlog_do_db = techlog // 指定需要记录 binlog 的数据库
binlog_ignore_db = test // 指定忽略记录 binlog 的数据库
mysql 官方测试表明,开启 binlog 后,因记录 binlog 造成的性能损耗小于 1%,所以为了数据安全,强烈建议开启 binlog。
且二进制目的是为了恢复定点数据库和主从复制,所以出于安全和功能考虑,极不建议将二进制日志和datadir放在同一磁盘上。
4. binlog 日志格式
上面的配置项中,有一项是 binlog_format,他指定了 binlog 的日志格式,有以下三个选项可选。
4.1. STATEMENT 模式(SBR)
mysql binlog 的默认格式。
在这个模式下,binlog 只会记录可能引起数据变更的 sql 语句。
4.1.1. 优点
这个模式下,因为没有记录实际的数据,所以日志量和 IO 都消耗很低,性能是最优的。
4.1.2. 缺点
但有些操作并不是确定的,比如 uuid() 函数会随机产生唯一标识,当依赖 binlog 回放时,该操作生成的数据与原数据必然是不同的,此时可能造成无法预料的后果。
由于所有的操作都依赖于先后顺序,所以像使用 AUTO_INCREMENT 生成主键 id 的 insert 方法、数据的恢复等都必须串行执行。
4.2. ROW 模式(RBR)
在该模式下,binlog 会记录每次操作的源数据与修改后的目标数据,而不会记录 sql 语句,从 mysql 5.6.2 版本开始,你可以通过在配置文件中指定 binlog_rows_query_log_events 配置项为 0 或 1 来决定是否同时记录 sql 语句。
但对于 GRANT,REVOKE,SET PASSWORD 等管理语句仍然是以 SBR 方式来进行记录的。
4.2.1. 优点
他的主要优势在于可以绝对精准的还原,从而保证了数据的安全与可靠。
并且复制和数据恢复过程可以是并发进行的。
4.2.2. 缺点
该模式最大的缺点在于 binlog 体积会非常大,同时,对于修改记录多、字段长度大的操作来说,RBR 记录时性能消耗会很严重。
同时,由于数据是通过二进制方式记录,无法直观的看到 binlog 究竟记录了什么信息。
4.3. MIXED 模式(MBR)
顾名思义,MIXED 模式是对上述两种模式的混合使用,对于绝大部分操作,都使用 SBR 来进行 binlog 的记录,只有以下操作使用 RBR 来实现:
- 表的存储引擎为 NDB
- 使用了uuid()、user()、current_user()、found_rows()、row_count()、sysdate() 等不确定函数(now() 函数仍然会以 SBR 方式记录)
- 使用了 insert delay 语句
- 使用了临时表
5. binlog 的查看
5.1. 基本信息的查看 – show 命令
通过 show 命令可以查看 mysql 的对应信息。
5.1.1. 查看 binlog 基本信息
show master status
这个命令实现了当前记录的日志文件、偏移量等信息。
5.1.2. 查看有哪些 binlog 日志
show binary logs
show master logs
上述两个命令是完全一样的,他显示了目前存在哪些具体的 binlog 文件。
5.1.3. 查看 binlog 中记录的详情信息
SHOW BINLOG EVENTS [IN ‘log_name’] [FROM pos]
这个命令查询了 binlog 中记录的具体信息。
5.2. mysql binlog 管理工具 – mysqlbinlog
mysqlbinlog [option] log-file1 log-file2…
-d,–database=name:只查看指定数据库的日志操作
-o,–offset=#:展示的起始偏移
-r,–result-file=name:将输出的日志信息输出到指定的文件中,使用重定向也一样可以。
-s,–short-form:显示简单格式的日志,只记录一些普通的语句,会省略掉一些额外的信息如位置信息和时间信息以及基于行的日志。可以用来调试,生产环境千万不可使用
–set-charset=char_name:在输出日志信息到文件中时,在文件第一行加上set names char_name
–start-datetime,–stop-datetime:指定输出开始时间和结束时间内的所有日志信息
–start-position=#,–stop-position=#:指定输出开始位置和结束位置内的所有日志信息
-v,-vv:显示更详细信息,基于row的日志默认不会显示出来,此时使用-v或-vv可以查看
通过 mysqlbinlog 工具,我们可以详细分析 binlog 中的所有信息。
6. 清理 binlog
6.1. 删除全部日志
reset master
这个命令会删除所有 binlog,并让日志文件从 000001 开始重新记录和生成。
6.2. 删除指定日志/时间前的所有日志
有时由于 binlog 占用磁盘空间过大,我们会希望只保留最近的几个文件或指定日期后的文件。
通过下面的命令就可以实现了:
purge master logs to ‘filename’
purge master logs before ‘yyyy-mm-dd hh:mi:ss’
6.2.1. 清理指定文件之前的所有 binlog 文件
purge master logs to "mysql-bin.000006"
6.2.2. 清理指定时间前的所有 binlog 文件记录
purge master logs before ‘2019-03-29 07:36:40’
7. 通过 binlog 定点还原数据库
我们开启 binlog 一个十分重要的目的是为了能够随时还原和回滚到近期某个时间节点。
通常,我们会每隔一段时间全量备份一次数据库,而在两次备份之间,则使用 binlog 提供精准的定点回滚功能。
首先,清空数据库,导入上一次备份,然后执行:
mysqlbinlog --stop-datetime="2019-07-02 15:27:48" /tmp/mysql-bin.000008 | mysql -u user -p password
于是,数据库成功回滚到 2019-07-02 15:27:48 时刻。
8. 微信公众号
9. 参考资料
https://www.cnblogs.com/f-ck-need-u/p/9001061.html#blog5。
https://zixuephp.net/article-440.html。
https://www.cnblogs.com/langtianya/p/5504774.html。