增量同步靠订阅日志来做,位点管不好就会漏掉一段
库里的数据变了,下游要跟着变。省事的办法是订阅操作日志,把每一次改动按顺序读出来,再写到目标端。这条链路看着简单,真正难的是记住自己读到哪儿了。一、日志里有什么
日志按提交顺序记录每一行的变化,插入、修改、删除都在里面,带着表名、主键和改动前后的值。它本来是为恢复和复制设计的,拿来做同步,等于借了一条现成的路。它记录的是提交之后的结果,回滚掉的事务不会留在里面。也正因为如此,读日志比定时扫表更贴近真实,扫表只看到收尾时的样子,中间的修改全丢了。
读日志要按顺序。跳着读会丢上下文,同一个主键的两次修改,顺序反了结果就错。所以订阅端一般只维护一个消费位点,多条链路各记各的。同一条日志被两个任务重复消费的情况要避免,各自的位点存在各自的表里,别共用一份记录,否则一个任务跑快了,另一个再启动时就找不到自己该从哪儿接着读。同步链路上任何一段变慢,到头来都会表现在数据的新旧上,所以每一段都要有耗时记录。
二、位点存在哪里
位点就是已经处理到哪一条。存在内存里,进程一重启就没了;存在本地文件,换台机器就找不到;存在目标库的一张表里,跟业务数据一起提交,稳妥。位点表别放到另一套实例上,那样提交就失去了共同成败的意义,出问题时还是会出现数据与位点对不上。
存在目标库的好处是能一起成败:数据和位点在同一个事务里落下去,不会出现数据写了、位点没更新,重启之后重复处理一遍的情况。位点表要定期备份,重建下游的时候,只有它能说明读到哪儿了,其余的地方都不可靠。订阅日志之前先确认库的日志格式和保留时长,保留太短,停机一段时间就追不回来了。
三、重复和漏读
多数订阅工具确保至少一次,也就是可能重复,但不该漏。重复可以用幂等消化掉,同一个主键按后面的值覆盖就行。漏读就麻烦了,只能靠对账去找。对账的频率按业务的重要程度定,重要的表按天,次要的表按周,别指望一次就把所有问题都捞出来。
漏读常见于位点更新太早。先把位点往前挪,再去处理数据,中间出一次错就永远丢了那一段。顺序必须是先处理、后记位点,反过来就是给自己挖坑。写代码的时候把处理数据和更新位点放在同一个事务里,别一个在数据库、一个在缓存,中间断了没有人知道。
四、大事务和长事务
一个事务写了几万行,日志里就是连续的一大段。订阅端要么整段读完再提交,要么分批提交但记住事务边界。处理不当,重启之后会重复写一半。判断事务边界靠日志里的标记,别靠时间间隔去猜,猜错了就是把两个事务当成一个,后面的顺序全乱。
长事务更麻烦,它一直不提交,日志里的位置就卡在那儿不动。下游看到的是延迟越来越大,可上游根本没出错。这种情况要先找出那个长事务,再谈优化。找的办法是查当前还在执行的事务,看开始时间,超过几分钟的就挨个问清楚在做什么。
五、追平怎么判断
看位点和日志末尾的距离,换算成时间。落后几秒是正常波动,落后几分钟就要查。光看条数不准,因为每条之间的间隔并不一样。换算的方法是用近一分钟的日志量估出每秒条数,再拿落后的字节数去除,误差落在业务能接受的范围内就够用。
追平的速度也要看。上游每秒写一千条,下游只能处理八百条,那永远追不上。这时候要么加并发,要么把每条的处理开销降下来。降开销比较直接的是把逐条查询换成批量查询,一次拿一批主键,往返次数少下来,速度就上去了。
六、怎么监控
三个数:当前位点、日志末尾位置、每条处理的耗时。前两个算延迟,第三个算能力。三个放在一张图上,是堵了还是慢了,一眼能看出来。报警的阈值按业务能容忍的旧数据时间来定,不要照抄别人的五分钟,有的业务五秒就嫌久。
再加一个业务侧的核对:抽几张表比条数和更新时间。技术指标正常但业务数据不对,说明中间那层转换逻辑出了问题。
订阅日志这条路,可靠性和复杂度是绑在一起的。位点、幂等、对账这三样做实了,剩下的就是调优。 虽然有些地方不太懂,但整体看完还是收获很多,慢慢消化一下。 感谢楼主愿意花时间分享,让我们这些后来者能少踩很多坑。 经验很宝贵,尤其是亲身实践过的总结,比网上随便找的靠谱多了。 很多建议都很接地气,能直接用在生活或工作中,实用性很强。
页:
[1]