You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

133 lines
11 KiB
Markdown

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# 23 | 站在Google的肩膀上学习Beam编程模型
你好,我是蔡元楠。
今天我要与你分享的话题是“站在Google的肩膀上学习Beam编程模型”。
在上一讲中我带你一起领略了Apache Beam的完整诞生历史。通过上一讲你应该对于Apache Beam在大规模数据处理中能够带来的便利有了一定的了解。
而在这一讲中让我们一起来学习Apache Beam的编程模型帮助你打下良好的基础以便应对接下来的Beam实战篇。希望你在以后遇到不同的数据处理问题时可以有着Beam所提倡的思考模式。
现在让我们一起进入Beam的世界吧。
## 为什么要先学习Beam的编程模型
可能你会有疑问很多人学习一项新技术的时候都是从学习SDK的使用入手为什么我们不同样的从SDK入手而是要先学习Beam的编程模型呢
我的答案有两点。
第一Apache Beam和其他开源项目不太一样它并不是一个数据处理平台本身也无法对数据进行处理。Beam所提供的是一个统一的编程模型思想而我们可以通过这个统一出来的接口来编写符合自己需求的处理逻辑这个处理逻辑将会被转化成为底层运行引擎相应的API去运行。
第二学习Apache Beam的时候如果只学习SDK的使用可能你不一定能明白这些统一出来的SDK设计背后的含义而这些设计的思想又恰恰是涵盖了解决数据处理世界中我们所能遇见的问题。我认为将所有的SDK都介绍一遍是不现实的。SDK会变但它背后的原理却却不会改变只有当我们深入了解了整个设计原理后遇到各种应用场景时才能处理得更加得心应手。
## Beam的编程模型
那事不宜迟我们来看看Beam的编程模型到底指的是什么
简单来说Beam的编程模型需要让我们根据“WWWH”这四个问题来进行数据处理逻辑的编写。“WWWH”是哪四个问题呢这里我先卖个关子在进入四个具体问题之前我需要先介绍一下根据Beam编程模型所建立起来的Beam生态圈帮助你理解Beam的编程模型会涉及到的几个概念。整个Apache Beam的生态圈构成就如下图所示。
![](https://static001.geekbang.org/resource/image/bb/35/bbe679898aef03c77e49ba8d93aca235.png)
为了帮助你理解,我为这几层加了编号,数字编号顺序是自下而上的,你可以对照查找。
第一层是现在已有的各种大数据处理平台例如Apache Spark或者Apache Flink在Beam中它们也被称为Runner。
第二层是可移植的统一模型层各个Runners将会依据中间抽象出来的这个模型思想提供一套符合这个模型的APIs出来以供上层转换。
第三层是SDK层。SDK层将会给工程师提供不同语言版本的API来编写数据处理逻辑这些逻辑就会被转化成Runner中相应的API来运行。
第四层是可扩展库层。工程师可以根据已有的Beam SDK贡献分享出更多的新开发者SDK、IO连接器、转换操作库等等。
第五层我们可以看作是应用层各种应用将会通过下层的Beam SDK或工程师贡献的开发者SDK来实现。
最上面的第六层,也就是社区一层。在这里,全世界的工程师可以提出问题,解决问题,实现解决问题的思路。
通过第6讲的内容我们已经知道这个世界中的数据可以分成有边界数据和无边界数据而有边界数据又是无边界数据的一种特例。所以我们都可以将所有的数据抽象看作是无边界数据。
同时每一个数据都是有两种时域的分别是事件时间和处理时间。我们在处理无边界数据的时候因为在现实世界中数据会有延时、丢失等等的状况发生我们无法保证现在到底是否接收完了所有发生在某一时刻之前的数据。所以现实中流处理必须在数据的完整性和数据处理的延时性上作出取舍。Beam编程模型就是在这样的基础上提出的。
Beam编程模型会涉及到的4个概念窗口、水位线、触发器和累加模式我来为你介绍一下。
* **窗口Window**
窗口将无边界数据根据事件时间分成了一个个有限的数据集。我们可以看看批处理这个特例。在批处理中我们其实是把一个无穷小到无穷大的时间窗口赋予了数据集。我会在第32讲中对窗口这个概念进行详细地介绍。
* **水位线Watermark**
水位线是用来表示与数据事件时间相关联的输入完整性的概念。对于事件时间为X的水位线是指数据处理逻辑已经得到了所有事件时间小于X的无边界数据。在数据处理中水位线是用来测量数据进度的。
* **触发器Triggers**
触发器指的是表示在具体什么时候,数据处理逻辑会真正地触发窗口中的数据被计算。触发器能让我们可以在有需要时对数据进行多次运算,例如某时间窗口内的数据有更新,这一窗口内的数据结果需要重算。
* **累加模式Accumulation**
累加模式指的是如果我们在同一窗口中得到多个运算结果,我们应该如何处理这些运算结果。这些结果之间可能完全不相关,例如与时间先后无关的结果,直接覆盖以前的运算结果即可。这些结果也可能会重叠在一起。
懂得了这几个概念之后我来告诉你究竟Beam编程模型中的“WWWH”是什么。它们分别是What、Where、When、How。
**What results are being calculated?**
![](https://static001.geekbang.org/resource/image/71/bb/71c8ace006d56d7f6fe93cbc56dc91bb.png)
我们要做什么计算得到什么样的结果Beam SDK中各种transform操作就是用来回答这个问题的。这包括我们经常使用到批处理逻辑训练机器学习模型的逻辑等等。
举个例子我们每次学习大规模数据处理时所用到的经典例子WordCount里我们想要得到在一篇文章里每个单词出现的次数那我们所要做的计算就是通过Transform操作将一个单词集合转换成以单词为Key单词出现次数为Value的集合。
**Where in event time they are being computed?**
![](https://static001.geekbang.org/resource/image/34/08/34005c0d4635d26304c6a9c71f857708.png)
计算什么时间范围的数据?这里的“时间”指的是数据的事件时间。我们可以通过窗口这个概念来回答这个问题。
例如我们有三个不同的数据它们的事件时间分别是12:01、12:59和14:00。如果我们的时间窗口设定为\[12:00 , 13:00),那我们所需要处理的数据就是前两个数据了。
**When in processing time they are materialized?**
![](https://static001.geekbang.org/resource/image/09/6c/0963adf3a79446382e366c2c82a96e6c.png)
何时将计算结果输出?我们可以通过使用水位线和触发器配合触发计算。
在之前的概念中我们知道触发器指的就是何时触发一个窗口中的数据被计算出最终结果。在Beam中我们可以有多种多样的触发器信号例如根据处理时间的信号来触发也就是说每隔了一段时间Beam就会重新计算一遍窗口中的数据也可以根据元素的计数来触发意思就是在一个窗口中的数据只要达到一定的数据这个窗口的数据就会被拿来计算结果。
现在我来举一个以元素计数来触发的例子。我们现在定义好的固定窗口Fixed Window时间范围为1个小时从每天的凌晨00:00开始计算元素计数定为2。我们需要处理的无边界数据是商品交易数据我们需要计算在一个时间窗口中的交易总量。
为了方便说明我们假设只接收到了4个数据点它们按照以下顺序进入我们的处理逻辑。
1. 于6月11号23:59产生的10元交易
2. 于6月12号00:01产生的15元交易
3. 于6月11号23:57产生的20元交易
4. 于6月11号23:57产生的30元交易。
接收到第三个数据的时候6月11号这个24小时窗口的数据已经达到了两个所以触发了这个窗口内的数据计算也就是6月11号的窗口内交易总量现在为10+20=30元。
当第四个数据6月11号23:57产生的30元交易进入处理逻辑时6月11号这个24小时窗口的数据又超过了两个元素这个窗口的计算再次被触发交易总量被更新为30+30=60元。你可以看到由于6月12号这个窗口的数据一直没有达到我们预先设定好的2所以就一直没有被触发计算。
**How earlier results relate to later refinements?**
![](https://static001.geekbang.org/resource/image/d1/5a/d1e21d08c6ecdc43c92c8bc753b8565a.png)
后续数据的处理结果如何影响之前的处理结果呢?这个问题可以通过累加模式来解决,常见的累加模式有:丢弃(结果之间是独立且不同的)、累积(后来的结果建立在先前的结果上)等等。
还是以刚刚上面所讲述的4个交易数据点为例子你可能会认为这里我们采取的累加模式是累积其实我们采取的是丢弃。因为我们从始至终只保存着一个计算结果。这里要再引入一个概念每一次通过计算一个窗口中的数据而得到的结果我们可以称之为窗格Pane
我们可以看到当数据处理逻辑第一次产生6月11号这个窗口结果的时候两次交易相加产生的30元成为了一个窗格。而第二次产生窗口结果是60元这个结果又是一个窗格。因为我们只需要计算在一个窗口时间中的交易总量所以第一个窗格随之被丢弃只保留了最新的窗格。如果我们采用的是累积的累加模式呢那这两个交易总量30元和60元都会被保存下来成为历史记录。
Beam的编程模型将所有的数据处理逻辑都分割成了这四个纬度统一成了Beam SDK。我们在基于Beam SDK构建数据处理业务逻辑时只需要根据业务需求按照这四个维度调用具体的API即可生成符合自己要求的数据处理逻辑。Beam会自动转化数据处理逻辑并提交到具体的Runner上去执行。我们可以看到无论是Runner自身的API还是Beam的SDK设计都需要有能力解决上述四个问题。Beam的编程模型是贯穿了Beam生态圈中的每一层的。
在模块四的后续的内容中我们会围绕着这四个问题展开具体的分析看看在Beam的实战中这每一步是如何被解答的。
## 小结
Google如此地推崇Apache Beam开源项目除了借此能够推广自己的云计算平台之外更是借鉴了Apache Hadoop在开源社区中所取得的巨大成功。Google希望为外界贡献一个容易使用而又功能强大的大数据处理模型可以同时适用于流处理和批处理并且还可以移植于各种不同数据处理平台上。
在Beam的生态圈中我们可以看到每一层的设计都是根据Beam的编程模型来搭建的。懂得了Beam编程模型之后我们可以为生态圈中的任意一层做出贡献。
## 思考题
在现实应用中你能否根据Beam的编程模型来分享你会怎么设计自己的数据处理逻辑呢
欢迎你把答案写在留言区,与我和其他同学一起讨论。如果你觉得有所收获,也欢迎把文章分享给你的朋友。
![unpreview](https://static001.geekbang.org/resource/image/4d/a8/4d90d26b0e793703f02bd8684a0481a8.jpg)