MySQL流转工具Maxwell的代码改造和优化方法教程

54次阅读
没有评论

共计 3414 个字符,预计需要花费 9 分钟才能阅读完成。

本篇内容介绍了“MySQL 流转工具 Maxwell 的代码改造和优化方法教程”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让丸趣 TV 小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

Maxwell 是开源产品, 相比 Canal 的体量也小很多,综合考虑下,在短期内选择了 Maxwell.

从快速上手到功能支持,算是一个总体支持还不错的产品,也让技术调研和迭代进度进展相对快了很多。

一般说要比较,基本都会拿出这幅图来(数据带有主观特点,仅供参考),因为考虑到 bootstrap 是个硬性需求,所以这部分的功能考量也是一个重要权衡。

最近在做数据库到大数据流转的过程中发现了 Maxwell 的一些问题和改进点:

1)Maxwell 的服务管理模式目前只支持 start 模式,如果要停止只能采用手工 kill 的方式,相对粗暴一些,当然和作者交流,可以使用信号处理的方式来间接实现。

2)Maxwell 的核心配置是对于同步对象的过滤,可以支持正则等模式,如果过滤规则较为复杂,或者后期不断的调整,每次调整都需要重新启动 Maxwell 服务,没有类似 reload 的模式。

3)对于 DDL 变更,如果 Maxwell 的初始化已完成,服务已启动,在后续创建一张表的时候,Maxwell 会把变更记录至 `schemas` 表中维护版本变更记录,在已有的元数据表中 `tables` 和 `columns` 里面就没有这些信息了,对于后端的服务解析表结构会带来一些偏差(DDL 的变更配置会有相应的 JSON)

1. 问题定位

这些问题算起来大多是建议,不算是致命问题,所以整体的进度依然可以继续推进,但是最近在做了几张大表的同步之后发现了一些数据问题。

1)bootstrap 的时间比较长,查看 Maxwell 相关监控,整体的数据吞吐量在 800 条 / 秒左右,好像是达到了整个同步的瓶颈,同步一张 200 多万数据的表需要 1 个小时左右,相对比较长,我们在近期的测试中,几张千万级的大表如果串行初始化,差不多得 2 - 3 个小时,实在是太长了。

2)同步数据的时间字段值存在差异,这也是在中端 (maxwell 规划为中端服务) 和后端 (Flink,Kudu 规划为后端) 在做数据比对中发现的,bootstrap 的数据比对结果几乎没有相同的,也就意味是 bootstrap 在数据方面存在一些潜在问题,所以整个事情轮盘到了 Maxwell 的 bootstrap 部分。

查看代码逻辑,着实让我一惊,这个问题目前仅在 bootstrap 的环节出现,比如数据的时间字段值为:

但是经过逻辑处理后,会有时区的计算,会自动补上时区的差异。

现在的问题已经不是初始化带来的性能隐患,而是数据质量出现了侵入性,导致数据看起来错乱。

对于这个问题,分析的重点就是时区的处理差异,本来想这个改动应该很小,没想到调试和环境集成着实花了不少功夫。

2. 问题修正

对于时区的数据差异,主要在于 datetime 数据类型存在时区差异,目前差距在 13 个小时。

查看 Maxwell 的代码类 SynchronousBootstrapper:

经过调试,需要改动的代码逻辑范围是基于函数 setRowValues:

可以修改为:

改动之后,整个 bootstrap 的逻辑经过调试和反复测试就正常了。

3. 性能问题的取舍和修正

当然在这个之外,也做了一些细小的改进。

第一个问题就是 bootstrap 的性能问题,之前看似乎是有瓶颈,吞吐量在 800 左右就上不去了,对此我做了如下的改进:

1).bootstrap 的一个基本原理就是 select * from xxxx order by id; 这种使用模式,如果表数据量比较大,其实 order  by 的部分看起来是走了主键,该子句会强制走全索引扫描,但是整体的效果反而不是全表扫描,所以我就干脆去除了逻辑中的 order by 子句。

整个逻辑的改造也很轻量:

private ResultSet getAllRows(String databaseName, String tableName, Table table, String whereClause, if ( pk != null   !pk.equals() ) { sql += String.format(  order by %s , pk); }

2). 去除了写入数据后的 sleep 1 毫秒

进一步分析代码,发现 bootstrap 中吞吐量的瓶颈是其中一个诡异的 sleep  1 的处理,根据初步分析,可能考虑到 bootstrap 的任务会产生大量数据,对于带宽和负载压力较大,通过 sleep 的方式能够做到降速,整体可控。

另外对于 bootstrap 的日志统计中会包括同步的数据条数,这个指标值目前的依赖度不高,而且数据校验的工作目前会先停止 Slave 再进行数据比对

性能提升和改进,在 3 - 5 倍左右,所以这个部分的逻辑我们可以根据实际情况取舍,在我们的流传设计中,数据都是基于 Slave 端进行流转的,所以不会对主库造成冲击,改动的这个部分的逻辑也很轻巧,注释掉 sleep(1)即可。

public void performBootstrap(BootstrapTask task, AbstractProducer producer, Long currentSchemaID) throws Exception { producer.push(row); Thread.sleep(1); ++insertedRows;

改动后经过测试和对比,发现性能好了很多,最多的时候能有 6000 多,同样的初始化不到 15 分钟左右就全部搞定了。

这样一些细小的改进也给我们带来了一些成就感,后续的数据同步规模继续扩大,也没有再反馈过数据质量的问题,当然在这个基础上还有一些工作需要细化。

4. 后续对于 bootstrap 方向的改进

1)使用分片的思路来完善 bootstrap

提高数据提取的效率,对于千万级以上的大表数据抽取,可以按照区间分段来提取(需要考虑到数据的变更和写入的影响),目前的逻辑过于僵硬。

private ResultSet getAllRows(String databaseName, String tableName, Table table, String whereClause, Connection connection) throws SQLException { Statement statement = createBatchStatement(connection); String pk = table.getPKString(); String sql = String.format( select * from `%s`.%s , databaseName, tableName); if ( whereClause != null   !whereClause.equals() ) { sql += String.format(  where %s , whereClause); } if ( pk != null   !pk.equals() ) { sql += String.format(  order by %s , pk); } return statement.executeQuery(sql); }

2)数据字典索引优化

Maxwell 数据字典的优化,目前的数据字典中,部分 SQL 执行频率较高,但是从数据库层面来看是全表扫描,这些细节的地方还需要进一步调整。

比如如下的 SQL 语句:

explain select * from bootstrap where is_complete = 0 and client_id =  dts_hb30_130_200_maxwell003  and (started_at is null or started_at  = now()) order by isnull(started_at), started_at asc, id asc;

基于业务场景的改进和调整,也让我们通过真实场景的落地,更好的拥抱开源,并在一定程度上能够回馈和反哺。

“MySQL 流转工具 Maxwell 的代码改造和优化方法教程”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注丸趣 TV 网站,丸趣 TV 小编将为大家输出更多高质量的实用文章!

正文完
 
丸趣
版权声明:本站原创文章,由 丸趣 2023-07-27发表,共计3414字。
转载说明:除特殊说明外本站除技术相关以外文章皆由网络搜集发布,转载请注明出处。
评论(没有评论)