最近配合调查一次用户恶意投诉事件,除了提供系统日志(nginx日志、程序日志)外还需要提供数据库的日志,因为二进制文件不易篡改,所以通过binlog入手。
什么是 binlog:
MySQL 是一个关系型数据库管理系统,它使用二进制日志来记录数据库的修改操作。这些日志文件称为二进制日志,或简称 “binlog”。
Binlog 文件记录了所有对数据库中的数据进行的修改操作,例如 INSERT、UPDATE 和 DELETE 等。使得管理员能够在数据库出现问题后恢复数据。也可用于在主数据库和从数据库之间同步数据,以及在集群环境中进行数据库备份。
Binlog 有两种格式,分别是:
- Statement-based replication (SBR):记录了每一条执行的SQL语句。
- Row-based replication (RBR) : 记录了每行受到影响的数据。
可以使用 MySQL 的 mysqlbinlog
工具来查看 binlog 文件中的内容,并使用 mysql
客户端来执行 binlog 文件中的语句来恢复数据。
使用 mysqlbinlog
工具查看 binlog 文件中的内容的例子:
查看本地 binlog 文件的内容:
mysqlbinlog /path/to/binlog.000001
查看远程服务器上的 binlog 文件的内容:
mysqlbinlog --host=remote.host --user=username --password=password /path/to/binlog.000001
查看某个时间点之后的 binlog 文件的内容:
mysqlbinlog --start-datetime="2020-01-01 10:00:00" /path/to/binlog.000001
查看某个事务中的 binlog 文件的内容:
mysqlbinlog --start-position=123 --stop-position=456 /path/to/binlog.000001
查看某个事务中的所有语句,在行开头添加事务 ID:
mysqlbinlog --base64-output=decode-rows -v /path/to/binlog.000001
更多用法使用 mysqlbinlog --help
查看。
结果示例:
$ mysqlbinlog /path/to/binlog.000001
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/;
/*!40019 SET @@session.max_insert_delayed_threads=0*/;
/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
DELIMITER /*!*/;
# at 4
#2020-01-01 10:00:00 server id 1 end_log_pos 122 Query thread_id=1 exec_time=0 error_code=0
SET TIMESTAMP=1609459200/*!*/;
BEGIN /*!*/;
# at 122
#2020-01-01 10:00:00 server id 1 end_log_pos 183 Query thread_id=1 exec_time=0 error_code=0
SET TIMESTAMP=1609459200/*!*/;
INSERT INTO test_table (id, name) VALUES (1, 'Test Data')/*!*/;
# at 183
#2020-01-01 10:00:00 server id 1 end_log_pos 215 Query thread_id=1 exec_time=0 error_code=0
SET TIMESTAMP=1609459200/*!*/;
COMMIT/*!*/;
DELIMITER ;
# End of log file
/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=0*/;
binlog2sql
上述示例可能不方便阅读,可以使用工具binlog2sql来查看更适合人类阅读的查询结果。还可以得到原始SQL、回滚SQL、去除主键的INSERT SQL等。
限制(对比mysqlbinlog)
- mysql server必须开启,离线模式下不能解析
- 参数 binlog_row_image 必须为FULL,暂不支持MINIMAL
- 解析速度不如mysqlbinlog
优点(对比mysqlbinlog)
- 纯Python开发,安装与使用都很简单
- 自带flashback、no-primary-key解析模式,无需再装补丁
- flashback模式下,更适合闪回实战
- 解析为标准SQL,方便理解、筛选
- 代码容易改造,可以支持更多个性化解析
binlog2sql 安装
binlog2sql使用python编写,需要先安装python环境,需要的组件有:
- PyMySQL==0.7.11
- wheel==0.29.0
- mysql-replication==0.13
也可以使用下述代码一键安装:
git clone https://github.com/danfengcao/binlog2sql.git && cd binlog2sql
pip install -r requirements.txt
基本用法
解析出标准SQL
python binlog2sql.py -h127.0.0.1 -P3306 -uadmin -p'admin' -dtest -t test3 test4 --start-file='mysql-bin.000002'
输出:
INSERT INTO `test`.`test3`(`addtime`, `data`, `id`) VALUES ('2016-12-10 13:03:38', 'english', 4); #start 570 end 736
UPDATE `test`.`test3` SET `addtime`='2016-12-10 12:00:00', `data`='中文', `id`=3 WHERE `addtime`='2016-12-10 13:03:22' AND `data`='中文' AND `id`=3 LIMIT 1; #start 763 end 954
DELETE FROM `test`.`test3` WHERE `addtime`='2016-12-10 13:03:38' AND `data`='english' AND `id`=4 LIMIT 1; #start 981 end 1147
解析出回滚SQL
python binlog2sql.py --flashback -h127.0.0.1 -P3306 -uadmin -p'admin' -dtest -ttest3 --start-file='mysql-bin.000002' --start-position=763 --stop-position=1147
输出:
INSERT INTO `test`.`test3`(`addtime`, `data`, `id`) VALUES ('2016-12-10 13:03:38', 'english', 4); #start 981 end 1147
UPDATE `test`.`test3` SET `addtime`='2016-12-10 13:03:22', `data`='中文', `id`=3 WHERE `addtime`='2016-12-10 12:00:00' AND `data`='中文' AND `id`=3 LIMIT 1; #start 763 end 954
但mysql binlog并不是默认开启的,mysql server必须以下参数:
[mysqld]
server_id = 1
log_bin = /var/log/mysql/mysql-bin.log
max_binlog_size = 1G
binlog_format = row
binlog_row_image = full
user需要的最小权限集合:
select, super/replication client, replication slave
权限说明
- select:需要读取server端information_schema.COLUMNS表,获取表结构的元信息,拼接成可视化的sql语句
- super/replication client:两个权限都可以,需要执行’SHOW MASTER STATUS’, 获取server端的binlog列表
- replication slave:通过BINLOG_DUMP协议获取binlog内容的权限
建议授权:
GRANT SELECT, REPLICATION SLAVE, REPLICATION CLIENT ON . TO