26-Maxwell

发布时间 2023-08-07 23:45:03作者: tree6x7

官网地址: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 有两个最重要的使用场景

  1. MySQL Replication 在 Master 端开启 binlog,Master 把它的二进制日志传递给 Slaves 来达到主从数据一致的目的。
  2. 用于数据恢复,通过使用 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 中还存有之前那些操作的日志。所以还需要如下两步操作:

  1. MySQL 命令行执行 RESET MASTER;(或者把 binlog 日志都删了)
  2. 清空 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 表,已新增一条记录。