Closed
Description
之前有较多的小伙伴, 反馈在大规模数据DML变更时消费速度有点跟不上, 反馈的问题列表:
- Mysql产生的binlog,大量数据的时候,同步到Canal慢,这个怎么解决? #672
- Canal Server 解析性能问题 #547
- 当数据库有大量的删除时,canal解析变慢 #355
- canal收集 由一条update语句更新多行 产生的binlog的速度很慢 什么原因呢? #267
这里会做一个相对完整的测试,进行针对性的优化,同时也非常欢迎大家的参与和代码MR,一起努力解决好性能和稳定性的问题. ps. 1.0.26会是一个里程碑式的版本。
Metadata
Metadata
Assignees
Type
Projects
Relationships
Development
No branches or pull requests
Activity
zwangbo commentedon Jul 2, 2018
赞赞赞
mjjian0 commentedon Jul 2, 2018
期待ing,期待ing
lcybo commentedon Jul 2, 2018
赞!
我先来抛个砖,说说以前遇到的issue和一些思路:
场景是,使用load backup file的方式灌数据,同时使用canal进行同步。
每个表一个或多个文件,由于每个文件中的行都同属于一张表的同一事件(INSERT),mysql-binlog会merge一定量的行(取决于binlog-row-event-max-size)到同一event。
*单句DML影响到多行数据的情况应该也适用。
压缩的event经过解析为protobuf对象,内存占用急剧膨胀,造成fgc频繁,甚至oom。
在MySQL 5.6的版本,官方默认将binlog-row-event-max-size从1024调高到了8192。
当时我们通过将binlog-row-event-max-size设回1024,问题被绕过。
如果将server/client 的netty3升级为4,用PooledByteBuf应该可以缓解一小部分。但大头还是protobuf这个memory hogs.
lcybo commentedon Jul 3, 2018
补充一下,ringbuffer size被设置为4096。内存是4g.由于load backup file以后就是平稳的正常traffic。因此并不想调整内存或进一步减小ringbuffer
fixed issue #726, 去掉socket receiveBuffer/sendBuffer的设置,影响网络吞吐量
agapple commentedon Jul 3, 2018
第一步网络优化(只做header解析,识别包大小、位点等信息,不做具体的记录级别解析)
结果:默认设置的32k的socket buffer,针对大吞吐量传输时有点过小,去掉了默认设置,让socket自我协调,默认在24c96g的物理机上测试,receiveBuffer协调结果为180k.
调整前后的性能吞吐量对比: 18MB VS 117MB,提供6倍多,socket buffer优化之后基本可以跑满网卡
fixed issue #726 优化时间类型的解析,速度从20MB提升到45MB
agapple commentedon Jul 3, 2018
第二步优化解析的能力,跑了下简单的对象解析(不做protobuf的对象构建),刚开始速度是20MB,主要优化了时间字段的解析上,提升到了45MB.
目前遇到瓶颈了,观察系统的负载cpu最高在1.5核左右,jvm gc主要集中在young区,下一步的优化思路:多线程并行解析,最大化的使用系统负载进行优化
agapple commentedon Jul 3, 2018
第三步整体并发模型设计,按照前面的优化网络和对象解析,瓶颈都在对象的深度解析上,如果要最大化性能,必须得引入并发设计,整体设计思路如下:
基于ringbuffer的并发模型,整个过程会分为4个阶段,多个阶段之间互相隔离和依赖,把最耗瓶颈的解析这块采用多线程的模型进行加速,预计整个优化完成,整个解析可以跑满整个千兆网卡.
ps. 如果各位有万兆网卡的机型,到时候可以也帮忙跑一下效果
agapple commentedon Jul 3, 2018
@lcybo 针对内存占用的问题,你有什么优化建议么?换掉protobuf?
lcybo commentedon Jul 3, 2018
个人一点不成熟的想法:
因为不跨语言,可以用基于protobuf和java的protostuff。
相对来说,优点:
不足的地方:
贴出一些细节:
// Re-use (manage) this buffer to avoid allocating on every serialization
LinkedBuffer buffer = LinkedBuffer.allocate(512);
对比protobuf:
byte[] result = new byte[this.getSerializedSize()];
此外,POJO还可以参考netty的Recycler或其他的对象池,理论上,ringbuffer中event占用Entry对象的峰值就是ObjectPool需要缓存的对象个数。
ProtostuffIOUtil.mergeFrom(protostuff, fooParsed, schema); //fooParsed是可以提供的,反序列化可以从ObjectPool受益。
当然这么做代码会复杂些。
agapple commentedon Jul 3, 2018
byte[]的复用倒是有, 基于ObjectPool的思路以前还真没考虑过, 对象里的各种嵌套结构体也不太一样, 不太理解复用的原理 @lcybo
42 remaining items