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.

130 lines
9.4 KiB
Markdown

2 years ago
# FAQ第三期 | Apache Beam基础答疑
你好,我是蔡元楠。
这里是“FAQ第三期Apache Beam基础答疑”。这一期主要是针对上周结束的模块四——Apache Beam的基础知识部分进行答疑并且做了一些补充。
如果你对文章的印象不深了,可以先点击题目返回文章复习。当然,你也可以继续在留言中提出疑问。希望我的解答对你有所帮助。
## [22 | Apache Beam的前世今生](https://time.geekbang.org/column/article/99379)
在第22讲中我分享了Apache Beam的诞生历程。留言中渡码、coder和Milittle都分享了自己了解的技术变迁、技术诞生历史。
![unpreview](https://static001.geekbang.org/resource/image/33/cf/337b762426b35a4b4222f33f7def3dcf.jpg)
![unpreview](https://static001.geekbang.org/resource/image/1e/89/1e59031e7acad0480e41ff5d80c0c889.jpg)
而JohnT3e则是分享了我在文章中提到的几个论文的具体内容。他分享的论文是非常好的补充材料也希望你有时间的话可以下载来看一看。我把链接贴在了文章里你可以直接点击下载浏览。
[MapReduce论文](https://research.google.com/archive/mapreduce-osdi04.pdf)
[Flumejava论文](https://research.google.com/pubs/archive/35650.pdf)
[MillWheel论文](https://research.google.com/pubs/archive/41378.pdf)
[Data flow Model论文](https://www.vldb.org/pvldb/vol8/p1792-Akidau.pdf%5D)
Morgan在第22讲中提问Beam和Spark是什么关系
![unpreview](https://static001.geekbang.org/resource/image/77/5e/772769f1de87b38363aa5aa59d22dd5e.jpg)
我的回答是Spark可以作为Beam的一个底层Runner来运行通过Beam SDK所编写的数据处理逻辑。相信在读完第23讲的内容后Morgan会对这个概念有一个更好的认识。
## [23 | 站在Google的肩膀上学习Beam编程模型](https://time.geekbang.org/column/article/100478)
在第23讲中明翼提出的问题如下
![unpreview](https://static001.geekbang.org/resource/image/d2/be/d2c5d558c7ddab8e4fe5f80de4f92bbe.jpg)
其实明翼的这些问题本质上还是在问Beam在整个数据处理框架中扮演着一个什么样的角色
首先为什么不是所有的大数据处理引擎都可以作为底层Runner呢原因是并不是所有的数据处理引擎都按照Beam的编程模型去实现了相应的原生API。
我以现在国内很火的Flink作为底层Runner为例子来说一下。
在Flink 0.10版本以前Flink的原生API并不是按照Beam所提出的编程模型来写的所以那个时候Flink并不能作为Beam的底层Runner。而在Flink 0.10版本以后Flink按照Beam编程模型的思想重写了DataStream API。这个时候如果我们用Beam SDK编写完数据处理逻辑就可以直接转换成相应的Flink原生支持代码。
当然明翼说的没错因为不是直接在原生Runner上编写程序在参数调整上肯定会有所限制。但是Beam所提倡的是一个生态圈系统自然是希望不同的底层数据处理引擎都能有相应的API来支持Beam的编程模型。
这种做法有它的好处那就是对于专注于应用层的工程师来说它解放了我们需要学习不同引擎中原生API的限制也改善了我们需要花时间了解不同处理引擎的弊端。对于专注于开发数据处理引擎的工程师来说他们可以根据Beam编程模型不断优化自身产品。这样会导致更多产品之间的竞争从而最终对整个行业起到良性的促进作用。
在第23讲中JohnT3e也给出了他对Beam的理解。
![](https://static001.geekbang.org/resource/image/da/bf/da3bff05ff22f997f8e70cb87acf4abf.jpg)
我是很赞成JohnT3e的说法的。这其实就好比SQL我们学习SQL是学习它的语法从而根据实际应用场景来写出相应的SQL语句去解决问题。
而相对的如果觉得底层使用MySQL很好那就是另外的决定了。写出来的SQL语句是不会因此改变的。
## [24 | 为什么Beam要如此抽象封装数据](https://time.geekbang.org/column/article/100666)
在第24讲中人唯优的提问如下
![unpreview](https://static001.geekbang.org/resource/image/10/a9/10d454ffc0205cf93023cd1a03022ea9.jpg)
确实Beam的Register机制和Spark里面的kryo Register是类似的机制。Beam也的确为常见的数据格式提供了默认的输入方式的。
但这是不需要重复工作的。基本的数据结构的coder在[GitHub](https://github.com/apache/beam/tree/master/sdks/java/core/src/main/java/org/apache/beam/sdk/coders)上可以看到。比如StringList之类。
## [25 | Beam数据转换操作的抽象方法](https://time.geekbang.org/column/article/101735)
在第25讲中我们学习了Transform的概念和基本的使用方法了解了怎样编写Transform的编程模型DoFn类。不过sxpujs认为通用的DoFn很别扭。
![unpreview](https://static001.geekbang.org/resource/image/22/07/22c8f87387991a176a5302d062675c07.jpg)
这个问题我需要说明一下Spark的数据转换操作API是类似的设计Spark的数据操作可以写成这样
```
JavaRDD<Integer> lineLengths = lines.map(new Function<String, Integer>() {
public Integer call(String s) { return s.length(); }
});
```
我不建议你用自己的使用习惯去评判自己不熟悉的、不一样的API。当你看到这些API的设计时你更应该去想的是这种设计的目标是什么又有哪些局限。
比如在数据处理框架中Beam和Spark之所以都把数据操作提取出来让用户自定义是因为它们都要去根据用户的数据操作构建DAG用户定义的DoFn就成了DAG的节点。
实际使用中往往出现单个数据操作的业务逻辑也非常复杂的情况它也需要单独的单元测试。这也是为什么DoFn类在实际工作中更常用而inline的写法相对少一点的原因。因为每一个DoFn你都可以单独拿出来测试或者在别的Pipeline中复用。
## [26 | PipelineBeam如何抽象多步骤的数据流水线](https://time.geekbang.org/column/article/102182)
在第26讲中espzest提问如下
![unpreview](https://static001.geekbang.org/resource/image/30/3a/3059789b7b009adab91e12081327103a.jpg)
其实我们通过第24讲的内容可以知道PCollection是具有无序性的所以最简单的做法Bundle在处理完成之后可以直接append到结果PCollection中。
至于为什么需要重做前面的Bundle这其实也是错误处理机制的一个trade-off了。Beam希望尽可能减少persistence cost也就是不希望将中间结果保持在某一个worker上。
你可以这么想如果我们想要不重新处理前面的Bundle我们必须要将很多中间结果转换成硬盘数据这样一方面增加很大的时间开销另一方面因为数据持久化了在具体一台机器上我们也没有办法再重新动态分配Bundle到不同的机器上去了。
接下来是cricket1981的提问
![unpreview](https://static001.geekbang.org/resource/image/e6/80/e6baae616b335289b936853ea6f27680.jpg)
其实文章中所讲到的随机分配并不是说像分配随机数那样将Bundle随机分配出去给workers只是说根据runner的不同Bundle的分配方式也会不一样了但最终还是还是希望能使并行度最大化。
至于完美并行的背后机制Beam会在真正处理数据前先计算优化出执行的一个有向无环图希望保持并行处理数据的同时能够减少每个worker之间的联系。
就如cricket1981所问的那样Beam也有类似Spark的persist方法BEAM-7131 issue就有反应这个问题。
## [28 | 如何设计创建好一个Beam Pipeline](https://time.geekbang.org/column/article/103301)
在第28讲中Ming的提问如下
![unpreview](https://static001.geekbang.org/resource/image/f9/e8/f9997a5ae3e28a36a774bead6aaabce8.jpg)
对此我的回答是一个集群有可能同时执行两个pipeline的。在实践中如果你的四个pipeline之间如果有逻辑依赖关系比如一个pipeline需要用到另一个pipeline的结果的话我建议你把这些有依赖关系的pipeline合并。
如果你的pipeline之间是互相独立你可以有四个独立的二进制程序。这个提问里Ming说的集群应该是物理上的机器这和pipeline完全是两个概念。好的集群设计应该能够让你可以自由地提交pipeline任务你不需要去管什么具体集群适合去安排跑你的任务。
JohnT3e的问题如下
![unpreview](https://static001.geekbang.org/resource/image/78/6e/783aceb1758747ac07e579f497fa3b6e.jpg)
对于这个问题我觉得JohnT3e可以先退一步看看这个需求场景到底适不适用于分布式数据处理。
分布式的核心就是并行也就是说同一批数据集合元素和元素之间是无依赖关系的。如果你的场景对于元素的先后顺序有业务需求可能可以看看PubSubRPC等是不是更适合。而不是Beam的PCollection。
好了第三期答疑到这里就结束了。最后感谢在Apache Beam的基础知识模块里积极进行提问的同学们谢谢你们的提问互动。
@JohnT3e、@渡码、@coder、@morgan、@Milittle、@linuxfans、@常超、@明翼、@ditiki、@朱同学、@Bin滨、@A\_F、@人唯优、@张凯江、@胡墨、@cricket1981、@sxpujs、@W.T、@cricket1981、@espzest、@沈洪彬、@onepieceJT2018、@fy、@Alpha、@TJ、@dancer、@YZJ、@Ming、@蒙开强