本文由 网易云 发布。sql
做者:周思华数据库
本篇文章仅限内部分享,如需转载,请联系网易获取受权。缓存
本文尝试描述Beam模型和Stream & Table理论间的关系(前者描述于数据流模型论文、the-world-beyond-batch-streaming101和the-world-beyond-batch-streaming-102,后者被MartinKleppmann和JayKreps推广)。事实证实,Steam & Tables理论对描述Beam模型的底层基础观点具备启发性意义。此外,考虑稳健的流处理概念能被集成进SQL,清楚了解它们间的关系是特别有益的。考虑到完整性,本文首先会对上述文章(主要是Martin和Jay的帖子)进行一个简要的回顾。数据结构
Steam & Tables的基本思想源于数据库。熟悉SQL的人均可能熟悉表和表的基本属性,大体归纳为,表包含行和列,每行都由显式或隐式的键惟一标识。 回忆下大学数据库系统课程,可能会记得大部分数据库底层所使用到的数据结构是一个只能进行追加写的日志文件。事务应用于数据库表时,这些事务首先会记录在这个日志中,而后事务会顺序的做用于目标表来实现更新操做。在Steam & Tables概念中,上面说起的事务日志实际上就是流。从这个角度来看,咱们如今能够理解如何将流转化为表:将流中的事务顺序的执行,其执行结果便成为了表。可是如何将表转化为流?本质上是逆思想:流是表的更新日志。数据库系统中的物化视图功能是一个用于说明表到流转换的不错案例。SQL中的物化视图,容许你指定表的查询语句,系统将这个查询语句视为另外一张表。物化视图本质上是查询的缓存版本,当源表内容发生变化时,系统须要确保视图对应的内容最新。显而易见,物化视图是基于源表的更新日志实现,任什么时候刻源表发生变化都会被记录下来,而后数据库评估物化视图的查询上下文是否须要更新,并将结果更新到物化视图上,以此来保证视图的内容为最新。大数据
结合以上两点,进行概括总结,咱们能够得出一个Steam & Tables的相对理论:spa
这是一对很是强大的概念,它们能被正确的应用到了流处理中是ApacheKafka取得巨大成功的一个重要缘由,其生态系统就是围绕这些基本原则构建而成。然而,这些理论自己没有足够泛化到能够将Steam & Tables与Beam模型中全部概念相结合。为此,咱们必须更深刻一点。日志
若是想将Steam & Tables理论和咱们所知道的Beam模型相结合,须要把一些零散的知识结合起来,特别是:blog
在此以前,咱们首先须要对面临的问题有个清晰的认知。除了经过上述定义来理解Steam & Tables间的关系外,独立定义它们的含义也颇有必要。先从简单的角度看下Steam & Tables的定义,这对咱们将来的一些分析颇有帮助,它们以下: 索引
这并非说表的内容是不变的。几乎全部实时表的内容都会以一些方式随时间不断变化。但在给定时刻,表的快照提供了数据库总体数据中的一部分数据视图。经过这种方式,表提供了一个供数据停下来缓存的静态场所:随着时间推移,在这里数据能够被累积计算、而且能够被观测。接口
表捕获的是某一特定时间点的数据视图,而流捕获的是数据随时间的变化发展。JulianHyde喜欢说流像表的求导结果,表像流的积分结果,这种使用数学思惟来理解是不错的方式。
虽然流与表密切相关,即便在许多案例中,一方来源彻底借鉴于另外一方,但必定要记住,它们之间是存在区别的。虽然区别是微妙的,但也是重要的,咱们会在下面看到。
随着讨论的深刻,让咱们开始总结一些零散分析。首先,咱们要解决的第一个问题是关于批处理的问题。最后,咱们将发现第二个关于流与有界和无界数据的关系的问题将天然而然地从第一个答案中获得解决。
为使咱们分析起来更简单,首先咱们能够看下Stream &Tables理论如何与传统的MapReduce任务相结合。就像它名字所表示的那样,MapReduce由两个关键的阶段组成:Map阶段和Reduce阶段,为了使得咱们的分析更加清晰,这里将其拆分红6个子阶段:
1. MapRead:消费输入数据,将数据预处理成标准的K/V结构,为Map阶段准备;
2. Map: 不断的消费(可能并行)前面过程预处理的单个K/V对,输出0或者多个K/V对;
3. MapWrite: Map阶段输出的具备相同key的value在这过程会被集群聚合在一块儿,聚合后的数据形如(K,Iterator(V)),接着持久化这些(K, Iterator(V))数据,简单来讲,MapWrite就是基本的根据key 进行聚合而后checkpoint这些结果到存储系统;
4. ReduceRead: 消费MapWrite阶段持久化的shuffle数据(K可能做为分桶的key,从而写入到不一样的磁盘上),转变成标准的(K,List(value))结构为Reduce阶段作准备;
5. Reduce: 不断消费一个Key对应的多条value,输出0条或者多条记录,这些记录仍然对应这个key;
6. ReduceWrite:将Reduce阶段的结果写入数据存储介质。
虽然在不少资料中,上述的MapWrite、ReduceRead阶段会被统一称为MapReduce中的Shuffle阶段,可是出于咱们的目的,这两个阶段最好单独分开看待。将MapRead和ReduceWrite分别当作是Sources与Sinks可能更好理解。除此以外,咱们如今看看它们与Stream &Tables理论又存在哪些关系?
有一点须要说明一下,因为在map阶段中,它的输入、输出都是表的形式,有些人可能会天然而然的认为,map过程当中涉及到的都是只有表而已。毕竟对于批处理任务来讲,你们都知道它是以表做为输入,而后再输出结果表。若是把整个批处理过程看出是执行一段SQL语句的话,可能更好理解一些。可是map过程与表之间的关系究竟是什么呢?难道它就真的只与表有关,与流就一点关系也没有吗?下面让咱们一步步深刻的进行说明?
首先,MapRead消费一张表,而后产生结果数据,这些结果数据又被下一步Map阶段做为输入数据,想要理解的更透彻些,能够看下Map阶段的API,JAVA接口以下:
voidmap(KI key, VI value, Emit);
每消费一条input表中的k/v对,都将调用一次map方法,若是你发现这里输入表的记录数据像流同样被处理,那么恭喜你,你是对的。稍后咱们将更进一步的去看表是如何转化为流,可是如今,咱们已经了解到MapRead阶段会迭代消费输入表中的数据,同时使这些数据以流的形式供Map阶段消费。
下一步,Map阶段消费流,而后干什么呢?因为map执行的是对一个元素的转化操做,所以它不会作任何阻止数据流动的事情,经过过滤一些元素或者拆分一些元素成为多个元素,它能够有效改变流中的数据,可是map阶段结束之后,这些元素彼此相互独立。所以能够说,map阶段消费流同时产出流。
一旦map阶段结束之后,就进入了MapWrite阶段,我上面提到,MapWrite根据key聚合记录,而后以这种数据结构持久化到存储介质中。这里存储到持久化存储其实不是严格必须的,也能够存储到其余地方(假如上一节点流被存储了,中间结果再失败的时候就能够经过从新计算上个节点获得,相似spark的的RDD方法),最重要的是在这一步中记录被聚合到了一块儿,并被存储在存储介质上,多是内存、磁盘、其余可以存储的介质。这个重要的缘由是,聚合操做致使的结果是,那些先前在流中一条一条流动的数据经过key被放到同一位置,所以可以针对每一个key后的分组数据进行聚合处理,注意这里是否是和前面提到定义流到表的转换很像呢?随着时间推移,更新流的聚合结果进而产生表,MapWrite以key来将流中的数据进行分组,将分组数据再写入下一级,所以将流又转化为了表。
到此为止咱们已经讨论了MapReduce过程的上半部分(Map部分),来看下咱们目前为止看到了什么?(在图1中)
经过三个操做完成了从表到流再到表的转换过程,MapRead将表转换成流,map阶段又将该流转变成了新流,最后这个新流通过 MapWrite又转表回到表,接下来将会发现Reduce阶段的三个操做和这三个操做很相似,尽管如此在接下来对Reduce阶段进行说明的过程当中,我仍然会指出一个重要的细节出来。
在了解了MapWrite之后,ReduceRead自己相对无趣,由于它基本上与MapRead相同,除了读取的是list形式的数据而不是单个值,由于MapWrite存储的数据是k/list(v)对。 可是,它仍然只是迭代计算一个表的快照,将其转换为流,这里没什么新鲜的。
Reduce实际上只是一个Map阶段的变形,接收每一个键的值列表而不是单个值。所以,它仍然只是将单个(复合,(K,List(V)))记录映射到零个或多个新记录。ReduceWrite这里是值得注意的一个过程,咱们都知道这个过程会将流转变成表,由于上面的Reduce过程产生流而最终的 ReduceWrite输出倒是表。这个是如何作的?其实这个就像前面的MapWrite阶段同样,对前一个阶段的输出的流按照key进行分组,而后将结果持久化到存储介质。假如你记得我前面提到的指定key对于reduce过程是一个可选的特征,使用这个特征,ReduceWrite和MapWrite基本相同,若是reduce的输出没有指定key,那么数据到达下游之后会发生什么呢?
再回想下经典sql表的执行语义将有助于理解将会发生什么,尽管在sql表中推荐使用主键,可是sql表并非严格须要主键来区分每行数据的,若是表中没有主键,插入到表中的每条数据都被视为新的独立的一行,尽管表中可能存在一条或者多条相同的数据,这里大部分是经过为表增长自动递增的列做为数据的key来实现的。在这些场景下这些key可能仅仅是一些物理块的位置索引,不会当作逻辑标识符去处理或者暴露出去。这个隐含的key,正是ReduceWrite中处理无Key数据状况的应对方法。 从概念上讲,这仍然是按key分组的操做,可是因为缺乏用户提供的key,ReduceWrite认为每条数据都是新的,每条数据都拥有一个惟一的key,而后根据它进行分组(结果是每组仅有一条数据),最后将结果流传到下游。
如今让咱们回顾下流/表的转换的整个流程,能够发现它是“表 -> 流 -> 流 -> 表 -> 流-> 流 -> 表”的序列。尽管咱们处理的是有界数据,尽管咱们使用的是传统的批处理思想,但其实本质仍然是流和表的转化。
图2:从流/表的角度来看MapReduce的Map和Rdeuce
经过这些分析,除了前面提到的两个问题外还有哪些问题呢?
Question:批处理是如何适配到Stream & Tables理论中的?
Question:流与有界和无界数据的有什么关联吗?
Answer:咱们能够经过MapReduce例子看出,不管是对于有界仍是无界的数据,流只是数据的动态形式。
经过这些分析,很容易发现Stream & Tables理论与有界数据的批处理理论差别并不大,事实上这更加支持我以前提出的批处理与流处理两者并没有差别的想法,有了这些分析,咱们能够很好的总结出一个通用的Stream & Tables理论,可是要把这些东西理清楚,咱们最后要解决what/where/when/how这个四个问题,找出它们之间的联系。
网易有数:企业级大数据可视化分析平台。面向业务人员的自助式敏捷分析平台,采用PPT模式的报告制做,更加易学易用,具有强大的探索分析功能,真正帮助用户洞察数据发现价值。可点击这里免费试用。
了解 网易云 :
网易云官网:https://www.163yun.com/
新用户大礼包:https://www.163yun.com/gift
网易云社区:https://sq.163yun.com/