| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 大数据 -> DM 中 relay log 性能优化实践丨TiDB 工具分享 -> 正文阅读 |
|
[大数据]DM 中 relay log 性能优化实践丨TiDB 工具分享 |
前言 不开启 relay log 时,每个 subtask 都会连接上游数据库拉取 binlog 数据,会对上游数据库造成较大压力,而开启后,只需创建一个连接拉取 binlog 数据到本地,各个 subtask 可读取本地的 relay log 数据。 数据同步延迟相比不开启 relay log 有明显上升,下面的表格是一个单 task 的 benchmark 的测试结果,可看出平均 latency 有明显的增长。下表中以“.”开头的是延迟的百分位数据。 开启 relay 后 CPU 消耗增加。(由于 latency 的增长,在一些简单场景下(比如只有 1 个 task)相比不开启 relay log,资源使用率反而是下降的。但当 task 增多时,开启 relay 的 CPU 消耗就增加了)。 当前 relay 实现 当前 relay 模块可以分为两个部分,relay writer 和 relay reader 部分,其结构如下所示: Relay writer 使用 binlog reader 从上游 MySQL/MariaDB 读取 binlog event; 将读取到的 binlog event 使用 binlog transformer 进行转换; 将转换后的 binlog event 使用 binlog writer 以 relay log file 的形式存储在本地的 relay directory 中。 Relay reader 读取 realy directory 中的 binlog 文件,发送给 syncer; 测试环境说明 上游为 MySQL,版本为 5.7.35-log; 下游为单实例的 TiDB,版本为 5.7.25-TiDB-v5.2.1; DM 使用了 1 个 master 和 1 个 worker Latency 基准测试版本为 2021-10-14 号的 master 分支(commit hash 为 d2dc22d) 较大规模测试(> 4 task)下 MySQL/TiDB/DM 分别运行在一台主机上,主机都是 8 核 16G 测量迁移延迟采用下游自更新时间列的方式,详细参考 多种方式告诉你如何计算DM同步数据到 TiDB 的延时时间 中的第三种方式。 Latency 优化 当前 relay reader 的定时 check 的实现方式本身就会对 latency 有一定影响,在最坏情况下一个 binlog event 至少要延迟 100ms 才能同步到下游; 在内存中缓存 relay writer 在最近一段时间内预备写入的 binlog,如果 relay reader 请求这段 binlog,relay reader 直接从内存读取; 方案 2,我们做了一些初步的测试,在增加 relay reader check 的频率时,开启 relay 基本能达到不开启 relay 时的latency,调研了下 MySQL 的 relay log,发现也是通过读取文件的方式,因此我们选择了方案 2。 实现相对较简单,在 relay writer 增加了 Listener,在有新 binlog event 时通知该 Listener(往 channel 中发送一个消息),然后在 relay reader 中,将定时 check 改为监听 channel 中的消息。 下图是在 4 table 4 task 测试下的 latency 结果,可以看出开启 relay 后的 latency 跟不开启很接近: CPU 优化 使用 golang 自带的 pprof 做了一个 CPU profile,从下图可以看出占比较大的主要是 syncer/relay reader/relay writer 等部分,对比代码逻辑后,发现: Relay reader 使用了 go-mysql 的 ParseFile 接口,该接口每次调用都会重新打开文件,并读取第一个 FORMAT_DESCRIPTION 事件,也就是下图中第一个蓝色标注的位置; 针对上面的问题,我们做了如下优化: 使用 go-mysql 的 ParseReader 来消除重复打开和读取的消耗; 由于我们测试用的 sysbench 产生 write 事件的速率是比较平稳的,DM 中也没有特别的执行代码,而 Golang 是一个编译型带 GC 的语言,因此我们猜测尖刺主要来自于 GC,但是这一点从 CPU profile 并不明显,见下图: 使用 GODEBUG=gctrace=1开启 GC 日志,见下图,可以发现: 开启 relay 后,驻留内存大了接近一倍(239 MB -> 449 MB),Heap 总空间也大了近一倍。 下图是上面优化后做的 heap profile 中 alloc_space 部分的火焰图: 说明:pprof 的 heap profile 是程序运行至今的一个剖析,并不是某一段时间内,所以从下图中也可以看到一些驻留内存的申请。 通过 heap profile 并对比代码,发现了以下可优化的点: Go-mysql 在从文件解析 binlog event 时,每个 event 都会重新申请一个 bytes.Buffer,并在读取过程中不断扩容。优化后改为使用一个 buffer pool,减少不断扩容带来的开销; 下图为在 20 table 20 task 场景下的测试结果: 遗留问题 & 未来工作 go-mysql读文件使用的 io.CopyN,这个函数内部会申请一个小对象,高频使用情况下还是对 GC 有一些影响的,但不大,这次暂时没改; |
|
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/24 10:27:19- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |