一、现象
每天夜里12点准时出现延迟告警,查看canal的监控指标,delay指标延迟在5-10分钟,blocking指标中的sink、dump趋于100%,同时canal服务的cpu及memeory很稳定40%左右。
二、分析
被告警吵的实在受不了了,于是下定决心解决这个问题。首先花了点时间研究了一下canal源码,整个canal的解析流程大致分成4步。
binlog dump -- parse -- sink -- kafka(rocketmq)
目前从指标分析,dump及sink都阻塞了,所以判断出是发送kafka能力没跟上,(出问题的canal是kafka模式启动的)。
三、调优的过程
找到可能的原因之后,就开始仔细地看了一下canal的kafka发送逻辑。在这个过程中,看到了kafka的几个参数,canal的默认值如下
1、kafka.acks = all,这里的ack有3个选项,0、1、all 。all是要等topic的某个分区的所有副本都同步完数据后才会给客户端响应,1只要topic的leader分区接收到数据就会给客户端响应,0是只要数据发出去了会立即返回,不会等待分区是否接收到数据。因此,首先我把这个值改成了1,为什么选择改成1,是因为1在kafka集群稳定的情况下是能够保证binlog的顺序性的。
结果:改完之后,发现效果不明显,依然有延迟(卒)
2、kafka.batch.size, 这个值是控制kafka批量消息的大小的,默认是16384 (16K),这里要更具实际的binlog event对象的值合理修改,这个值的修改我也是观察了好久数据才定位到问题的。我们的event对象大小是45K,所以默认的16K压根就没起到批量发送的作用,没解析一个event对象就会发送,导致吞吐量上不去,于是我改成了 921600 (900K),注意这个值不能超过broker端的最大发送字节(message.max.bytes)
结果:改完之后,发现效果不明显,依然有延迟(卒)
3、kafka.linger.ms,批量发送消息的最大等待时长,这里我改成了100,需要自己判断
结果:改完之后,效果依然不明显,延迟依旧(卒)
到这里就有点抓狂了,因为只能在夜里验证,一等就是一天,修改这些值已经搞了快一周了,老板一直催要结果。害,只能接着观察数据,接着干。
4、canal.mq.canalBatchSize,最后终于找到了这个参数,这个参数不是kafka相关的,这个是从环形队列中批量处理的event数量,本来我以为这个是指的event数量,结果看完源码才发现,canal的内存队列是通过内存大小限制的,默认这个值是50,其实不是拿50个event对象,而是拿50K的数量,如果event很大,每次就只取很少的量,我的event 45K,所以每次都只取一个对象,更本没法提高吞吐量。根据高峰期的写入峰值,峰值大概3M/s,于是我把这个canal.mq.canalBatchSize设置成了4500,也就是(4500K)。
当晚就怀着一颗激动地心,眼睛一眨不眨地盯着canal监控。下面是监控截图。3307是优化了的,其他几个没有优化。
3307的blocking明显降低
3307的delay明显降低
完美,竣工,睡觉!