关于flink:Flink-on-K8s-在京东的持续优化实践

12次阅读

共计 7949 个字符,预计需要花费 20 分钟才能阅读完成。

摘要:本文整顿自京东资深技术专家付海涛在 Flink Forward Asia 2021 平台建设专场的演讲。次要内容包含:

  1. 根本介绍
  2. 生产实践
  3. 优化改良
  4. 将来布局

点击查看直播回放 & 演讲 PDF

一、根本介绍

K8s 是目前业内十分风行的容器编排和治理平台,它能够非常简单高效地治理云平台中多个主机上的容器化利用。在 2017 年左右,咱们实时计算是多个引擎并存的,包含 Storm、Spark Streaming 以及正在引入的新一代计算引擎 Flink,其中 Storm 集群运行在物理机上,Spark Streaming 运行在 YARN 上,不同的运行环境导致部署和经营老本特地高,且资源利用有肯定节约,所以迫切需要一个对立的集群资源管理和调度零碎来解决这个问题。

而 K8s 能够很好地解决这些问题:它能够很不便地治理成千上万的容器化利用,易于部署和运维;很容易做到混合部署,将不同负载的服务比方在线服务、机器学习、流批计算等混合在一起,取得更好的资源利用;此外,它还具备人造容器隔离、原生弹性自愈的能力,能够提供更好的隔离性与安全性。

通过一系列的尝试、优化和性能比照后,咱们抉择了 K8s。

2018 年初,实时计算平台开始全面容器化革新;到 2018 年 6 月,曾经有 20% 的工作运行在 K8s 上,从运行后果看,无论是资源的共享能力、还是业务解决能力,以及敏捷性和效率方面都取得了较大晋升,初步达到了预期的成果;到 2019 年 2 月实现了实时计算全副容器化;之后直到现在,咱们在 K8s 的环境也始终在进行优化和实际,比方进行弹性伸缩、服务混部、工作疾速恢复能力建设等方面的实际。

全副 on K8s 后收益还是比拟显著的:首先混合部署服务和资源共享能力取得了晋升,节俭机器资源 30%;其次,具备更好的资源隔离和弹性自愈能力,比拟容易实现依据业务的负载进行资源的弹性伸缩,保障了业务的稳定性;最初开发、测试、生产一致性的环境,防止环境给整个开发过程带来问题,同时极大晋升了部署和经营自动化的能力,升高了治理运维的老本。

京东 Flink on K8s 的平台架构如上图,最上面是物理机和云主机,之上是 K8s,它采纳京东自研的 JDOS 平台,基于规范的 K8s 进行了许多定制优化,使之更适应咱们生产环境的理论状况。JDOS 大部分运行在物理机上,少部分是在云主机上。再往上是基于社区版 Flink 进行深度定制化后的 Flink 引擎。

最下面就是京东的实时计算平台 JRC,反对 SQL 作业和 jar 包作业,提供高吞吐、低提早、高可用、弹性自愈易用的一站式海量流批数据计算能力,反对丰盛的数据源和指标源,具备欠缺的作业管理、配置、部署、日志监控和自运维的性能,提供备份回滚和一键迁徙的性能。

咱们的实时计算平台服务于京东外部十分多的业务线,次要利用场景包含实时数仓,实时大屏、实时举荐、实时报表、实时风控和实时监控以及其余的利用场景。目前咱们的实时 K8s 集群由 7000 多台机器组成,线上 Flink 工作数有 5000 多,数据处理峰值能够达到每秒 10 亿多条。

二、生产实践

最开始容器化计划采纳的是基于 K8s deployment 部署的 standalone session 集群,这是资源动态调配的模式,如上图所示,须要用户在创立的时候就决定好所须要的治理节点 Jobmanager 的个数和规格 (包含 CPU 的核数、内存和磁盘的大小等)、运行节点 Taskmanager 的个数和规格 (包含 CPU、内存和磁盘大小等),以及 Taskmanager 蕴含的 slot 个数。创立集群后,JRC 平台通过 K8s 客户端向 K8s master 发出请求,创立 Jobmanager 的 deployment,这里应用 ZK 保障高可用,应用 HDFS 和 OSS 进行状态存储,集群创立实现后就能够提交工作了。

然而在咱们实际的过程中发现该计划存在一些有余,它须要业务提前预估出所须要的资源,对业务不太敌对,无奈满足灵便多变的业务场景。比方对一些简单拓扑或者一个集群跑多个工作的场景,业务很难事后精准确定出所须要资源,这时候个别都会先创立出一个较大的集群,这样就会带来肯定的资源节约。在工作运行的过程中,也没有方法依据工作的运行状况,按需进行资源的动静伸缩。

于是咱们又对容器化计划进行了降级,反对弹性资源模式。这是采纳资源按需分配的形式,如上图所示,它须要用户在创立时指定好所须要治理节点 Jobmanager 的个数和规格,以及运行节点 Taskmanager 的规格,而 Taskmanager 的个数能够不指定。点击创立集群后,JRC 平台会通过 K8s 客户端向 K8s master 发出请求,创立 Jobmanager 的 deployment 以及可选地预创立指定数量 Taskmanager 的 pod。

平台提交工作后,由 JobMaster 通过 JDResourceManager 向 JRC 平台收回申请资源的 rest 申请,而后平台向 K8s master 动静申请资源去创立运行 Taskmanager 的 pod,在运行过程中,如果发现某个 Taskmanager 长时间闲暇,能够依据配置动静开释资源。这里通过平台与 K8s 交互进行资源的创立和销毁,次要是为了保障计算平台对资源的管控,同时防止了集群配置和逻辑变动对镜像的影响;通过反对用户配置 Taskmanager 个数进行资源的预调配,能够做到与资源动态调配同样疾速的工作提交速度;同时通过定制资源分配策略,能够做到兼容原有 slot 扩散散布的平衡调度。

在 Flink on K8s 的环境中,日志和监控指标是十分重要的,它能够帮忙咱们察看整个集群、容器、工作的运行状况,依据日志和监控疾速定位问题并及时处理。

这里的监控指标包含物理机指标 (比方 CPU、内存、负载、网络、连通性、磁盘等指标)、容器指标 (比方 CPU、内存、网络等指标)、JVM 指标和 Flink 指标 (集群指标和工作指标)。其中物理机指标和容器指标是通过 metric agent 采集上报到 Origin 零碎,JVM 指标和 Flink 指标是通过 Jobmanager 和 Taskmanager 中定制的 metric reporter 上报到白泽零碎,之后对立在计算平台进行监控的查看和告警。

日志采集采纳京东的 Logbook 服务,它的根本机制是在每个 Node 上会运行一个 log agent,用于采集指定门路的日志;而后 Jobmanager 或 Taskmanager 会依照指定规定输入日志到指定目录,之后日志就会被主动采集到 Logbook 零碎;最初能够通过计算平台进行实时日志和历史日志的检索和查问。

接下来是容器网络的性能问题。一般来说虚拟化的货色都会带来肯定的性能损耗,容器网络作为容器虚拟化的一个重要组件,相比物理机网络来说,不可避免地会呈现一些性能的损耗。性能的降落水平依据网络插件的不同、协定类型和数据包的大小会有所不同。

如上图所示,是对于跨主机容器网络通信的性能测评。参考基线是 server 和 client 在同一主机上进行通信。从图中能够看到,host 模式获得了靠近参考基线的吞吐量和提早,NAT 和 Calico 有较大的性能损失,这是因为地址转换和网络包路由的开销导致的;而所有 overlay 网络都有十分大的性能损失。总的来说,网络包的封装和解封相比地址转换和路由来说开销更大,那么采纳何种网络就须要做一个衡量。比方 overlay 网络因为网络包的封装和解封导致了很大的开销,性能会比拟差,但容许更灵便和平安的网络管理;NAT 和主机模式的网络比拟容易获得好的性能,然而安全性较差;Routing 网络性能也不错但须要额定的反对。

此外,网络损耗对于 checkpoint 的快慢影响也很大。依据咱们比照测试,网络模式不同的状况下,同样的环境下运行同样的工作,采纳容器网络工作的 checkpoint 时长比应用主机网络慢了一倍以上。那么怎么解决这个容器网络的性能问题?

  • 一是能够依据机房环境抉择适合的网络模式:比方对于咱们一些旧的机房,容器网络性能降落特地显著,而且网络的架构也不能降级,采纳了主机网络 (如上图所示,在 pod yaml 文件中配置 hostNetwork=true) 来防止损耗的问题,虽说这不太合乎 K8s 的格调,但须要依据条件做个衡量;而对于新的机房,因为根底网络的性能晋升以及采纳了新的高性能网络插件,性能损耗相比主机网十分小,就采纳了容器网;
  • 二是尽量不要应用异构网络环境,防止 K8s 跨机房,同时适当调整集群网络的相干参数,减少网络的容错能力。比方能够适当调大 akka.ask.timeouttaskmanager.network.request-backoff.max 两个参数。

上面说一下磁盘的性能问题。容器中的存储空间由两局部组成,如上图所示,底层是只读的镜像层,顶部是可读写的容器层。容器运行的时候波及到文件的写操作都是在容器层中实现的,这里须要一个存储驱动提供联结文件系统来治理。存储驱动一般来说为空间效率进行了优化,额定的形象会带来肯定的性能损耗 (取决于具体存储驱动),写入速度要低于本地文件系统,特地是应用了写时复制的存储驱动来说,损耗更大。这对于写密集型的利用来说,会有更大的性能影响。而在 Flink 中,很多中央都波及到本地磁盘的读写,比方日志输入、RocksDB 读写、批工作 shuffle 等。那么该如何解决来减小影响?

  • 一是能够思考应用外挂的 Volume,应用本地存储卷,间接写数据到 host fileSystem 来晋升性能;
  • 此外也能够调优磁盘 IO 相干参数,比方调优 RocksDB 参数,晋升磁盘的拜访性能;
  • 最初也能够思考采纳一些存储计算拆散的计划,比方应用 remote shuffle,晋升本地 shuffle 的性能和稳定性。

在实际过程中常常会发现,很多业务的计算工作配置不合理,占用了过多的资源造成了资源节约。此外,流量存在波峰波谷,如何在洪峰时主动扩容,在波谷时主动缩容,在缩小人工干预、保障业务稳固的同时进步资源利用率,这都波及到资源弹性伸缩的问题。为此咱们开发了弹性伸缩的服务,依据作业运行状况动静调整工作的并行度以及 Taskmanager 的规格,来解决作业吞吐有余、资源节约等问题。

如上图所示,大抵的工作流程如下:首先在 JRC 平台进行工作的伸缩配置,次要包含运行度调整的上上限以及一些伸缩策略的阈值,这些配置都会发送到伸缩服务;伸缩服务运行过程中会实时监测集群和工作的运行指标 (次要是一些 CPU 的使用率和算子的忙碌水平等),联合伸缩配置和调整策略生成工作调整后果,发送到 JRC 平台;最初 JRC 平台依据调整后果,对集群和工作进行调整。

目前通过该伸缩服务,能够较好地解决一些场景的资源节约问题,以及工作吞吐与算子并行度呈线性关系条件下的性能问题。不过它还是存在肯定的局限性,比方对于内部的零碎瓶颈、数据歪斜以及工作自身的性能瓶颈还有无奈通过扩并行度晋升的场景,不能很好地应答解决。

此外,联合弹性伸缩,咱们也进行了一些实时流工作和离线批工作错峰混部的尝试。如上图右所示,在凌晨前后,流工作比拟闲暇,会缩容开释出一些资源给批工作;之后能够应用这些开释的资源在夜间运行批工作;到了白天批工作运行完开释的资源又能够还给流工作,用于扩容以应答流量洪峰,从而进步资源的整体利用率。

相比物理机或 YARN 环境,Flink on K8s 呈现问题当前的排查绝对要更艰难,因为这外面还波及到 K8s 许多组件,比方容器网络、DNS 解析、K8s 调度等各方面的问题,都存在肯定的门槛。

为了解决这个问题,咱们开发了智能诊断的服务,将作业相干的各个维度的监控指标 (包含物理机的、容器的、集群的和工作的指标) 与工作拓扑联合起来并与 K8s 买通,联合 pod 日志和工作日志联结进行剖析,并将日常人工运维的一些办法进行演绎总结利用到剖析策略中,诊断出作业的问题并给出优化倡议。目前反对对工作重启、工作背压、checkpoint 失败、集群资源利用率低等一些常见问题进行诊断,后续会继续丰盛和欠缺。

三、优化改良

在实际的过程中,采纳资源动态分配模式的时候,个别都会将 slot 依照 Taskmanager 打散,将消耗资源的算子依照 Taskmanager 分散开来,实现作业的平衡调度,进步作业的性能。

如右上图所示有 2 个 Taskmanager,每个 Taskmanager 有 4 个 slot,1 个作业有 2 个算子 (别离用绿色和红色示意),每个算子 2 个并行度。在应用默认调度策略 (程序调度) 的状况下,这个作业的所有算子都会集中在一个 Taskmanager;而如果应用平衡调度,这个作业的所有算子都会依照 Taskmanager 进行横向打散,每个 Taskmanager 都会分到两个算子的一个并行度 (绿色和红色)。

而在采纳资源动态分配模式 (native K8s) 的时候,资源是一个个 pod 独自申请创立的,那么这个时候如何实现平衡调度呢?咱们采纳了在任务调度之前进行资源预调配的形式来解决这个问题。具体过程如下:用户提交作业后,如果开启了资源预调配,JobMaster 不会立刻调度工作,而是会向 ResourceManager 一次性预申请作业所需的资源,在所需资源到位后,JobMaster 会失去告诉,此时再调度工作就能够做到和动态资源分配模式时同样的平衡调度了。这里还能够给 JobMaster 配置一个超时工夫,超时后就走失常任务调度流程,而不会有限地期待资源。

咱们进行了实在场景的性能比照,如上图右所示,应用程序调度的时候作业吞吐量为 5700 万 / 分钟,而开启了资源预调配和平衡调度后,作业吞吐量为 8947 万 / 分钟,性能晋升了 57%,还是有比拟显著的成果的。

咱们平台有不少业务采纳一个集群运行多个工作的模式,这样就会存在一个 Taskmanager 散布了不同 job 的 Task,从而导致不同 job 之间相互影响。那么如何解决这个问题?

咱们定制了 slot 的调配策略,在 Jobmanager 向 ResourceManager 申请 slot 时,如果开启了工作资源隔离,SlotManager 会把曾经调配 slot 的 Taskmanager 打上 job 的标签,之后该 Taskmanager 的闲暇 slot 只能用于该 job 的 slot 申请。通过将 Taskmanager 依照 job 分组,实现了集群多任务的资源隔离。

如上图右所示,一个 Taskmanager 提供 3 个 slot,有 3 个 job,每个 job 有一个算子,且并行度都为 3 (别离用绿色、蓝色和红色示意)。开启 slot 平铺扩散,在隔离前,这三个 job 会共享这三个 Taskmanager,每个 Taskmanager 上都散布了每个 job 的一个并行度。而在开启工作资源隔离后,每一个 job 部将会独占一个 Taskmanager,不会相互影响。

容器环境复杂多变,pod 被驱赶或重启时有发生:比方机器产生硬件故障、docker 故障、节点负载较低等都会导致 pod 被驱赶;过程不衰弱、过程异样退出、docker 异样重启等也都会导致 pod 重启。此时,会导致工作重启复原,对业务造成影响。那么如何能力缩小对业务的影响?

一个方面是针对容器环境,放慢 pod 异样 (被驱赶或重启) 的感知速度,迅速复原作业。在官网的默认实现中,如果 pod 产生异样,可能会从两个门路感知到:一个是故障 pod 上游算子可能会感知到网络连接的断开,从而引发异样触发 failover;一个是 Jobmanager 会首先感觉到 Taskmanager 心跳超时,此时也会触发 failover。无论是通过哪个门路,所须要的时长都会比超时要多一些,在咱们默认系统配置下,所需的工夫是 60 多秒。

这里咱们优化了 pod 异样感知的速度。在 pod 异样被进行时,默认会有一个 30 秒的优雅进行的工夫,此时容器主过程启动脚本会收到来自 K8s 的 TERM 信号,除了做必要的清理动作之外,咱们减少了告诉 Jobmanager 异样 Taskmanager 的环节;在容器内工作过程 Taskmanager 异样退出的时候,主过程 (这里是启动脚本) 也会感知到,也会告诉 Jobmanager 是哪个 Taskmanager 产生了异样。这样一来,Jobmanager 就能够在 pod 异样的时候第一工夫失去告诉,并及时进行作业的故障复原。

通过这项优化,测试典型场景下,在集群有空余资源的状况下,工作 failover 的时长从原来的 60 多秒缩短到几秒;在集群中没有空余资源须要期待 pod 重建的状况下,工作 failover 的时长也缩短了 30 多秒,成果还是比拟显著的。

另外一个方面是减小 pod 异样对作业的影响范畴。虽说社区版在 1.9 之后,提供了基于 region 的部分复原策略,在 Task 产生故障时,只重启故障 Task 关联 region 内的 Task,在有的场景下能够减小影响。然而很多时候一个作业的算子之间都是 rebalance 或者 hash 等全连贯的形式,region 策略也起不到太大作用。为此,咱们在 1.10 和 1.12 版本中,开发了基于故障 Task 的单点故障复原策略,Task 产生故障时只复原该故障 Task,非故障 Task 不受影响。

如上图所示,这个作业有三个算子 source、map 和 sink。其中 source 和 map 都是 1 个并行度,sink 是 2 个并行度。map 的第一个并行度 map(1/1) 和 sink 的第二个并行度 sink(2/2) 散布在 pod_B 上,在 pod_B 被驱赶的时候,Jobmanager 会检测到 pod_B 异样,之后会在新的 pod_D 上重新部署这两个 Task,记为 map(1/1)’和 sink(2/2)’;部署实现后,会告诉故障 Task map(1/1) 的上游 sink(1/1) 新的上游 Task map(1/1)’曾经 ready,而后 sink(1/1) 就会和上游 map(1/1)’从新建设连贯,进行通信。

在具体实现的时候有以下几点须要留神:

  • 一是故障复原前,故障 Task 的上游对于待发送数据和上游对于接管的残留数据如何进行解决?这里咱们会将上游输入到故障 Task 数据间接抛弃掉,上游如果收集到不残缺的数据也会抛弃掉;
  • 二是上下游无奈感知到对方异样时,再复原的时候如何进行解决?这里可能须要一个强制的更新解决;
  • 三是一个 pod 上散布了多个 Task 的状况,如果该 pod 异样,存在多个故障 Task,这些故障 Task 之间如果存在依赖关系,如何正确地进行解决?这里须要依照依赖关系进行程序的部署。

通过单点复原策略,在线利用获得了不错的成果,对作业的影响范畴大大减少 (取于具体的作业,可能缩小为原来的几十分之一到几百分之一),防止了业务的断流,同时复原时长也大大降低 (从典型场景的一分多钟升高到几秒 – 几十秒)。

当然,这个策略也是有代价的,它在复原的时候会带来大量的丢数,实用于对大量丢数不敏感的业务场景,比方流量业务。

四、将来布局

将来咱们会在以下几方面持续摸索:

  • 首先是调度优化:

    • 一个是 K8s 层面资源调度优化,更高效地治理大数据的在线服务和离线作业,晋升 K8s 集群的利用率和运行效率;
    • 一个是 Flink 作业调度优化,反对更丰盛、更细粒度的调度策略,晋升 Flink 作业资源的利用率和稳定性,满足不同的业务场景须要。
  • 其次是服务混部:将不同负载的服务混部在一起,在保障服务稳固的前提下尽量晋升资源利用率,使服务器的价值最大化;
  • 而后是智能运维:反对对工作进行智能诊断,并自适应调整运行参数,实现作业的资质,升高用户调优和平台运维的老本;
  • 最初是 Flink AI 的反对:人工智能利用场景中,Flink 在包含特色工程、在线学习、资源预测等方面都有一些独特的劣势,后续咱们也将在这些场景从平台层面进行摸索和实际。

点击查看直播回放 & 演讲 PDF

更多 Flink 相干技术问题,可扫码退出社区钉钉交换群
第一工夫获取最新技术文章和社区动静,请关注公众号~

正文完
 0