一次 Debezium 升级记录

最近做了一个 debezium 流水线升级的工作,遇到了挺多问题,记录一下。 事情的起因是最近几个礼拜我们的多个 postgres 实例遇到了磁盘空间不足的问题,看下来并不是我们数据量很大,而是 WAL 日志占据了很大的空间,有些实例 WAL 占用空间是数据的十倍以上,这显然是不正常的情况。即使凭借我浅显的 postgres 知识,我也很快联想到这大概和我们的 debezium 流水线有关。我们的服务的数据写入量并不大,WAL 正常情况下不会占据很大空间,但开启了主从同步,并且延迟很大的话,WAL 就会积攒起来,毕竟总得存着等从库消费完才能删掉,这应该就是我们的问题。 第一个 postgres 实例出现问题的时候,是个很简单的情况:这是个测试实例,之前有 debezium 从这个实例捕捉变动,后来迁走了。但是,我们忘记了删除 replication slot,于是 WAL 从 debezium 停止开始就一直不停积累,终于磁盘不足了。这很好解决,既然迁走不用了,就删掉 replication slot,然后 WAL 就会被自动清理掉,磁盘占用率也就恢复了。 第二个 postgres 实例出现问题的情况就复杂了一些,这正是前面 debezium 流水线后读的数据库,它显然是在不停消费的,那就没道理 WAL 会不停的积累。因为这是测试库,为了不让数据库因为磁盘满而完全不可用,我先停掉了 debezium 服务,然后删除了 replication slot,就和之前的实例一样,磁盘空间被顺利释放出来。之后我重新开启 debezium 观察,可以发现,WAL 确实会以比较快的速度积攒,估计一两天就会撑满磁盘。然而看 debezium 服务,它看起来是正常工作的,输出的 kafka topic 里可以看到有数据。那这就和之前的问题不一样了,并不是不消费才导致的 WAL 积累。 重新搜索了一下,看了 debezium 的文档,原来这个问题是有详细解释的。简单来说就是,并不是不消费,而是需要同步的库流量太少,而 WAL 是针对整个实例而言的,如果其他库写入量很大,产生的 WAL 就很大,但是需要同步的库很久没有变动,debezium 也就没法记录下来,这样就会导致 WAL 积累。解决的办法文档里也提了,需要用心跳机制来保证 WAL 有变动,这样就不会积累了。那就需要配置 heartbeat.interval.ms 和 heartbeat.action.query 两个参数,前一个是心跳包发送间隔,每次心跳会往 sink 里写一条消息。后一个可以配置一条 SQL,内容是随便的一些写入操作即可,比如更新任意表的一条记录,只要保证他能触发 replication 点的更新即可。于是我就配了这俩,但是……看起来不生效。 ...

December 17, 2022 · GUAN Hao