一文看齐,主流大数据技术总结(下)
前文见 :point_right: :
一文看齐,主流大数据技术总结(上)
计算引擎
计算引擎目前主流的两个开源组件分别是 Spark 和 Flink。从两个引擎的处理模型来看,Spark 的批处理更为高效,Flink 则善于流处理,尽管两者都向着流批一体化的方向发展。当然,只要对弱项做优化还是可以跟另一方未做太多优化的强项比的,只是实现难度大些和效果上限可能略低。比如 Blink,阿里内部的 Flink,其 ML 模块经过优化,在大部分常用模型的计算效率都能高于开源的 Spark 的。如果开源 Spark 也经过阿里那样深度的优化,两者的差距就难说了。
简单提一下他们的特点
- 适合:大批量数据的灵活计算,包括关联、机器学习、图计算、实时计算等。
- 不适合:小量数据的交互式计算。
Spark
下面首先介绍 Spark,它是一个用于大规模数据处理的统一分析引擎,其内部主要由 Scala 实现。Spark 当初引起关注主要是它与 Hadoop 的三大件之一的 MapReduce 之间的比较。Hadoop 的三大组件包括 HDFS、Yarn 和 MapReduce。他们三个都是可以拆分开来单独使用的。比如 Yarn 作为资源调度系统,传统 Spark 和 Flink 都会借助它的功能实现任务的调度。而 MapReduce 作为计算引擎,其计算速度当时是弱于 Spark 的,主要是 Spark 减少了不必要的磁盘IO;增加迭代计算功能,从而更好支持机器学习;引入了一些自动优化功能。另外,Spark 广泛的语言支持、API 更强的表达能力等优点都让 Spark 在当时的离线计算领域中超越 MapReduce。
功能丰富
4大场景:Spark 的高层组件包括Spark SQL、Spark Streaming、Spark ML、GraphX。他们都是通过底层组件为 Spark Core 实现具体功能的。但是在使用 Spark 的时候,尽量是不要使用 Spark Core,因为高层组件的产生的 Spark Core一般会更高效,因为Spark做了不少优化,具体后面再说。
多种语言:支持 Java、Python、R 和 Scala 来编写应用代码。
多种部署模式:本地、独立部署、Mesos、Yarn、K8S
多种数据源:HDFS、HBase、Hive、Cassandra、Kafka等
架构原理
Driver 是启动 Spark 作业的JVM进程,它会运行作业(Application)里的main函数,并创建 SparkContext 对象。这个 SparkContext 里面包含这次 Spark 计算的各种配置信息。Spark 通过它实现与 Cluster Manager 通信来申请计算资源。这里的 Cluster Manager,在生产环境一般是 Mesos、Yarn 或者 K8s。这些 Manager 根据其管理的集群情况,给这个 Spark 任务分配相应的容器container,在容器中启动 executor 进程。这些启动后的 executor 会向 Driver 注册,之后 Driver 就可以把它根据用户计算代码生成出的计算任务task发送给这些 executor 执行。计算结束后,结果可能输出到 Driver,也可能输出到当前 executor 的磁盘,或者其他存储。
作业例子
object SparkSQLExample {
def main(args: Array[String]): Unit = {
// 创建 SparkSession,里面包含 sparkcontext
val spark = SparkSession
.builder()
.appName("Spark SQL basic example")
.getOrCreate()
import spark.implicits._
// 读取数据
val df1 = spark.read.load("path1...")
val df2 = spark.read.load("path2...")
// 注册表
df1.createOrReplaceTempView("tb1")
df2.createOrReplaceTempView("tb2")
// sql
val joinedDF = sql(
"""
|select tb1.id, tb2.field
|from tb1 inner join tb2
|on tb1.id = tb2.id
""".stripMargin)
// driver 终端显示结果
joinedDF.show()
// 退出 spark
spark.stop()
}
}
SQL会经过一层层的解析然后生成对应的 Java 代码来执行。
计算引擎的优势
与 HBase、 es 和传统数据库查询比较,计算引擎的优势:1)数据量大时速度快,2)计算更加灵活。
以大数据关联为例:
- 文档型数据库:大部分都不支持关联,因为效率低。关联基本都要全文档扫描。因为文档是 schemaless 的,并不确定某个文档是否有关联所需字段。而且个文档的读取都是整个对象的读取,并不会只读某个字段来减少内存开销。另外,这两个组件在内存中本身就有各自的数据结构来服务读写,所以额外的内存用于这类大开销计算也是不现实的。因此,HBase 本身只支持简单的过滤,不支持关联。ES 即便支持过滤、聚合,但依然不支持关联。
- 传统关系型数据库:可以完成较大数据关联,然而效率低,这主要是受到其大量的磁盘 IO、自身服务(读写、事务等、数据同步)的干扰。在真正大数据情况下,这关联还涉及数据在不同机器的移动,数据库需要维持其数据结构,如 BTree,数据的移动效率较低。
- 计算引擎:
- 基于内存:计算引擎留有大量内存空间专门用于计算,尽量减少磁盘 IO。
- 计算并行化
- 算法优化
具体而言,Spark 提供了三种 Join 执行策略:
- BroadcastJoin:当一个大表和一个小表进行Join操作时,为了避免数据的Shuffle,可以将小表的全部数据分发到每个节点上。算法复杂度:O(n).
- ShuffledHashJoinExec:先对两个表进行hash shuffle,然后把小表变成map完全存储到内存,最后进行join。算法复杂度:O(n)。不适合两个表都很大的情况,因为其中一个表的hash部分要全部放到内存。
- SortMergeJoinExec:先hash shuffle将两表数据数据相同key的分到同一个分区,然后sort,最后join。由于排序的特性,每次处理完一条记录后只需要从上一次结束的位置开始继续查找。算法复杂度:O(nlogn),主要来源于排序。适合大表join大表。之所以适合大表,是因为 join 阶段,可以只读取一部分数据到内存,但其中一块遍历完了,再把下一块加载到内存,这样关联的量就能突破内存限制了。
从上面的例子可以看出计算引擎相比于其他组件在计算方面的优势。
数据流动
下面通过一张图,从另一个角度了解 Spark 的运作。
这是一张简单的数据流程图。描述了一个 WorkCount 的数据流向。其主要代码如下:
// 假设每个 block 里的数据如下
// a
// b
// a
val textFile = sc.textFile("hdfs://...")
val counts = textFile.map(word => (word, 1)) // a ->
.reduceByKey(_ + _) // <a,> ->
counts.saveAsTextFile("hdfs://...")
图中同一阶段有多个数据流体现的是并行。中间的 shuffle 是在聚合、关联、全局排序等操作时会出现的。比如这里的 reduceByKey 就是将相同 key 的数据移动到相同的 partition。这样就能对所有的 a 进行加总,从而得出 a 的总数。
上图的任务是一次性的,或者是周期性的,数据的驱动是拉取型的。如果将数据块换成数据流,map 和 reduce 在启动后就一直存在,并接受数据源不断发送过来的信息,那就变成了流计算。即由周期性变为一直处理,从而变为实时处理,由主动拉取变为被动接收的形式。下面就来介绍 Flink 计算引擎。
Flink
Flink 同样是分布式的计算引擎,主要基于Java实现,但它的特色主要体现在流式计算。这个引擎流行的主要推手是阿里。阿里在19年初开源了它修改过的 Flink,收购了 Flink 的母公司,并在各种线下技术论坛上推广 Flink,让 Flink 在 19 年的关注度极速上升。
除了在实时计算领域,Flink 在其他领域或许稍微落后于 Spark,毕竟 Spark 发展比较早,其生态比 Flink 要成熟更多。Flink 目前支持 Scala、Java 和 Python 来写任务代码。功能上同样支持批计算、ML、Graph。部署工具、支持的数据源也 Spark 类似。
场景
- 实时分析/BI指标:比如某天搞活动或新版本上线,需要尽快根据用户情况来调整策略或发现异常。
- 实时监控:通过实时统计日志数据来尽快发现线上问题。
- 实时特征/样本:模型预测和训练
架构原理
细节补充
和 Spark 一样,Flink 也会根据 SQL 或者业务代码生成 DAG 图,然后将任务划分并发送给不同的节点执行。最大的不同正如之前所说,数据是实时地、一条条或一小批一小批地不断流进这些节点,然后节点输出响应的结果。而在这种场景下,Flink 在一定程度上解决了实时处理中的不少难点。
- 保证数据刚好被处理一次,即便在计算过程中出现网络异常或者宕机。
- event-time处理,即按照数据中的时间作为计算引擎的时间,这样即便数据上报出现一定的延迟,数据仍然可以被划分到对应的时间窗口。而且还能对一定时间内的数据顺序进行修正。
- 在版本升级,修改程序并行度时不需要重启。
- 反压机制,即便数据量极大,Flink 也可以通过自身的机制减缓甚至拒绝接收数据,以免程序被压垮。
与 Spark 比较
Spark:
- 拉模型
- 系统更加成熟,尤其是离线计算
- 生态更加完善
Flink:
- 推模型
- 实时计算更优秀
- 阿里推动,正在迅速发展
- 生态对国内更为友好
小红书实时技术
小红书旧的离线框架和我们现在的大数据体系有点类似,都是把埋点数据上报到日志服务,然后进入离线数仓,只是小红书用 Hive,我们用 DataWorks。然后我们同样也有 T+1 的用户画像、BI报表和推荐的训练数据。
而后续的实时框架是这样的
日志服务的埋点数据先进入 Kafka 这一消息队列里面。不太清楚为什么要加上 Kafka 这一中间件,或许当时并没有开源的 日志服务到Flink 的 connecter 吧。但总之,引入 Flink 之后就可以实时累计埋点中的数据,进而产生实时的画像、BI指标和训练数据了。下面介绍一下这个实时归因
如上图所以,用户app屏幕展示了4个笔记,然后就会有4条曝光埋点,而如果点击笔记、点赞笔记以及从笔记中退出都会有相应的埋点。通过这些埋点就可以得出右面两份简单的训练或分析数据。这些数据跟原来已经积累的笔记/用户画像进行关联就能得出一份维度更多的数据,用于实时的分析或模型预测。实时模型训练这一块至少小红书在19年8月都还没有实现。下图是小红书推荐预测模型的演进
那么如何进行实时训练深度学习模型呢?以下是我的一些想法。借助一个阿里的开源框架flink-ai-extended。
如上图所示,这是 flink 的数据流结构图,左边 source 为数据源,然后进过join、udf等算子进行训练样本数据的生成,然后传递给一个 UDTF/FlatMap 算子,这实际上也是一个 Flink 节点,但它里面包含的是 Tensorflow 的训练 worker,而上下也是 Flink 的节点,都是包含了 Tensorflow 训练所需的一些角色,这样数据源源不断地实时进入 TF 模型来完成实时训练。TF 也可以因此借助 Flink 的分布式框架来完成分布式的学习。多台GPU或者CPU或许应该会比一台GPU的训练效率更高。
这个框架同时适用于模型预测,只要把里面的训练角色换成训练完成的 model,也就可以进行实时的预测,而且这里借助 Flink 内部的通信机制,效率应该会比普通的 http 调用要快不少。
本次分享由于时间有限,讲的都是比较浅层的东西,实际上刚刚所说的每一个组件里面包含的内容都不少,都可以作为一个长远的目标去研究和改造。说回分享的主题之一,使用场景。
首先是存储,上述介绍的 HDFS、HBase、ES(ES虽然是搜索引擎,但它也可以在某些方面替代传统关系型数据的功能) 都是适用于 OLAP 场景,即分析推荐而非事务。从公司目前的情况来看,HDFS 基本可以忽略,因为已经有 DataWork,数据的存储暂时不是问题。更多的问题在于数据使用时的性能。HBase 和 ES 作为文档型数据库,适合一对多的数据模型,比如将帖子和其评论作为一个整体来存储。对于多对一、多对多的模型,文档型数据库实际上并不合适,但可以通过合并宽表、应用层关联等方式在一定程度上进行弥补。而如果多对多关系确实复杂、量大、文档型数据库性能无法满足,比如一些大型社交网络,那么可以考虑图数据库。
当决定尝试文档型数据库时,HBase 的特点在于较为快速地查询小范围的新数据,而且这条数据可以很大。ES 的特点则在于快速的全文检索、准实时的数据分析。当然,分析的复杂度是不能跟计算引擎比的,比如关联、机器学习等。但通过合并宽表、各种where、group by操作,还是能满足不少需求的,尤其是应用的搜索功能,ES 实现起来是比较简单的。目前公司并没有应用它的强项,最好由专人负责它的调试,尤其是搜索排序方面。
然后是计算引擎,目前公司用的 MaxCompute 已经能够满足离线计算的各种需求,或者就欠缺实时计算了。但公司目前实时性需求不多而且也不紧急,所以开发一直都没有启动。目前就看明年推荐是否有这样的需求,而且有相应的prd出来了。而考虑到成本和灵活性,自建或许是更好的选择,比如刚刚提到的 Flink + Tensorflow。
以上便是这次分享会的全部内容,谢谢大家的参与。
参考:
书籍:
- Martin Kleppmann: “Designing Data-Intensive Applications”, O’Reilly Media, March 2017
- Tom White: “Hadoop: The Definitive Guide”, 4th edition. O’Reilly Media, March 2015
- 胡争, 范欣欣: “HBase原理与实践”, 机械工业出版社, 2019年9月
- 朱锋, 张韶全, 黄明: “Spark SQL 内核剖析”, 电子工业出版社, 2018年8月
- Fabian Hueske and Vasiliki Kalavri: “Stream Processing with Apache Flink”, O’Reilly Media, April 2019
文章:
- 再谈 HBase 八大应用场景:https://cloud.tencent.com/developer/article/1369824
- Elasticsearch读写原理:https://blog.csdn.net/laoyang360/article/details/103545432
- ES文章集:https://me.csdn.net/wojiushiwo987
- MySQL和Lucene索引对比分析:https://www.cnblogs.com/luxiaoxun/p/5452502.html
-
深入浅出理解 Spark:环境部署与工作原理:
https://mp.weixin.qq.com/s/IdrX4Hh1HQaJZx-VnB7XsQ
文档:
- ES官方文档:https://www.elastic.co/guide/index.html
- Spark官方文档:http://spark.apache.org/docs/latest/
- Flink官方文档:https://flink.apache.org/
分享:
- 基于Flink的高性能机器学习算法库 https://www.bilibili.com/video/av57447841?p=4
- “Redefining Computation” https://www.bilibili.com/video/av42325467?p=3
- Flink 实时数仓的应用 https://www.bilibili.com/video/av66782142
- Flink runtime 核心机制剖析 https://www.bilibili.com/video/av42427050?p=4
-
小红书大数据在推荐中的应用
https://mp.weixin.qq.com/s/o7JM7DDkUNuGZEGKBtAmIw - TensorFlow 与 Apache Flink 的结合 https://www.bilibili.com/video/av60808586/