MySQL Binlog 里面记录了每行数据的变更, 开发有时候需要根据这些变更的时间中间值去查问题, 是 bug 导致的, 还是用户操作引发的然而原始 binlog 内容不利于检索, 有段时间使用阿里 RDS 企业版 DMS 数据追踪的功能, 也能完成这个工作, 甚至生成回滚 sql, 后由于收费以及容量不够的缘故, 放弃不用
本文所介绍的就是基于外面开源的各类组件, 整合起来, 达到类似数据追踪的功能 binlog 可视化
功能类似: 10 分钟搭建 MySQL Binlog 分析 + 可视化方案
1. 主要技术
项目地址: github.com/seanlook/ma
docker
使用容器来实现资源的申请和释放, 毕竟这类检索 binlog 内容的需求不多
本文基于阿里云的容器服务
maxwell
从 mysql server 获取 binlog 和字段信息, 组装成 json 流建议先阅读 seanlook.com/2018/01/13/
官网: maxwells-daemon.io/
graylog
代替 ELK 技术栈的日志收集处理展示平台社区版够用, 需要自行安装, 也可以把 graylog 换成 ELK stack
官网: www.graylog.org/
nxlog
nxlog 是用 C 语言写的一个开源日志收集处理软件, 它是一个模块化多线程高性能的日志管理解决方案, 支持多平台
参考: blog.csdn.net/weixin_2947
rabbitmq
一款开源消息队列中间件, 采用 Erlang 语言开发, RabbitMQ 是 AMQP(Advanced Message Queueing Protocol) 的标准实现建议先阅读 seanlook.com/2018/01/06/
你也可以把消息队列换成 kafka
2. 使用说明
2.1 举例
查看 some3 库 2018-01-22 13:00:00 ~ 2018-01-22 13:00:00 之间, 表 t_ecsome_detail 的 binlog 变化, graylog 根据 AMQP 协议从 rabbitmq 取 binlog json 流
提前创建一个 Swarm 容器集群, 名字叫 maxwell
在编排模板里选择 maxwell-graylog-rabbitmq, 创建应用下一步修改编排模板:
(只修改 environment 里面的变量值)
- mysql-binlogsvr:
- image: registry-vpc.cn-hangzhou.aliyuncs.com/workec/mysql_binlogsvr:1.1.3
- volumes:
- - maxwellgraylog_db_data:/var/lib/mysql
- environment:
- DBINSTANCE_ID: rm-bp19t9it7c2998633
- START_TIME: '2018-01-22 13:00:00'
- END_TIME: '2018-01-22 14:00:00'
- ACCESS_ID: LTAIXKHm0v6ob5P4
- ACCESS_SECRET: F7g***************Nll19no
- MYSQL_ROOT_PASSWORD: strongpassword
- maxwell-svr:
- image: registry-vpc.cn-hangzhou.aliyuncs.com/workec/maxwell_graylog:1.1.3
- depends_on:
- - mysql-binlogsvr
- environment:
- producer: rabbitmq
- MYSQL_HOST:
- MYSQL_USER:
- MYSQL_PASSWORD:
- MYSQL_HOST_GIT: db_some_shard3
- include_dbs:
- include_tables: t_ecsome_detail
- include_column_values:
- init_position:
- rabbitmq_host: 10.81.xx.xxx
- rabbitmq_virtual_host: /maxwell
- rabbitmq_user: admin
- rabbitmq_pass: admin
- kafka_server:
- kafka_producer_partition_by: database
- MAXWELL_OPTS:
- volumes:
- - maxwellgraylog_db_data:/var/lib/mysql
- links:
- - mysql-binlogsvr:mysql_binlogsvr
2.2 变量 / 参数说明:
DBINSTANCE_ID
需要分析哪个实例的 binlog 必须提供
ACCESS_ID, ACCESS_SECRET
从 OSS 下载该实例 binlog 的 key, 这个 key 的用户需要 RDS 的读权限必须提供
START_TIME, END_TIME
需要分析 binlog 大致位于哪个时间段请尽可能的精确, 如果时间范围过大, 可能耗时非常久 3 个 binlog 入完 graylog 大约 6 分钟不能保持示例默认的值
如果你想从 MYSQL_HOST 直接在线拉取 binlog, 则不要设置设置 START_TIME 和 END_TIME, 程序会一致从当前位置持续读取
MYSQL_ROOT_PASSWORD
mysql binlogsvr 的 root 的密码默认为 strongpassword
producer
指定 maxwell 产生的 binlog json 流输出到哪里, 完整的支持 file, rabbitmq, kafka
MYSQL_HOST, MYSQL_USER, MYSQL_PASSWORD
它在两种情况下使用:
前面的 START_TIMEEND_TIME 留空, 这里的 MYSQL_HOST 代表的是 maxwell 直接连接的地址, 持续获取 binlogmaxwell 的 schema_database 也在这个库上 (monitor, 用户需要有读写这个 db 的权限)
前面的 START_TIMEEND_TIME 有值, 并且没有设置 MYSQL_HOST_GIT, 那么 MYSQL_HOST 代表的是从这个地址拉取表结构, 相当于 maxwell 的 schema_host 地址 (当然获取 binlog 还是从 mysql_binlogsvr )
- MYSQL_HOST_GIT,
- MYSQL_HOST_GIT_COMMIT
从 git 仓库拉取表结构信息, MYSQL_HOST_GIT 指定仓库里面实例目录名,
MYSQL_HOST_GIT_COMMIT
可以满足指定某个 提交 时候的表机构版本在 START_TIME, END_TIME 有设置的情况下才有效
仓库见: seanlook.com/2016/11/28/
- rabbitmq_host,
- rabbitmq_virtual_host
- , rabbitmq_user, rabbitmq_pass,
- rabbitmq_exchange_type
在 producer=rabbitmq 才有效这些 rabbitmq_xxx 选项, 与 maxwell 配置文件里面的完全相同
过滤选项
- include_dbs, include_tables,
- include_column_values
与 maxwell 配置文件里面的完全相同这里没有列出 exclude_xxx 相关过滤项, 如果要指定, 请使用 MAXWELL_OPTS
exclude_columns, 去除哪些列是值不予展示, 可用于脱敏
支持的值参考 maxwell 的配置文件里面正则说明
kafka_server
在 rabbitmq=kafka 时有效对应 maxwell 的
kafka.bootstrap.servers
选项
其它选项如果要指定, 可以使用 MAXWELL_OPTS
MAXWELL_OPTS
因为现有 environment 变量没有覆盖所有的 maxwell 选项, 所有其它选项可以直接像 maxwell 命令行参数一样, 指定在 MAXWELL_OPTS 里面
创建完后, 可以看到两个容器:
其中 maxwell-svr 在等待 mysql_binlogsvr 就绪:
- maxwell-graylog-rabbitmq-some3_maxwell-svr_1 | 2018-01-26T11:58:08.424411112Z waiting for mysql_binlogsvr prepared
- maxwell-graylog-rabbitmq-some3_maxwell-svr_1 | 2018-01-26T11:58:28.427993770Z waiting for mysql_binlogsvr prepared
- maxwell-graylog-rabbitmq-some3_maxwell-svr_1 | 2018-01-26T11:58:48.431136523Z binlog download is done, wait more seconds for mysql_binlogsvr ready
mysql-binlogsvr 在初始化 mysql server 的数据, 下载 binlog 完成的标志是在
/var/lib / mysql / initialized.lock
里面写入 1 或 2, 来通知 maxwell-svr(1 和 2 的意义见下面的 Dockerfile 说明)
在 maxwell-svr 日志里面看到
INFO BinlogConnectorLifecycleListener - Binlog connected.
字样, 表示已经在 binlog 往外推
此时在 graylog 里面就可以看到输出内容了: graylog.workec.com:3003/search?q=gl
处理速度大概在 10000msg/s, 在 graylog 里面没有看到新数据进来, 就代表分析完成
现在比较麻烦的地方在于, 处理完结束后, 销毁容器容易, 但前面创建的持久存储卷, 阿里云的容器服务并不会删除本地的卷, 它所提供的存储推荐是 OSS,NAS, 云盘 这些存储服务, 然后要为它单独创建子账号, 单独对某个盘 bucket 授权, 十分麻烦
本地卷并不能自动的删除, 如果下次启动这个 binlog 分析服务, 因为挂在的是同样的 db_data, 里面已经有脏数据, 所以需要手动删除 主机上的
rm -rf /var/lib/docker/volumes/maxwellgraylog_db_data/_data/*
2.3 其它编排模板
上面的示例, 是基于
maxwell - graylog - rabbitmq
的编排模板, 已经自定义了一下 compose 模板:
maxwell - graylog - rabbitmq
依赖于外部 rabbitmq server, 需要明确指定 rabbitmq_host 等信息
第一次使用, 通过
rabbitmq-init-for-maxwell.sh
去初始化 maxwell-graylog 所需要的 exchange,queue 等
maxwell - graylog - rabbitmq - nodeps
会比上面的多起一个容器: rabbitmq-server, 但是它的数据要通过容器集群的 LB, 才能被外面的 graylog 服务消费
它的 rabbitmq_host 被指定为
- maxwell - rabbitmq - server
- (container link)
- maxwell - graylog - file
不适用消息队列, 直接写入文件, 通过 nxlog 将数据推到 graylog, 所以会多出一个 nxlog 容器
多出三个 environment variabeles:
graylogserver
nxlog 将日志上报的 graylog server 地址
graylog_maxwell_gelf_port
graylog 节点为接收这个消息监听的端口 (NXlog Outputs)
graylog_maxwell_source_collector
graylog 为这个消息定义好的 collecter 名字 (collecter 是 graylog 的入口, 在它之上定义流转拆解存储等流程)
graylog 的配置方法和搜索使用, 见后文
maxwell - graylog - kafka
使用 kafka 作为消息队列需要指定现有的 kafka_server
这个编排模板, 没有提供很详细的实现, 请结合 MAXWELL_OPTS 使用
提示:
在使用时, 如果容器启动失败, 观察日志后, 一般可以放心的直接重启容器, 已做良好的修复处理
选择哪个模板和设置什么变量值, 主要考虑两个因素: 从哪里获取 binlog,maxwell 将 binlog 生产到哪里
输出到 file,nxlog 读取的交给 graylog 处理的压力会非常大, 可能会导致 graylog 响应慢输出到 rabbitmq, 可以控制流入 graylog 的速度 (Allow throttling this input?)
2.4 docker-compose.yml
阿里云的编排模板, 与标准的 docker compose 并不完全一样在 docker-compose 目录中, 提供了 6 种编排方案, 可使用自建的 docker 平台来做
4 个容器和变量的组合, 应对不同的场景:
docker-compose.file.yml
启动 mysql-binlogsvr, maxwell-svr, nxlog-svr 三个容器, binlog 数据写入 file
docker-compose.file-schema.yml
启动 mysql-binlogsvr, maxwell-svr, nxlog-svr 三个容器, binlog 数据写入 file
表结构从 schema_host 获取, 而不是 git 仓库 monitor 用户需要 REPLICATION SLAVE, REPLICATION CLIENT 权限
docker-compose.rabbitmq.yml
启动 mysql-binlogsvr, maxwell-svr 两个容器, binlog 数据写入现有 rabbitmq
docker-compose.rabbitmq-nodeps.yml
启动 mysql-binlogsvr, maxwell-svr, rabbitmq-server 三个容器, binlog 数据写入 rabbitmq 容器
不依赖外部 rabbitmq
docker-compose.rabbitmq-nobinlog-svr.yml
启动 mysql-binlogsvr, maxwell-svr, rabbitmq-server 三个容器, binlog 数据写入 rabbitmq 容器
mysql-binlogsvr 启动后会停止, 这里直接从 MYSQL_HOST 在线持续拉取 binlog, 用户需要能够读取表结构的权限
docker-compose.kafka.yml
启动 mysql-binlogsvr, maxwell-svr 两个容器, binlog 数据写入现有 kafka
也可以逐个启动容器, 不适用 docker-compose.yml 各个容器详情见后文
3. graylog 配置和使用
生成的 binlog json 流要在 graylog 里面可视化展示, 还需要对 graylog 设置下面分别以 file 和 rabbitmq 的输出为例
3.1 Input: file
上面已经通过 maxwell 容器 将数据写入了 output_file=
/var/lib / mysql / maxwell_binlog_stream.json.log
, 又通过 nxlog 容器 tail 监控这个日志文件
创建一个 GELF TCP Input
[System / Inputs] -> [Inputs]
勾选 Global 表示所有的 graylog 集群节点, 都可以接收这个日志, Port:
12201
便是监听的端口前文编排模板里面要求提供的参数 graylogserver 和
graylog_maxwell_gelf_port
, 就是从这来的
那么 Collecter
graylog_maxwell_source_collector
呢, 可以任意设置一个字符串在标准的 graylog 配置流程里面, collecter 就是一个 nxlog 进程, 一般一台机器就一个 nxlog, 所以 collecter 对应的其实是收集日志的机器
nxlog 是一个单独的组件, 与 graylog 没多大关系, 而为了将两者整合在一起, 需要 graylog-sidecar 来下发 nxlog 的配置, 告诉它日志目录在哪怎么读取日志
所以我们的 docker 容器只需要 nxlog 进程, 不需要 graylog-sidecar 来交代配置, 也就不需要在 graylog web 界面配置 NXLog Outputs/Inputs, 而是直接通过变量传递来完成 nxlog.conf 模板的配置
下面的过程实际是不需要的, 只是为了理解如何生成 nxlog.conf
Create configuration
给这个 configuration 设置 tags 例如 maxwell_binlog
graylog-sidecar 会把 tag 打给某个机器 (collecter), 告诉 nxlog 或其他收集组件, 当前机器有哪几种日志需要收集
编写 NXLog Outputs
相当于 nxlog.conf 中 <Output > 部分, HostPort 即第 1 步里面的 graylog 接收 binlog json 流而监听的地址和端口
Type 选择
[NXLog] GELF TCP output
编写 NXLog Inputs
相当于 nxlog.conf 中 <Input > 部分, 这里指定日志输入来源于文件, Type 选择 [NXLog]file input
Forward to 设置刚才创建的 Output
File, 要收集的日志路径为
/var/lib / mysql / maxwell_binlog_stream.json.log
Pool Interval, 即检查日志文件的间隔时间剩下的保持默认
使用 JSON extractor 解析 message
经过上面几步, 启动 maxwell 和 nxlog 服务 / 容器之后, 在 graylog 的 WebUI 上找到第 1 步建的 Input, 就可以看到有日志进来了
选择任意一个 message,[Create extractor for field message] -> [JSON], 将 json 数据解压出来, 存储, 便可以快速根据字段名来搜索 binlog 内容
3.2 Input: rabbitmq
使用 rabbitmq 更简单, 不需要 nxlog, 直接在第 1 步里, 把新建 GELF TCP 改成 Raw/Plaintext AMQP
需要填写的就是 AMQP 协议里 broker, port, user, exchange, queue, routing_key
就可以在 binlog 里面, 可视化看到 binlog 内容了
3.3 在 graylog 里面搜索 binlog 日志
搜索语法: docs.graylog.org/en/2.4/page
例如, 查看 t_ecsome_detail 表中 f_some_id=1242036566 在给定时间内的变化过程:
gl2_source_input: 5a38cc9bd56c001305aaefc0 AND data_f_some_id: 1242036566 OR old_f_some_id: 1242036566
例如使用 Quick values 功能, 快速得到全国各地区对 t_ecsome_detail 表的操作量:
gl2_source_input: 5a38cc9bd56c001305aaefc0 AND NOT data_f_company_region: 0
我们有做 db 分库, 查看各个分库下的请求量数据是不是平均的, database: quick value:
4. 容器镜像说明: Dockerfile
本节是关于细节实现的部分, 与上面的介绍会略有重复
4.1 Dockerfile.binlogsvr
承载 binlog 的 mysql server 服务
它首先根据提供的数据库实例信息日期时间信息, 去 OSS 拉取已经上传的 binlog 到本地, 修改 mysql-bin.index 文件, 提供 binlog 来源
因为容器停止或者销毁后, 内部的数据也随之丢失, 所以需要一个主机上的目录来挂在到容器中, 做数据的持久化, 我们把这个数据卷命名为 db_data
binlogsvr - entrypoint.sh
容器入口因为 mysql server 启动第一次都要进行初始化, 假如容器启动失败, 再次启动时不需要再次初始化
脚本内通过
lockfile = /var/lib / mysql / initialized.lock
区分三种工作模式:
lockfile 存在: mysql server 已经初始化
lockfile 内容为 0:mysql server 作为 binlogsvr
lockfile 内容为 2: binlog 已经下载完成避免重启容器导致重复下载 binlog
lockfile 内容为 1: 该容器无用, 因为判断 START_TIME 和 END_TIME 为空实际上表示后续 maxwell 拉取, 是直接从原 MYSQL_HOST 读取, 不需要该 binlogsvr
lockfile 里面的值会被 maxwell 容器读取, 以便决定工作模式
download_binlog.py
从阿里 OSS 下载 binlog, 需要提供 DBINSTANCE_ID 和 时间界限
requirements.txt:python 环境依赖
mysql_3306.cnf
binlogsvr 的启动配置文件
4.2 Dockerfile.maxwell
maxwell 服务容器, 主版本 1.12.0, 加上修改了点内容: github.com/seanlook/ma
maxwell - entrypoint.sh
容器入口会等待 mysql_binlogsvr 初始化完成, maxwell 的结构 postion 等信息存放在 binlogsvr 的 monitor 库
work_mode=1: 直接从 MYSQL_HOST 拉取 binlog, 不需要 binlogsvr, 可以实现持续读取现网的 binlog
work_mode=0: 从 mysql_binlogsvr 拉取 binlog
该模式下因为 binlogsvr 里并没有 maxwell 需要的表结构, 支持两种方法:
如果设置了 MYSQL_HOST_GIT, 表示从我们的 git 仓库里面拉取表结构
否则从 MYSQL_HOST 拉取表结构, 对应 maxwell 变量 schema_host 即这个时候的 MYSQL_HOST 不是指定 binlog 来源, 而是表结构来源
如果都没设置, 异常退出
maxwell 启动时需要指定 init_position, 即从 binlog_svr 哪个 binlog 位置开始拉取:
如果从直接从原数据库实例拉取, 则指定为最新的 binlog 起始点;
如果为 binlogsvr 拉取, 则指定为下载的 binlog 最小的那个 binlog 起始点;
在容器启动的时候, 也可以直接指定 init_postion , 优先生效
lockfile = /var/lib / mysql / initialized_maxwell.lock
表示已经通过 init_postion 启动, 如果重启 maxwell 容器, 应该从上次停止的地方继续
容器启动时, 可以指定 producer 为 file, rabbitmq, kafka, 根据对应的生产者, 应该设置子选项见后文
maxwell - retrive - tablemeta.sh
从 git 拉取所需要的表结构, 并用 myloader 工具导入到 binlogsvr
因为考虑到需求通常要过滤表, 所以这里也这会在 binlogsvr 创建需要的表结构
如果指定了
MYSQL_HOST_GIT_COMMIT
, 可以拉取 git 上历史表结构
id_rsa: 文件是拉起表结构用的 ssh key
- maxwell - src - 1.12.0.tar.gz
- :
已下载的 maxwell 包, 会通过 maven 编译
4.3 Dockerfile.nxlog
在 producer=file 时, maxwell 产生的 binlog stream 是文件, 要把文件放到 graylog 用到 nxlog
它也会挂在 db_data, 读取
output_file = /var/lib / mysql / maxwell_binlog_stream.json.log
内容, 发送到 graylog server
graylogserver: graylog server 地址
graylog_maxwell_gelf_port
: 在 graylog 提前配置好的接收 maxwell 数据的端口
graylog_maxwell_source_collector
: 对应 graylog 的 collector id.
配置 graylog 方法见后文
nxlog - entrypoint.sh
容器入口主要是对 /etc/nxlog/nxlog.conf 进行变量替换
提示: 也会读取
/var/lib / mysql / maxwell_instance_id
里面由 mysql_binlogsvr 传递过来的 instance_id 作为 message 的一部分
nxlog.conf
nxlog 的配置文件模板, 用于替换成上面的变量
4.4 Dockerfile.rabbitmq
在 producer=rabbitmq 时, maxwell 需要 rabbitmq server 作为队列
这里提供两种使用方法:
如果已经有现成的 rabbitmq , 则自己创建 vhost, exchange, user, 需要提供的内容见
rabbitmq - init - formaxwell.sh
如果没有 rabbitmq, 则通过这个 Dockerfile 创建 rabbitmq server container
rabbitmq - entrypoint.sh
容器入口只是为了调用
rabbitmq - init - formaxwell.sh
, 在 rabbitmq 起来后, 创建
- --vhost = /maxwell --username=admin --password=admin/
- ,
- exchange = maxwell.binlog queue = maxwell_binlog binding_key = #
给 maxwell 和 graylog 使用
在后台通过 wait-for-it.sh 来同步等待 rabbitmq ok.
- 4.5 build image
- docker build -f Dockerfile.binlogsvr . -t registry-vpc.cn-hangzhou.aliyuncs.com/workec/mysql_binlogsvr:1.1.3
- docker build -f Dockerfile.maxwell . -t registry-vpc.cn-hangzhou.aliyuncs.com/workec/maxwell_graylog:1.1.3
- docker build -f Dockerfile.nxlog . -t registry-vpc.cn-hangzhou.aliyuncs.com/workec/maxwell_nxlog:0.4.3
- docker build -f Dockerfile.rabbitmq . -t registry-vpc.cn-hangzhou.aliyuncs.com/workec/maxwell_rabbitmq:0.4.3
- docker push registry-vpc.cn-hangzhou.aliyuncs.com/workec/mysql_binlogsvr:1.1.3
- docker push registry-vpc.cn-hangzhou.aliyuncs.com/workec/maxwell_graylog:1.1.3
- docker push registry-vpc.cn-hangzhou.aliyuncs.com/workec/maxwell_nxlog:0.4.3
- docker push registry-vpc.cn-hangzhou.aliyuncs.com/workec/maxwell_rabbitmq:0.4.3
参考
原文连接地址: seanlook.com/2018/01/25/
来源: https://juejin.im/entry/5a7ac5ff6fb9a063395c5817