定时把整表拉出来做对比,会漏掉两次抽取之间改回去的值,表一大也会越来越慢。日志型捕获读的是库已经写下的变更:预写日志、二进制日志或变更流。拿到的是事件。事件可以再送一次,所以下游从一开始就按至少一次来写,而不是按恰好一次来假设。

信封里哪些字段能排序

字段 用它做 不要用它做
操作类型 区分插入、更新、删除、快照 代替来源顺序
来源位置 排序和断点 用到达时间推断
幂等键 认出重复投递 单独做整表去重或排序
前后镜像 生成当前行或历史行 假定快照行也有前镜像

一条事件通常有变更前的行、变更后的行、操作类型、来源位置和事件时间。操作类型四个值就够用:c 表示插入,u 表示更新,d 表示删除,r 表示快照读。来源位置要能比较先后,一般是日志序号,还可以带事务标识,以及当时是不是在做快照。事件时间只表示这条记录何时被观察到。同一键的两行谁该留下,看的是来源位置,不是谁先进入湖里。

推送进表时,可以把信封收成固定九列:目标表、目的地、分区、操作、幂等键、键、值、来源位置、头。值用 JSON 的变体类型或 Protobuf 都可以,但整条链路要选定一种,不要按批次混用。幂等键是目的地、分区、键、操作和来源位置算出来的 SHA-256。它回答这是不是同一条事件。它不排序,也不把同一个业务键折成当前行。

偏移何时才允许向前

接收端要等一段连续的事件已经落稳,才把来源偏移向前拨。后面的确认如果失败,前面那段可能被再次推送。这就是至少一次。连接器可以单独进程把事件推进一张只追加的受管控表,中间不经过消息总线;也可以走带总线的连接器集群。两种部署的交付语义一样,都不能省略下游去重。Debezium 的独立服务和连接器集群就是这两种外形,差别在中间有没有总线,不在会不会重复。

原始层保留事件,重复也留着,方便和来源对账。整理层按幂等键去掉重复,再按来源位置排序。服务层才分叉:只要当前值,就按键合并成一行;要审计历史,就写成带起点和终点的多行。合并仍然要求目标表支持行级更新。只追加的原始表不能直接当当前维度表用。

出站推送只是部署形态

有的网络只允许持有日志的一侧主动向外发,不接受湖仓侧连回去拉。这时用推送,让事件从库侧送出。这是在现有出站规则之内搬数据。账号、库和表的范围仍按来源库原来的审计要求。接收端只接受约定的目的地和分区,不根据事件内容临时改写目标。不要为了这条链路去加一条入站通路。

用三条事件验收

把同一来源位置的事件送两次。整理层应只留一行。仍是两行,就是幂等键没有参与去重。把来源位置更小的旧事件故意晚送到。服务层当前行应保持较新的那条。被旧事件盖掉,就是按到达顺序合并了。单独看一条快照事件,操作类型应是 r。不要把它写成删除,也不要因为它没有前镜像就丢弃。三步都通过,再把当前表和历史表交给下游。只通过去重、没通过乱序的,不要先接报表。

用效率龙虾改这份稿

常见问题 FAQ

幂等键能不能代替来源位置?

不能。幂等键只标识同一条事件,便于去掉重复投递。同一业务键的先后,要用来源日志的位置排序。

为什么不能假设恰好送达一次?

偏移要等一段连续事件落稳才向前。后面的确认失败时,前面已经成功的那段可能再次送来。下游必须能认出重复。

快照事件的操作类型是什么?

是 r,不是插入、更新或删除。快照行常常只有后镜像。不要因为缺少前镜像就丢弃,也不要把它记成删除。

原始层看到重复,算故障吗?

至少一次的设计下,原始层可以有重复。整理层应按幂等键收成一行。服务层才按键合并成当前行或历史行。

只允许出站时,应该让湖仓侧去拉吗?

不改网络规则的前提下,由持有日志的一侧按原有账号把事件推出来。接收端只写约定的目的地,不扩大读取范围。