OPED 是 (我自己发起的) One Paper Each Day 挑战, 即每天(偶尔)读一篇 Paper, 领域不限.

这是 OPED 挑战的第七篇, 论文为 One SQL to Rule Them All

最近实际上, 还是读了几篇论文的, 但是感觉都不太值得写 (). 昨天读的这一篇, 感觉可以记录一下.

前段时间, 拜读了一下 Streaming Systems, 对流式系统的理解有深入了一点点. 它把 bounded 和 unbounded 数据源的处理统一的思想, 以及 Table 和 Stream 关系的看法真的还是蛮有意思的. 知乎上有篇文章把这本书吹炸了, 我个人觉得也很不错, 有兴趣的千万读一下 (支持一下正版哟, 正版的 EPUB 格式有一些动图, 对于理解很有帮助).

言归正传. 我感觉这篇论文实际上是 Streaming System 中描述的思想的延伸, 即基于 Table 和 Stream 的关系, 使用 SQL (以及必要的拓展) 来同时做到 Unbounded 和 Bounded Processing.

说了那么多遍 Table 和 Stream 的关系, 它们到底是什么关系呢? Table 就不用解释了, 就是个表嘛. 而表是一个动态的东西, 随着时间的变化, 其中的数据会发生变化, 也就是说, 表实际上是一个函数 Table(t). 表中的数据变化构成了一个 Stream(t). 所以 Stream(t)Table(t) 的导数, Table(t)Stream(t) 的积分. 为了避免混淆, Streaming Systems 这本书中用 TVR (i.e. Time Variable Relation) 来表示 Table(t) 这个函数. 如果再进一步, 你会发现 Stream(t) 实际上也是一个 TVR.

那么 Table 和 Stream 的这种关系怎么能帮助我们使用 SQL 来做到批流统一呢? 我们再想一想, SQL 本质上是定义了一个函数, 这个函数接受若干个表作为参数, 返回了一个新的表. 结合上面的 TVR 这个定义, 我们就会发现, SQL 定义函数, 实际上接受的参数是若干个 TVR, 返回了一个新的 TVR! 一旦接受了这个设定, 你是不是觉得豁然开朗, 打开了新世界的大门?

道理是这个道理, 但是流式处理往往还有很多批处理不会遇到的问题, 主要是:

  1. 如何处理事件时间
  2. 如何持久化结果

事件时间的处理

事件时间的处理在 Streaming System 这本书中已经解释的很详细了, 问题主要是如何使用 SQL 来做到这件事. 事件时间的处理包含了两个部分, 一个是怎么做时间窗口, 另一个是怎么判断一个时间窗口的数据以及全部处理完了.

对于第一个问题, 一个很简单的想法就是, 把事件时间处理一下, 然后 group by 就好了. 为了简化这个过程, 这篇论文提出了在 SQL 中提供一些函数, 能够接受一个 TVR, 返回一个新的 TVR, 在新的 TVR 中会增加新的两列, 分别表示时间窗口的起始和终止.

对于第二个问题, 就需要 Watermark 了, 这个属于实现细节, 在 SQL 层面没有改变, 需要执行引擎的支持.

结果的持久化

对于流式处理任务的结果, 往往有两种使用方式. 一个是每个时间窗口结束之后, 自动将结果持久化, 这和批处理模式下 T+1 的情况类似. 另一个是不断的更新结果, 比如对于 dashboard 这种需求. 这篇论文提议通过扩展 SQL 来支持这两种方式.