第10章 批处理系统
通过弄清数据的来龙去脉,来理清复杂的系统架构,是本书的宗旨。
三种系统:
-
在线服务(或称在线系统)
服务等待客户端请求或指令的到达。当收到请求或指令时,服务试图尽快的处理它,并发挥响应。响应时间和可用性是衡量标准。
-
批处理(或称离线系统)
接收大量的输入数据,运行一个作业来处理数据,并产生输出数据。衡量标准是吞吐量。
-
流处理(或称近实时系统)
流处理介于在线与离线之间。与批处理类似,流处理处理输入并产生输出。但是,流处理作业在事件发生不久就可对事件进行处理。
linux命令是单机版的批处理,map-reduce是分布式的批处理。unix工具使用stdin和stdout作为输入输出,MapReduce作业使用HDFS(Hadoop Distributed File System)分布式文件系统读写文件。
除HDFS外,还有GlusterFS和Quantcast File System(QFS)。注入Amazon S3,Azure Blob存储和Open Swift对象存储服务也有相似之处。
HDFS在每台机器上都有一个守护进程,并开放一个网络服务以便其他节点访问存储在该机器上的文件。名为NameNode的中央服务器会跟踪哪个文件存储在哪台机器上。
批处理的输出:
- 生成搜索索引。尽管如今Google不再使用MapReduce构建索引,但是MapReduce仍是构建Lucene和Solr的好方法。
- 构建机器学习系统。比如分类器(如垃圾邮件过滤,异常检测,图像识别)和推荐系统(可能认识的人,可能感兴趣的产品)。
MapReduce虽然在模型抽象上比较简单,但是使用起来却很不方便。例如,你需要从头开始实现全部join算法。
MapReduce在物化(将中间状态写入文件的过程)的过程中存在如下问题:
- 前面的作业完成之后,后面的作业才能开始。
- Mapper通常是冗余的。它们通常是读取前一个reducer写入的文件,并为下一个分区和排序阶段做准备。通常可以和reducer放在一起。
- 中间状态会复制到多个节点。
为了解决这些问题,Spark、Tez和Flink等数据流引擎应运而生。它们有一个共同点:将整个工作流作为一个作业完成,而不是把它分解为独立的子作业。同时也不严格区分map和reduce角色,而是以函数运算符进行组合。优点:
- 排序等昂贵的操作只在需要的地方进行,而不是在map和reduce之间默认发生。
- 没有不必要的map,可以合并到前一个reduce中。
- 所有join和数据依赖都是明确声明的,调度器知道哪些是必需的,因此可以进行本地优化。比如将使用某些数据的任务放在生成数据的机器上,避免网络复制。
- 将中间状态保存在内存或本地磁盘就够了,比写入HDFS更省IO。
- 运算符在输入准备就绪后立即开始,不用等待上一阶段全部完成。
- MapReduce每个任务启动一个JVM,现在可以重用JVM。
Spark、Flink和Tez为了避免写入中间状态,同时失败了能够重新开始计算,必须在框架层追踪给定数据是如何计算的,使用了哪个输入分区以及应用了哪个运算符。Spark使用弹性分布式数据集(Resilient Distributed Dataset,RDD)来追踪数据的祖先,Flink对运算符状态建立检查点。