Uber 如何在生产环境中真正落地 Kappa 架构?

Uber 核心流处理管道 rider sessionization 从 Lambda 迁移到了 Kappa。本文复盘这次重构,看他们如何用单一代码路径,同时满足下游对低延迟和高准确性的双重诉求。

写在前面:最近读到 Uber 实时处理管道的演进历程,想推荐给大家。这篇文章最打动我的地方,是它把一个 system design 题目从纸面带到了现实。我们准备面试时反复练习"如何设计一个实时数据管道",答案却往往停留在画框图、列组件;而这篇文章呈现的是:当业务方同时要求低延迟和高准确性时,工程师真正纠结的是什么、最后放弃了什么、又如何说服自己和团队接受这个取舍。读完之后,我对"trade-off"这个词的理解比从前具体了很多。所以我们来具体看一下

Uber 原本有什么?

在Uber的底层数据流中, 有一条非常核心的流处理管道: rider sessionization(乘客会话化)。它的作用是把一个乘客的一连串行为(打开 app、查价、下单、取消、评价……)按“一次会话”切分打包。最初这条管道是为 Uber 的动态定价系统服务的,给动态定价模型提供低延迟的建模特征。

很快公司的其他团队发现这个 “session” 的定义非常好用,反欺诈团队、用户行为分析团队、做月度业务报表的数据科学家全都来接入这份数据,把它当成了公司级的 canonical session 数据源。

为什么要升级?

一个管道被这么多团队共用,问题就出现了:不同下游对延迟正确性的要求完全矛盾。

一类下游要快——秒级分析,算错一点、漏一点没关系,反正下一秒会更新;

另一类下游要准——月度业务报表,可以等几天才出,但数据必须完整,漏一条都是 bug。

而流处理天生就是在“快”和“准”之间做取舍的。

事件不会严格按时间顺序到达——乘客可能下次打开 app 才去评价上次的司机,客户端日志可能因为网络几小时后才上传。问题是:流处理要一直往前算,不能永远等下去。所以它必须定一个规矩:

“我等到 9:05 分为止。9:05 之前发生的事件,只要在 9:05 之前到达,我都算进来;9:05 一过,我就认为 9:00 这个时间段的数据已经齐了,开始出结果。之后再有迟到的 9:00 事件进来,对不起,直接丢掉。”

这个“我等到什么时候为止”的截止线,就是所谓的 watermark

这么做的好处是系统永远不卡、延迟可控;代价是迟到的数据会被静默丢弃。对定价、秒级分析这种下游来说,丢一点无所谓,反正下一秒会刷新;但对要出月度报表的下游来说,丢一条就是一条 bug

所以 Uber 需要一条 backfill 管道:过几天之后,回头把当时漏掉、算错的数据重新算一遍。

阅读全文

注册 立即解锁全文并访问全部文章: 网站会员, 成为小万的高级会员 and 海外DE会员 tiers 专享.

订阅
已有账号? 登录

小万和大树知识成长营地

注册成功!

欢迎回来,已成功登录。

你已成功订阅 小万和大树知识成长营地。

成功!请查收登录邮件。

成功!账单信息已更新。

账单信息未更新。