技术选型:批处理为什么选择Flink?最近我们接手了一个整合日志的服务。经过梳理,我认为目前的服务在设计上存在缺陷。和Leader开会商量后,我们决定重新进行技术方案研究,最终我们选择了使用Flink来重构服务。目前,重构后的服务已成功经受住国庆流量高峰的考验。今天,我将总结和回顾,与大家分享我的经验。首先我们要明确业务需求和背景,我们要解决的问题是什么,目前的服务是怎么解决的?目前的业务逻辑比较清晰:采集同一时间段不同数据源的日志。处理收集的数据。将处理后的数据上传到指定位置,供客户下载。我们面临的痛点和难点:日志量比较大,每小时未压缩的日志在50G左右;如果是节假日等特殊时间节点,日志量一般会翻倍。目前该服务采用单机处理,速度较慢,扩展不便。目前服务在处理数据时,需要清洗字段,按时间排序,统计某个字段出现的频率。这些步骤都是ETL中的常规操作,但目前都是以代码的形式实现的。我们要以配置的形式减少重复编码,尽可能的简单和通用。解决方案1:我们需要数据库吗?针对以上业务需求,有同学提出:“我们可以把原始数据全部放到数据库中,后续的ETL可以通过SQL来实现”。如果你一听到“数据库”就想到Pg、Mysql、Oracle等,觉得这个方案不可行,那你就错了。如下图所示,数据库的类型和维度非常丰富。根据业务负载的特点,关系型数据库可以分为OLTP数据库(事务型)和OLAP数据库(分析型):OLTP,OnlineTransactionProcessing。OLTP数据库最大的特点是支持事务,具有强大的增、删、查、改等功能,适合频繁修改的“热点数据”。我们熟悉的Mysql、Pg等都属于这一类。缺点是由于事务的支持,插入比较慢。用它来实现我们的需求展示是不合适的。OLAP,OnlineAnalyticalProcessing,基于数据分析。不支持事务,或对事务的支持有限。OLAP场景是:大部分是读请求,数据始终以相当大的批次(>1000行)写入,而不修改添加的数据。方案一总结OLAP的使用场景满足我们的需求,所以我们也专门调研了ClickHouse。但是有一个因素让我们最终放弃了使用OLAP。请注意,数据库中存储的数据是二维的,有行和列两个维度。但是日志只有一个维度的行。点,那么我们对统计字段的需求就很容易实现了,那为什么还要保存数据呢?因此,OLAP使用场景的一个隐藏特征就是:存储的数据需要多维度重复分析。只有这样才能将数据存储在数据库中的力量,比如我们现在需要简单的对日志进行变形,仍然以文本日志的形式输出,用OLAP是不合适的。解决方案2:为什么Hive不工作?看到这里,熟悉大数据的同学可能会觉得我们的水平很低,因为业务需求说到底就是三个字:“批处理”。(细化我们的需求,其实就是大数据的一个典型应用场景。大数据处理流程,见下图)那我们当初为什么不考虑大数据呢?大数据确实很流行,但是我们团队的大部分日志处理都是用Golang实现的,团队其他业务用的是Python、Lua、C。但是从来没有用到Java。目前大数据都是基于JVM开发的。Golang没有调用这些服务的有用客户端。所以,以团队目前的技术储备,大数据并没有成为我们的首选。但就目前的情况来看,大数据似乎是最优解。那么我们应该选择大数据的哪些组件来满足我们的需求呢?放弃使用数据库,直接使用HDFS来存储日志文件应该是毋庸置疑的。我们的需求是离线批量处理数据,对时效性没有要求,MapReduce和Hive都可以??满足要求。但是Hive相对于MapReduce和Hive,在MapReduce上做了一层封装,支持SQL。看来Hive很合适。那为什么我们最终放弃了Hive?无法批准资源。公司其他团队已经有了一套HDFS设施,只是用于存储,Hadoop的MapReduce组件根本没有跑起来。ve计算会影响他们当前HDFS的性能;想批新一批机器,重新用Ambari搭建一套Hadoop,却被告知没有那么多闲置机器资源。而且即使我们申请了机器,我们也只是运行目前服务还不够,大部分机器资源都会闲置,也有浪费资源的嫌疑。存储分离是一种趋势。我们在研究中发现,像Hadoop这样把存储和计算放在一起的,是比较“落伍”的。Hadoop存储分离需要修改源码。目前还没有开源实现,但是云厂商和各个大数据公司都有相关的商业产品。从这个角度看,即使拿到机器资源,自己搭建一套Hadoop,也只是浪费时间。方案2总结再合适的技术方案不能实施也是一句空话。但是,当一个技术方案要实施的时候,就不再是单纯的技术问题了。需要考虑资源限制、团队限制等。一个优秀的技术方案,是立足于解决当前的问题,并且能够展望未来,画出蓝图(“大饼”),让大家觉得“有利可图”,才愿意和你一起折腾。解决方案3:我们为什么放弃Spark?虽然一般的计算引擎使用HDFS团队不赞成我们在他们的机器上运行Hive,但是我们把日志数据存储在他们的HDFS上是没问题的。基于“存储和分离是趋势”的前提,“我们需要什么?”这个问题已经有了答案。我们需要的是一个通用的计算引擎。存储已经剥离到HDFS,所以我们只需要找一个工具来帮助我们处理ETL。Spark和Flink正是这样的场景。Spark初次接触Spark和Flink,我们毫不犹豫的选择了Spark。原因很简单:Spark适合批处理。Spark最初旨在替代MapReduce。后来加入了Spark流处理的能力,所以使用Spark进行批处理是得心应手的。Spark具有很高的成熟度。Spark已经发布到3.0,而Flink还处于Flink1.x阶段。Flink一直以流处理着称,虽然被国内某云收购,开始提倡“流批一体”t;,不过线上效果还有待测试。Scala的祝福。大部分Spark都是在Scala中实现的。Scala是一种多范式编程语言,与Haskell有着深厚的渊源。Haskell是一种著名的函数式编程语言。对于函数式编程语言,大多数程序员一定有一种“虽然不能实现,但又向往”的情结。现在使用Spark,您可以使用函数式编程语言Scala。这不是很好吗?出色地?泪割星火在上一篇文章中已经讲解过了。我们拒绝Hive的一个重要因素是我们没有足够的机器资源。所以我们直接在云平台上部署Spark。对于我们的云平台,我们需要添加一些细节。它是基于K8S二次开发的。通常我们使用的时候都是上传Docker镜像,然后启动Docker实例。不支持阿里云的“容器服务ACK”等功能。因此,我们采用“SparkonK8S”运行模式号。在这样的条件下,我们采用了“SparkStandalone”模式。Standalone模式,也就是MasterSlaver模式,类似于Nginx的架构。Master节点负责接收分发任务,Slaver节点负责“工作”。等到我们在云平台上以“SparkStandalone”模式部署完毕,跑了几个测试用例,发现问题又来了。我们的云平台与办公网络是隔离的,如果办公网络要访问云平台上的Docker容器,需要配置域名。在Spark的管理页面中,很多URL的域是其所在机器的IP,容器的IP是虚拟IP。虚拟IP会在容器重启后发生变化。具体图:Spark的管理平台很重要,因为它可以从上面我们可以看到当前各个节点的运行状态,任务的异常信息等,现在很多环节都无法访问,不利于我们排查问题和调整Spark任务。为此,我们最终放弃了Spark。方案三总结Spark你真的很优秀,你擅长批处理,你成熟的很,还有功能基因……这些优点早就吸引我了Spark你真是个好人,如果不是云平台的限制,我一定会选择你。斯帕克,对不起。方案四:Flink,真香!把好人卡发到Spark之后,我们来看看我们的新宠Flink。不客气地说,Flink早期很多实现都是从Spark抄来的,所以两者的很多概念是相似的。所以Flink也有Standard模式,我们在部署阶段也没有遇到什么问题。跑了几个Flink测试用例后,我们由衷地感叹Flink的芬芳!当我们放弃Spark的时候,我们的痛点是“部署在云平台上的Spark服务的管理接口很多功能都不能用”,而Flink的管理平台完全没有这个问题!此外,“颜值”和功能都是Spark无法比拟的。管理平台外观对比Spark管理平台页面(网络图片):Flink管理平台页面:相比之下,Spark页面完全是“黄脸婆”。Flink管理平台的功能由于Spark的功能很多无法使用,这里就不重点和Flink比较了。这里我们只说说Flink比较吸引人的一些功能。完善的RestfulAPI与Flink或Spark服务部署后,如何下发计算任务?一般是通过bin目录下一个名字包含submit的可执行程序。如果我们想把Flink或者Spark做成一个微服务,通过http接口发送任务怎么办?spark1.0支持http,2.0有这个功能,基本很多参数不支持,http的功能交给了第三方开源组件jobService。jobService这个开源组件对云平台也很不友好。所以在我们看来,Spark使用Http的方式来传递任务,基本是阻塞的。相对于Flink,管理平台的接口是Restful。不仅支持Http下发计算任务,还可以通过相关接口查看任务状态,获取异常或返回值。强大的任务分析能力Flink任务分为几个不同的阶段,每个阶段都有不同的颜色。这样,仅从颜色就可以判断出当前Flink任务执行的大概情况。如下图所示:在任务详情页面,会有任务分解图和任务执行耗时表,结合这两个可以知道Flink任务是怎么分解的,有没有数据倾斜,哪一步耗时最多,有没有优化的空间……
