共计 5725 个字符,预计需要花费 15 分钟才能阅读完成。
日前,由又拍云举办的大数据与 AI 技术实际|Open Talk 杭州站沙龙在杭州西溪科创园顺利举办。本次流动邀请了有赞、个推、方得智能、又拍云等公司核心技术开发者,现场分享各自畛域的大数据技术教训和心得。以下内容整顿自又拍云资深开发工程师张召现场分享:
张召,资深开发工程师,目前负责又拍云 CDN 的刷新预热、日志解决和运维平台开发。相熟 OpenResty,在 Web 开发畛域教训颇丰,目前热衷钻研大数据处理相干技术。
大家好,我是来自又拍云的张召,明天次要分享又拍云多数据源日志解决选型 Flink 的考量,以及 Flink 落地过程中遇到的问题和解决方案。
为什么用 Flink 做批处理
在选用 Flink 前,咱们对日志批处理的整个业务需要分为三步:数据源采集、日志解决、后果的保留。咱们的日志量在 100G/h,单机服务处理速度慢、扩容不不便,一些类似的需要都是以编码模式实现的。另外,数据处理流程简单,须要在多个服务间流转,迫切需要一个计划来解决问题。
后期咱们调研了数据库,发现数据库里没有多维度的重复总结和开掘的性能,所以咱们放弃了选用数据库的计划,选用 MapReduce 里的 hadoop 这条组件。理论生产中发现它常常在写入的时候呈现一些谬误,导致无奈做一些聚合的操作。接着咱们抉择了 Spark,新的问题又呈现了:提交工作时,Restful API 接口的反对不全面;web 控制台中虚构 IP 无法访问外部。
基于以上起因,咱们须要一个更好的解决方案。通过比拟之后,咱们发现了 Flink。Flink 躲避了后面所有的问题,前面还提供一套残缺的 Restful API。不仅可能渲染出这个页面,还能够通过 Submit New Job 间接提交工作。同时,咱们对老服务降级的过程中,逐步明确了咱们日志数据的特点,以及以后咱们须要开掘日志数据的哪些方面。 在盘点了手头上可调用的资源后,咱们心愿部署的服务整个零碎是可观测、可保护的,所以基于以上各种起因,最终咱们放弃 Spark 计划,抉择了 Flink。
Flink 基础知识
Flink 组件栈
如下图所示,这是一个分布式系统,整体也比较简单。最右边的 Flink Client 反对客户端当初的提交形式,前面谈判到它反对提交 Restful API 接口以及通过命令行等 5 种伎俩向这个 Job Manager 提交工作。
Job Manager 是分布式系统里的 master 节点,master 节点拿到数据之后会对架包进行剖析,而后把相干其余信息给传送到对应的 TaskManager 节点。TaskManager 节点拿到信息后才真正执行 Job,Job Manager 最次要的作用就是解析这个图以及维持整个集群,比方心跳、资源调度、HA 高可用、文件存储等,这是 Flink 提交工作 runtime 的过程。
接着看 Flink 动态的整体设计,底层是部署局部,稍后开展讲。两头的外围局部是 Runtime,别离封装了两个不同的 API:DataStream 是流解决,是当初 Flink 用的最多的场景;DataSet 是咱们用到的批处理形式。尽管当初 Flink 号称反对流批一体解决,然而它目前版本两个接口是离开的,往年 12 月发的 1.12 版本曾经不激励用 DataSet 相干的 API,这部分性能合到了 DataStream 里。但因为咱们部署的版本还在 1.1,没有降级,所以咱们还没有把这些 Job 迁到 DataStream 下来。
接下来咱们摸索最上层的 tabl circle,但应用的最终成果并不好,因为无论是文档里,还是代码里写的反对限度是比拟无限的。比方去执行 circle,但 circle 想把最终后果输入到 PG 外面的时候,它就呈现了一个 bug,它 PG 的数据库最终拼出来的地址是错的,它的 host 和 pot 少了一个反斜线。这个 bug 非常简单,然而当初都没有修复。所以我认为最上层这部分可能测试的还不欠缺,也不是很稳固。所以咱们最终代码的实现和业务集中编写也是放在调用的 DataSet API 这部分来做的。
另外咱们还做了些小的工作,咱们基于又拍云存储系统,扩大了它的相干性能,可能反对 Flink 的处理结果间接输入到云存储上,对整体代码起到简化作用。
JobManager 和 TaskManager
JobManager 的作用次要体现在外面的组件。比方 Dataflow Graph 能够把 Flink 客户端提交的架包剖析成一个能够执行的 graph,散发到上面的 TaskManager 节点外面去。另外一个咱们比拟关注的组件是 Actor System,它是由 ScadAKKA 异步网络组件实现的。咱们前期部署时发现有很多 AKKA time out 这类问题,这意味着 JobManager 组件和 TaskManager 组件进行通信的时候呈现了问题。
再看 TaskManager 次要关注的概念,当 TaskManager 和外界零碎产生交互时,它用的不是 actor 模型,actor 模型次要是异步通信,强调的是快。它和内部通信时,TaskManager 用的是 Netty,输出数据更加的稳固。
这里要着重关注一下 Task Slot 概念,一些分享的最佳实际案例提到 TaskManager 里的 slot 最好和以后机器 CPU 核数放弃 1:1 的设置。咱们最后依照 1:1 设计跑一些小的 job 的时候很好,但数据量上升时常常会呈现一些 time out 的问题。起因在于 Kubernetes 提供的 CPU 只是一个 CPU 的实际片,不能等同物理机上的 CPU,当在 TaskManager 下部署多个的时候,尽管它们的内存会被摊派掉,但 CPU 却是共享的。在这种情况下,整个 TaskManager 就不是特地稳固。所以咱们最终设置大略在 1:4 或 1:8。具体数据应该是从以后环境内的网络情况和经验值来确定的。
Flink 部署
刚开始部署 Flink 时,咱们是比拟懵的,因为 Flink 部署文档里介绍了很多模式,比方部署在 standalone,Kubernetes、YARN 或者是 Mesos,还有一些利用实际都比拟少的模式。尽管咱们在云平台上搞一个 Kubernetes 的操作,但咱们做不到间接应用 Kubernetes 托管式的服务,所以最终采纳的是 Standalone on Docker 模式,如下图所示:
- Standalone 模式下,Master 和 TaskManager 能够运行在同一台机器或者不同的机器上;
- Master 过程中,Standalone ResourceManager 的作用是对资源进行治理。当用户通过 Flink Cluster Client 将 JobGraph 提交给 Master 时,JobGraph 先通过 Dispatcher;
- 当 Dispatcher 收到申请,生成 JobManager。接着 JobManager 过程向 Standalone ResourceManager 申请资源,最终再启动 TaskManager;
- TaskManager 启动后,经验注册后 JobManager 将具体的 Task 工作分发给 TaskManager 去执行。
Flink 提交工作
Flink 提供丰盛的客户端操作提交工作和与工作进行交互,包含 Flink 命令行、Scala Shell、SQL Client、
Restful API 和 Web。
最重要的是命令行,其次是 SQL Client 用于提交 SQL 工作的运行,以及 Scala Shell 提交 Table API 的工作,还提供能够通过 http 形式进行调用的 Restful 服务,此外还有 Web 的形式能够提交工作。对咱们十分实用的是 Restful API 性能。目前的服务里,除了拉取原始日志这块代码没有动,其余一些 go 自研组件的统计、排序等后续的操作当初通通不必了,间接调用 Flink 相干的接口。
Flink 是一个异步执行的过程。调用接口传递工作后,紧接着会把 taster 的 ID 返还给你,后续的操作外面能够通过这个接口一直去轮循,发现当前任务的执行状况再进行下一步决策。综合来看,Flink 的 Restful API 接口,对于咱们这种异构的、非 JAVA 系的团队来说还是十分不便的。
应用批处理时遇到的问题
网络问题
当咱们逐渐迁徙日志服务时,开始日志量比拟小,Flink 运行的十分好;当发现它负载不了,呈现 GVM 堆谬误之类的问题时也只须要把相干参数调大就能够了,毕竟云平台上资源还是比拟富裕的,操作也很不便。
但当咱们越来越信赖它,一个 job 上百 G 流量时,整个 tap 图就变成一条线,网络问题就呈现了。此前有心跳超时或者工作重试之类的问题,咱们并不是特地在意,因为失败后 Flink 反对重试,咱们通过 restful 接口也可能感知到,所以失败就再试一次。然而随着前面的任务量加大,每运行一次代价就越来越大了,导致提交的越多以后整个集群就会越来越好转。
当这种上百 G 的日志批处理工作放进去后常常会呈现三类谬误:最下面红线画出的 akkaTimeout 问题是后面讲的 JobManager 和 TaskManager 互相通信呈现的问题;像心跳超时或链接被重置的问题也十分多。
为什么咱们没有齐全把这个问题解决掉呢?是因为咱们看了一些阿里的 Flink on K8S 的经验总结。大家有趣味也能够看一下。
这篇文章中面对同样的问题,阿里团队提出将网络放到 K8S 网络虚拟化会实现肯定的性能,咱们参考了这种解决方案。具体来说,须要对 Flink 配置进行一些调整,另外有一些波及 connection reset by peer 的操作:
调整 Flink 配置参数
- 调大网络容错性, 也就是配置参数中 timeout 相干的局部。比方心跳 5 秒一次超时了就调成 20 秒或者 30 秒,留神不能够齐全禁掉或者调到很大;
- 开启压缩。如果是以纯文本的模式或者不是压缩包的模式上传,Flink 会并行读取文件放慢处理速度,所以后期偏向上传解压后的文本;当网络开销变大后,咱们就抉择开启文件压缩,心愿通过 CPU 的压力大一点,尽量减少网络开销。此外,TaskManager 或者是 JobManager 和 TaskManager 之间进行通信也能够开启压缩;
- 利用缓存, 如
taskmanager.memory.network.fraction
等,参数配置比拟灵便; - 缩小单个 task manager 下 task slots 的数量。
Connection reset by peer
- 不要有异构网络环境(尽量不要跨机房拜访)
- 云服务商的机器配置网卡多队列 (将实例中的网络中断扩散给不同的 CPU 解决,从而晋升性能)
- 选取云服务商提供的高性能网络插件:例如阿里云的 Terway
- Host network,绕开 K8s 的虚拟化网络(须要肯定的开发量)
因为 Connection reset by peer 的计划波及到跨部门协调,施行起来比拟麻烦,所以咱们目前可能缓解网络问题的计划是对 Flink 配置进行一些调整,通过这种伎俩,以后集群的网络问题有了很大水平的缓解。
资源节约
standlone 模式下,整个集群配置资源的总额取决于以后所有 job 里最大的 job 须要的容量。如下图所示,最上面不同工作步骤之间拷贝的数据曾经达到了 150G+,可能缓解这种问题的方法是一直配置更大的参数。
但因为 Flink 这一套前面有一个 JVM 的虚拟机,JVM 虚拟机常常申请资源后并没有及时开释掉,所以一个容器一旦跑过一个工作后,内存就会飙下来。当一直拉大配置,且配置数量还那么多的状况下,如果咱们的工作只是做一个小时级的日志解决,导致真正用到的资源量很少,最终的成果也不是很好,造成资源节约。
job 卡死
在容量比拟大后,咱们发现会呈现 job 卡死,常常会呈现量大的 job 加载进行到一半的时候就卡住了。如下图所示(浅蓝色是曾经实现的,鲜绿色示意正在进行的),咱们试过不干涉它,那么这个工作就会三五个小时甚至是八个小时的短暂运行上来,直到它因为心跳超时这类的起因整体 cross 掉。
这个问题目前没有齐全定位进去,所以当初能采取的措施也只是通过 restful 接口查看工作的时候,给它设置一个最大的阈值。当超过这个阈值就认为这个工作曾经齐全坏掉了,再通过接口把它勾销掉。
Flink 带来的收益
下图所示是日志解决的某一环节,每一个小方块代表一个服务,整个服务的链路比拟长。当有多个数据源加载一个数据时,它会先 transfer porter 放到又拍云的云存储里,由 log-merge 服务进行转换,再依据以后服务的具体业务需要,最终才会存到云存储或者存到 redis。
工作和工作之间的连接是通过两种形式:一种是人为之间进行约定,比方我是你的上游组件,咱们约定提早 3 个小时,默认 3 个小时后你曾经数据处理好,我就去运行一次;第二种是用 ASQ,我解决完结后推送音讯,至于你生产不生产、生产是否胜利,上游不须要关怀。 尽管本来失常的状况下服务运行也很稳固,但一旦呈现问题再想定位、操纵整个零碎,追捕一些日志或重跑一些数据的时候就比拟苦楚。这一点在咱们引入到 Flink 后,整体上有十分大的改良。
目前只有工作治理局部是复用了之前的代码,相当于采集板块。采集好数据间接向 Flink 提交以后的 job,Flink 解决好后间接存进云存储。咱们的工作治理次要分两类性能,一个是采集,另一个是动静监控当前任务的进行后果。总的来看,重构后相当于造成了一个闭环,无论是 Flink 解决呈现问题,亦或是存储有问题,工作管理系统都会去重跑,相当于缩小一些前期的运维工作。
总结
抉择 standalone 零碎部署一套 Flink 零碎,又要它解决不是太善于的批处理,且量还比拟大,这是十分有挑战性的。充斥挑战的起因在于这不是 Flink 典型的利用场景,很多配置都做不到开箱即用,虽说号称反对批处理,但相干配置默认都是敞开的。这就须要调优,不过很文档里大多会写如果遇到某类问题就去调大某类值,至于调大多少齐全靠教训。
尽管如此,但因为以后 Flink 主推的也是流批一体化开发,咱们对 Flink 后续的倒退还是比拟有信念的。后面也讲了 Flink1.1 版本中,datesat 批处理的 API 和 stream 的 API 还是离开的,而在最新版本 1.12 中曾经开始交融在一起了,并且 datesat 局部曾经不倡议应用了。咱们置信沿着这个方向倒退,跟上社区的节奏,将来可期。
举荐浏览
有赞对立接入层架构演进
微服务架构下 CI/CD 如何落地