26-Maxwell
官网地址:http://maxwells-daemon.io/
Maxwell 是由美国 Zendesk 公司开源,使用 Java 编写的 MySQL 变更数据抓取软件。它会实时监控 Mysql 数据库的数据变更操作(包括 insert、update、delete),并将变更数据以 JSON 的格式发送给 Kafka、Kinesi 等流数据处理平台。
1. Maxwell 工作原理
1.1 MySQL 主从复制
- Master 主库将改变记录写到二进制日志(binary log)中
- Slave 从库向 Master 发送 dump 协议,将 Master 主库的 binary log events 拷贝到它的中继日志(relay log);
- Slave 从库读取并重做中继日志中的事件,将改变的数据同步到自己的数据库。
1.2 MySQL 的 binlog
MySQL 的二进制日志可以说 MySQL 最重要的日志了,它记录了所有的 DDL 和 DML 语句,以事件形式记录,还包含语句所执行的消耗的时间,MySQL 的二进制日志是事务安全型的。一般来说开启二进制日志大概会有 1%的性能损耗。
(1)binlog 有两个最重要的使用场景
- MySQL Replication 在 Master 端开启 binlog,Master 把它的二进制日志传递给 Slaves 来达到主从数据一致的目的。
- 用于数据恢复,通过使用 mysqlbinlog 工具来使恢复数据。
(2)binlog 包括两类文件
- 二进制日志索引文件(文件名后缀为 .index)用于记录所有的二进制文件
- 二进制日志文件(文件名后缀为 .00000*)记录数据库所有的 DDL 和 DML 语句事件
(3)binlog 模式介绍
模式 | 说明 | 补充 | 优点 | 缺点 |
---|---|---|---|---|
statement | 基于语句 | binlog 会记录所有写操作的 SQL 语句,包括 insert、update、delete 等。 | 节省空间 | 有可能造成数据不一致,如 insert 中包含 now() 函数。 |
row | 基于行 | binlog 会记录每次写操作的被操作行记录的变化 | 保持数据的绝对一致性 | 占用较大空间 |
mixed | 混合模式 | 默认是 statement-based,如果 SQL 可能导致数据不一致,就自动切换到 row-based。 | 节省空间,同时兼顾了一定的一致性。 | 还有些极个别情况依旧会造成不一致,另外 statement 和 mixed 对于需要对 binlog 监控的情况都不方便。 |
(4)修改 MySQL 的配置文件 /etc/my.cnf 以开启 binlog
[mysqld]
# 数据库id
server-id=1
# 启动binlog,该参数的值会作为binlog的文件名前缀
log-bin=mysql-bin
# binlog类型,Maxwell要求binlog采用Row-based模式
binlog_format=row
# 启动binlog的数据库,多个数据库需要配置多次该属性
binlog-do-db=gmall
binlog-do-db=test
1.2 Maxwell 工作原理
Maxwell 的工作原理很简单,就是把自己伪装成 MySQL 的一个 Slave,然后以 Slave 的身份假装从 MySQL Master 复制数据。
Maxwell 和 Canal 简单对比:
- Maxwell 没有 Canal server+client 模式,只有一个 server 把数据发送到 MQ 或 Redis。但 Maxwell 有一个亮点功能,就是 Canal 只能抓取最新数据,对已存在的历史数据没有办法处理,而 Maxwell 有一个 bootstrap 功能可以直接引导出完整的历史数据用于初始化,非常好用。
- Canal 支持 HA,Maxwell 不能直接支持 HA,但是它支持断点还原,即错误解决后重启继续上次点儿读取数据(其实就是会 Maxwell 元数据库生成对应的 position 信息,通过记录 binlog 的 position 位点来实现断点还原)。而 Canal 则是单纯的依靠 binlog 的 position 位点记录,解析 binlog 发送到 Kafka 或其他组件。
- Maxwell 只支持 json 格式,而 Canal 如果用 server+client 模式的话,可以自定义格式。
- Maxwell 比 Canal 更加轻量级。使用场景上也相对单一,定位就是 Mysql=>Kafka,部署很方便,适合短时间内项目快速迭代的场景。
2. Maxwell 安装部署
2.1 基础环境
(1)上传 maxwell-1.29.2.tar.gz 到 /opt/software 下并解压到 /opt/module(1.30开始之后的版本要求 JDK11)
(2)开启 MySQL binlog 设置
(3)初始化 Maxwell 元数据库
# 创建一个数据库用于存储Maxwell的元数据
mysql> CREATE DATABASE maxwell;
Query OK, 1 row affected (0.00 sec)
# 创建maxwell用户来操作该数据库
mysql> create user 'maxwell'@'%' identified by 'maxwell';
Query OK, 0 rows affected (0.01 sec)
# 分配maxwell库的所有权限给maxwell用户
mysql> grant all on maxwell.* to 'maxwell'@'%';
Query OK, 0 rows affected (0.00 sec)
# 分配这个账号可以监控其他数据库的权限
mysql> grant select, replication client, replication slave on *.* to 'maxwell'@'%';
Query OK, 0 rows affected (0.00 sec)
# 刷新权限
mysql> flush privileges;
2.2 启动方式
a. 命令行参数
$ bin/maxwell --user='maxwell' --password='maxwell' --host='localhost' --producer=stdout
启动示例:
这个报错的字符集就是我创建 gmall 时候选中的字符集。
错误原因是 Maxwell 不支持 utf8mb3,下载源码打开 StringColumnDef 类:
然后重新打包上传即可。还有点需要注意,这个打包时候环境得是 JDK11。
在这里我只是想简单测试下 Maxwell 使用而已,所以我把 gmall 库删掉重建,字符集选 utf8mb4。但这时候直接重新启动 Maxwell 还是会报错,因为 binlog 中还存有之前那些操作的日志。所以还需要如下两步操作:
- MySQL 命令行执行
RESET MASTER;
(或者把 binlog 日志都删了) - 清空 Maxwell 元数据库中的数据
再启动就没问题了。
b. 配置文件
[root@centos7 maxwell-1.29.2]$ mv config.properties.example config.properties
[root@centos7 maxwell-1.29.2]$ vim config.properties
-----------------------------
log_level=info
producer=kafka
kafka.bootstrap.servers=hadoop102:9092,hadoop103:9092,hadoop104:9092
kafka_topic=maxwell
host=hadoop103
user=maxwell
password=maxwell
-----------------------------
# 前台启动
[root@centos7 maxwell-1.29.2]$ bin/maxwell --config ./config.properties
# 以守护进程方式启动maxwell
[root@centos7 maxwell-1.29.2]$ bin/maxwell --config ./config.properties --daemon
启动后可通过启动 Kafka 消费者观察同步情况:
停止 Maxwell:
[root@centos7 maxwell-1.29.2]$ ps -ef | grep maxwell | grep -v grep | grep maxwell | awk '{print $2}' | xargs kill -9
2.3 启停脚本
maxwell.sh
#!/bin/bash
MAXWELL_HOME=/opt/module/maxwell-1.29.2
status_maxwell(){
result=`ps -ef | grep com.zendesk.maxwell.Maxwell | grep -v grep | wc -l`
return $result
}
start_maxwell(){
status_maxwell
if [[ $? -lt 1 ]]; then
echo "启动Maxwell"
$MAXWELL_HOME/bin/maxwell --config $MAXWELL_HOME/config.properties --daemon
else
echo "Maxwell正在运行"
fi
}
stop_maxwell(){
status_maxwell
if [[ $? -gt 0 ]]; then
echo "停止Maxwell"
ps -ef | grep com.zendesk.maxwell.Maxwell | grep -v grep | awk '{print $2}' | xargs kill -9
else
echo "Maxwell未在运行"
fi
}
case $1 in
start )
start_maxwell
;;
stop )
stop_maxwell
;;
restart )
stop_maxwell
start_maxwell
;;
esac
3. Maxwell 入门案例
3.1 监控 MySQL
a. 输出到 stdout
b. 输出到 kafka
Kafka 主题数据的分区控制
在公司生产环境中,我们一般都会用 Maxwell 监控多个 mysql 库的数据,然后将这些数据发往 Kafka 的一个主题 Topic,并且这个主题也肯定是多分区的,为了提高并发度。那么如何控制这些数据的分区问题,就变得至关重要。
3.2 监控 MySQL 指定表
3.3 历史数据全量同步
我们已经实现了使用 Maxwell 实时增量同步 MySQL 变更数据的功能。但是,有时候只有增量数据是不够的,我们可能需要使用到Mysql数据库中从历史至今的一个完整的数据集。这就需要问哦们在进行增量同步之前,选进行一次历史数据全量同步。这样就能保证得到一个完整的数据库。
【需求】将 test_maxwell 库下的 test2 表的四条数据,全量导入到 Maxwell 控制台进行打印。
a. bootstrap 表记录
Maxwell 进程默认只能监控 mysql 的 binlog 日志的新增及变化的数据,但是 Maxwell 是支持数据初始化的,可以通过修改 Maxwell 的元数据,来对 MySQL 的某张表进行数据初始化,也就是我们常说的全量同步。
(1)修改 Maxwell 的元数据,触发数据初始化机制,在 mysql 的 maxwell 库中 bootstrap 表中插入一条数据,写明需要全量数据的库名和表名。
mysql> insert into maxwell.bootstrap(database_name,table_name) values('test','test_maxwell');
(2)启动 maxwell 进程
[liujiaqi@hadoop102 maxwell-1.29.2]$ bin/maxwell --config config.properties --daemon
logs/MaxwellDaemon.out 查看日志输出:
consumer 消费 maxwell 情况:
(3)当数据全部初始化完成以后,刚刚插入的记录的某些字段会发生变化。
- is_complete 字段从 0 变为 1
- start_at 字段从 null 变为具体时间(数据同步开始时间)
- complete_at 字段从 null 变为具体时间(数据同步结束时间)
b. bootstrap 命令
(1)Maxwell 提供了 bootstrap 功能来进行历史数据的全量同步(前提要有一个已经在运行的 maxwell 程序!)
[liujiaqi@hadoop102 maxwell-1.29.2]$ bin/maxwell-bootstrap --database test --table test_maxwell_bootstrap --config config.properties
connecting to jdbc:mysql://hadoop103:3306/maxwell?allowPublicKeyRetrieval=true&connectTimeout=5000&zeroDateTimeBehavior=convertToNull
[liujiaqi@hadoop102 maxwell-1.29.2]$
(2)查看 consumer 消费 maxwell 情况
- 第一条 type 为 bootstrap-start 和最后一条 type 为 bootstrap-complete 的数据,是 bootstrap 开始和结束的标志,不包含数据,中间的 type 为 bootstrap-insert 的才包含数据。
- 一次 bootstrap 输出的所有记录的 ts 都是相同的,为 bootstrap 开始的时间。
(3)查看 bootstrap 表,已新增一条记录。