← 全部文章

Databricks 多语句事务 GA:用两个客户案例看它到底省了什么

一条赛艇上三名桨手同时向前探身,四支桨叶颜色各不相同,却在同一时刻停在水面上
封面 · 来源: David Trinks / Unsplash
目录
  1. 一次地址变更要写两行,Fivetran 以前怕的是中间那一刻
  2. 每天约 1,700 个理赔事务,Accolade 不用再为它们多养一个仓库
  3. 一个事务从 BEGIN 到 END 走过哪几步
  4. 作者按:省下的是修补代码,上线前还要核对三处

Databricks 10 月 16 日宣布,多语句事务正式可用(GA)。1它 3 月进入公开预览,7这次转正。

它解决的问题,用官方文档里的转账例子最好懂:把 100 从账户 1 转到账户 2,要执行三条语句,账户 1 减 100,账户 2 加 100,审计日志记一笔。2如果每条语句各自提交,第一条成功、第二条执行时作业崩了,账户 1 的 100 已经扣掉,账户 2 却没收到,这 100 就从账上凭空消失了。多语句事务把这三条语句包成一个整体,可以跨多张 Unity Catalog 托管的 Delta 或 Iceberg 表:三条都成功才一起生效;任何一条失败,三条全部撤销,两个账户都回到转账之前。12

数据管道里,这种“几步必须一起成功”的作业到处都是,所以我很看好这个功能。可惜官方博客讲客户时,Fivetran 和 Accolade 各只给了一段引语,没说他们原来怎么做、现在省了什么。下面按场景、以前、现在,把两个案例补完整。

一次地址变更要写两行,Fivetran 以前怕的是中间那一刻

Fivetran 做数据接入的连接器,它的 History Mode 会留下一条记录的每个版本,也就是 SCD Type 2(缓慢变化维度第二型)。1目标表多出三列:_fivetran_start 和 _fivetran_end 记每个版本的起止时间,_fivetran_active 标出当前版本,同一条记录只能有一个是 TRUE。5

假设客户 42 改了地址,目标表要写两次:把旧版本 v1 标成 FALSE,结束时间设成新版本开始前 1 毫秒;再插入新版本 v2 作为当前版本。5

以前。 Fivetran 的产品经理 Egidio Terra 说,过去事务保证只覆盖单条语句,这两步只能分开执行,靠对账逻辑和后续同步里的一致性检查兜底。1中途断掉会怎样,看图 1 上排:先关旧版本、插入失败,客户 42 没有当前版本,“当前客户”视图里查不到他。反过来先插入、关闭失败,他会有两条当前记录,汇总时算两次。这种错要等下一次同步才修好,期间下游报表都是错的。

FIG.1同一次地址变更的两种写法。上排是以前:两条语句各自提交,中途中断时下游会读到半笔数据,要等下次同步才修好。下排是用了多语句事务以后:两步先暂存,END 时一次提交。列名和更新规则来自 Fivetran 文档,客户 42 是示例。

现在(图 1 下排)。 把这条 UPDATE 和那条 INSERT 放进同一个 BEGIN ATOMIC … END,一次变更要么完整写进去,要么完全没写。Fivetran 说,他们因此删掉了一整类“一致性修补”代码。1提交之前,改动只有当前会话看得见,别人读不到中间状态;提交之后,它在表的日志里只算一条记录。23

每天约 1,700 个理赔事务,Accolade 不用再为它们多养一个仓库

Accolade 是一家医疗科技公司。6工程经理 Akshay Ajgaonkar 说,他们每天在生产环境跑大约 1,700 个事务,处理新进来的理赔和负债记录,每次更新都必须可靠、一致;有了多表事务,这些多步操作直接在受治理的湖仓上跑,迁移关键负载也不用另建数据仓库。1原文没说涉及哪些表、以前跑在哪里;客户故事只提到,它的数据过去分散在 Redshift、Snowflake 等多个平台上。6

场景(示意,原文没给表结构)。 一笔理赔进来,至少动三张表:理赔明细加一行,负债表里这位会员的应付余额加上去,处理日志记一笔。月底对账时,明细合计要等于负债余额的变化。

以前(图 2 上排)。 湖仓上每条语句各自提交,明细写进去了、负债没更新,账就差一笔。团队通常二选一:把作业留在支持事务的仓库里,数据多复制一份,权限和审计两边各配一套;或者留在湖仓上,自己写补偿和对账作业。1

FIG.2一笔理赔的两种写法(示意,Accolade 没有公开表结构)。上排是以前:三条语句各自提交,中途中断会让账对不上,只能靠补偿作业或另一个仓库兜底。下排是用了多语句事务以后:三张表一起提交,校验不过就整体回滚。

现在(图 2 下排)。 三条语句放进一个 BEGIN ATOMIC,任何一步失败都整体回滚。业务校验也能放进去:余额算出负数,用 SIGNAL 抛错,前面写的明细一起撤销。23几个理赔批次可以同时写同一张负债表,只要没改到同一位会员的那一行就不冲突;Unity Catalog 的行级安全和列掩码对写入同样生效。1

把数字乘一下:每天 1,700 个,一年约 62 万个。假设分开提交时千分之一会断在中间,一天约 1.7 笔半完成的数据,一年 600 多笔要人去对、去解释。

一个事务从 BEGIN 到 END 走过哪几步

FIG.3非交互式事务(BEGIN ATOMIC)的路径。成功时多张表一起出新版本,任何一步失败都整体回滚。依据 Databricks 的事务文档、教程和 catalog commits 文档整理。

事务第一次读一张表时拍下快照,之后都读这份。2语句的改动先暂存。3能跨表提交,靠的是 catalog commits:原来每张表各管各的提交日志,开启后改由 Unity Catalog 统一协调。4执行时不加锁,提交时才检查有没有人改了同一行或表结构;出错、SIGNAL、冲突、会话断开或超过 48 小时,全部回滚。2

作者按:省下的是修补代码,上线前还要核对三处

参考

  1. Transactions are Generally Available, advancing warehousing on the Lakehouse, Databricks Blog
  2. Transactions, Databricks Documentation
  3. Tutorial: Coordinate transactions across tables, Databricks Documentation
  4. Catalog commits, Databricks Documentation
  5. History mode, Fivetran Documentation
  6. Accolade customer story, Databricks
  7. Transactions on the open lakehouse unlock mission-critical warehousing workloads, Databricks Blog

评论