APP下载

Hadoop2.0系统中的资源分配与动态监控实践

2021-06-16张博

电子技术与软件工程 2021年5期
关键词:流式队列运算

张博

(每锐软件(上海)有限公司(Marin Software)上海市 200011)

1 引言

信息化社会中的信息爆炸引发了数据量的大幅增长。传统数据处理器已经很难快速高效地在经济实用的条件下完成数据实时运算。服务器联同协作成为大规模数据处理的发展方向。在此背景之下,大数据运算平台应运而生,其中以Apache 基金会旗下的Hadoop 项目最为知名。得益于其开源特性,Hadoop 被许多大学、研究所与商业公司广泛采用,在大数据领域已经成为广为接受的基准平台。与此同时,为了方便使用者更简便快捷的在Hadoop 平台上实现分布式运算,许多分布式运算框架被研发与发行,其中Spark 以其突出的基于内存存取的高性能运算,自推出之时,便成为了学术界与工业界重要的关注与应用对象。

然而,大规模数据集所带来的问题并不止于数据量的大幅增长,数据结构的复杂性与差异性导致各个数据之间运算量差异亦十分明显。直接的结果就是导致了Spark 工作集的多样化。不同种类的Spark 工作,其生存周期与资源消耗各不相同。当大量多种类Spark工作同时出现在同一个Hadoop 平台上时,运算资源的不当分配极易导致大量微型工作被阻塞,等待资源,直至超时。当数据量极大,例如运算峰值阶段的平台资源紧张时期,各个Spark 工作会因为资源争抢,导致相互阻塞,数据运算因为各个Spark 工作均无法取得足够资源而停顿,致使整个Hadoop 平台产生系统死锁,工作流停顿。

问题产生的根源是Spark 工作多样性与单一的资源分配规则之间的矛盾。故而,在Hadoop 平台搭配Spark 框架支持大规模数据运算的实践中,Spark 工作集应该被系统化分类,采用不同的分配原则,避免数据流高峰时刻因资源争抢而导致的相互阻塞。此外,Hadoop 平台资源高利用率阶段出现性能下降是正常的反应,与工作流完全阻塞相比,两者在短时间内会呈现相同现象,而长时间的人工观测在此情境下并不经济可取。因此,固定的监控规则需要进行动态化改良,使其可以根据平台负载量与工作流阻塞的特定现象自动调整监控阈值,从而大幅降低监控系统的误报率,尽力削减非必要的运维成本。在大数据平台运算资源的合理分配与动态监控系统的配合之下,大数据平台可以更加稳定、健壮、高效的承受大规模多样化Spark 工作流带来的系统压力。

本文后续篇章将主要分为几个部分:Hadoop 平台与Spark 框架的架构介绍,工作流阻塞问题的生成机理,资源分配规则与动态监控,与最终的经验总结。

2 系统架构介绍

本章节将由两个部分组成:

(1)Hadoop2.0/YARN 平台与相关系统的架构介绍;

(2)Spark 框架与各Spark 工作集种类的介绍。

图1:Hadoop 2.0 架构

作为被广泛应用的大数据平台与分布式框架,Hadoop 与Spark其本身内部的架构缺陷并不会对使用者造成严重影响。然而当多套系统与框架需要协同工作、合并运行时,两者结构上的不同便会在极端条件下产生严重的负面影响。对于Hadoop 平台与Spark 工作流内部架构与种类的理解将会成为重要的知识背景,在其帮助下,读者会更加容易和有条理地理解这种协作系统下问题的产生根源。

2.1 Hadoop2.0/YARN平台与相关系统的架构介绍

自2013年推出Hadoop2.0 以来,Hadoop 平台已经摆脱了MapReduce 框架的束缚,从单一的HDFS+MapReduce 模式,变得更为开放与多元化。其中最大的改变,就是将工作调度元件从MapReduce 框架中分离出来,成为了独立的Hadoop 构件,被命名为YARN。基础的Hadoop 架构从此变成了三级结构(如图1 所示)。本段落将着重介绍工作调度与资源监控构件YARN 的内部结构与单/多租户条件下的资源使用规则。

2.1.1 YARN 的系统结构

作为Hadoop2.0 的核心构件之一,YARN 的主要目的是实现跨服务器平台的整体资源监控与分布其上的工作调度,其监控管理的主要资源类型是内存。YARN 采取了经典的主从式(Master-Slave)分布式结构。这种结构实现方法简单明了,架构清晰,算法简明扼要。缺点亦十分明显,主控节点的单点故障容易导致整个平台瘫痪。然而,随着多个版本的更新,Hadoop2.0 平台已经可以通过待机节点切换的高可用模式来规避单点故障,从而被业界所接受并将其放心地用于生产环境。

(1)从系统层级来看, 它由一个平台级监控中心ResourceManager(RM)和各个服务器各自独有的托管代理模块NodeManager(NM)构成。通过这样的架构,YARN 可以全面掌控整个平台内各个服务器的健康与资源消耗情况,并为工作调度提供了充足的信息支持。YARN 将整个平台的资源视为一个整体,再根据客户请求与配置,将资源切割为一个个独立的资源块分配给其进行数据处理。

(2)从客户请求工作层级来看,每一个工作请求,都实际上由一组资源块构成。每个资源块各包含(有且只有)一个模块。在众多模块中,有一个为主控模块(ApplicationMaster:AM),其余都是受其监控管理的工作模块(YarnChild:YC)。在客户请求工作期间,这些资源块统一由AM 监控管理,不再受系统约束,直至请求完成,将它们归还系统。

图2:YARN 双层分布式系统与客户请求的生命周期

图3:Oozie 工作层级与YARN 的逻辑关系

综上所述,YARN 的内部结构其实是一个双层主从式分布式系统,其包含了系统级(RM+NM)与依赖其上的客户请求工作级(AM+YC)两部分,如图2 所示。本文主旨所要讨论的问题便与客户请求工作层级密切相关。

2.1.2 YARN 中单/多租户条件下的资源使用规则

YARN 中的资源使用规则主要由客户请求中各资源块的生命周期,既客户请求的工作流程,所决定。其工作流程可以分为8 个阶段(图2,序号标示):

(1)客户向RM 提交请求;

(2)RM 寻找空闲的NM;

(3)NM 在RM 的要求下,为客户请求创建AM;

(4)基于对客户请求的分析,AM 联系RM,以取得用于数据处理的运算资源;

(5)依照AM 提出的要求,RM 寻找合适的NM;

(6)NM 根据RM 的要求,创建多个YC 以满足AM 的需求;

(7)YC 完成数据处理,并将各自的结果返回给AM;

(8)AM 对收集到的分散结果进行总结合并,然后将最终结果返回客户。

由此工作流程,YARN 中的资源使用规则可以被总结为以下几点:

(1)被单租客客户请求消耗的资源Rrequest,可分为RAM和RYC,其关系如公式1 所示(n 表示YC 的数量)。

(2)在多租户多请求并行状态下,YARN 集群的资源RYARN分配如公式2 所示,其中Ridle表示空闲资源,m 表示客户请求的数量,n 表示YC 工作模块的数量。

(3)每一个客户请求,有且只有一个AM,而且其生命周期贯穿整个运算过程。

(4)YC才是数据处理的主要模块,其数量n由AM的需求决定,生命周期亦不固定,只取决于各自的数据处理工作是否完成。

2.1.3 Oozie 的介绍与应用

Oozie 是Hadoop 2.0 大数据平台生态环境中的一个附属构件,同属Apache 基金会旗下。其主旨是帮助使用者实现大规模Hadoop工作流的顺序调度。通过应用有向无环图(DAG)算法,Oozie可以实现Hadoop 工作流中复杂逻辑关系的编排。在Oozie 中,工作流分为三个层级:Bundle 工作级,Coordinator 工作级,和Workflow 工作级(如图3 所示)。其中,只有workflow 工作级和YARN 有交互关系,Bundle 和Coordinator 两个级别都只是一个逻辑层级存在于Oozie 中,既Bundle 工作和Coordinator 工作最终都会落实到子Workflow 工作中,并由其最后在YARN 中实现。

在使用Oozie 编排Spark 工作流时,Workflow 工作会先在YARN 中启动一个MapReduce 工作,其被命名为Oozie_launcher。Oozie_launcher 是相关Spark 工作在YARN 中的母进程,它将依据Oozie 中的设定与配置实时监控Spark 工作的进度并保证其始终遵循Oozie 的逻辑顺序运行;在Spark 工作因意外中止时,亦由Oozie_launcher 负责其错误信息的收集与工作的重启。

得益于Oozie 的协作,使用者可以批量管理并行工作,并实现工作流间复杂的逻辑运行关系。然而,这种架构的劣势也很明显。除了Spark 工作流外,Oozie 会为每个Spark 工作都另外创建一个MapReduce 工作,这就使工作流在数量上翻升了一倍,其资源使用分布如公式3 与公式4 所示。在处理大型数据集的工作流中,既∑0mRspark远远大于∑0mRoozie_launcher时,这样的负面影响并不明显;但在中小微型数据集工作流中时),非工作模块的资源占比r(公式(5)所示)会大幅上升,当Hadoop 平台遇到足够大规模的工作流负载时,平台的运算与资源压力将会变得更加巨大,为系统死锁埋下隐患。

2.2 Spark框架与各Spark工作集种类的介绍

由图1 可知,Hadoop2.0 不仅支持 MapReduce,Spark 也成为可用框架之一。在对于运算性能有要求的情境下,Spark 成为了更受欢迎的选项而被广泛应用在测试与生产环境中。Spark 框架在结构上完全遵守YARN 的客户请求工作层级架构,采用主从分布式结构。一个运行的Spark 工作由一个主控模块SparkAM和一组受其监控的工作模块SparkYC组成,其资源消耗亦符合公式1 所示。

Spark 工作的原生种类大体可分为两种:流式数据作业模式与存储式数据作业模式

(1)流式数据作业模式:此种模式下的Spark 工作是一种长期运行的微服务类工作,它们长期运行于Hadoop 集群上,实时于内存中处理网络上传输来的流式数据,并将最终结果存于HDFS 以备后用或实时反馈给客户。

(2)存储式数据作业模式:此类Spark 工作的处理对象并非网络实时传输的流式数据,而是HDFS 中的预存数据。这类工作的工作原理与MapReduce 类似,但得益于纯内存间数据运算与传输,相较于MapReduce 工作中Map 与Reduce 任务之间shuffle 阶段的落磁盘操作,其性能更为强大。其早期版本与Hadoop1.0 系统的性能对比中,就有近100 倍[1]的性能优势。

Spark 框架的两种工作模式搭配上Oozie 的编排服务,便可以衍生出了多种工作种类。在互联网企业中,使用较多的工作种类主要包含以下四种:

(1)流式数据工作:此类工作主要便是针对网络中传输的流式数据,是典型的资源密集型工作种类。其特点为,长时间运行,资源消耗量大且稳定,不会轻易释放占有的运算资源。

(2)微型存储式数据工作:微型存储式数据工作大多是基于事件而诱发的微小型工作。单个工作资源用量小,运行时间短,相较于大数据平台,几乎可以忽略不计。但此类工作往往成群出现,且数量极大,非常容易在Hadoop 平台中造成短时间内负载高峰。然而,在平台负载出现拥堵时,此类工作群的出现,会大幅加剧资源的争抢力度。平台拥堵大都由工作量的提升而引起,此时工作群的数量也大概率会出现提升,资源使用总量相较平时也会增加,可用资源在现有运行工作间的争抢力度,既平台拥堵程度,会出现骤增。同时,由于各个工作均无法获得足够的运算资源,导致运行时间加长,使得平台的拥堵时段亦被延长。此外,由于其巨大的工作数量,一旦出现此情况,平台的等待工作数量与等待时间,都会大幅增长。

(3)编排预设工作:此类工作本身也属于存储式数据工作,其资源使用量一般小于流式数据工作,但远高于微型工作。与前两者的最大区别在于,在Oozie 的编排服务辅助下,它可以根据用户的需求,预设工作时段。既不需要长期运行于平台上占用资源;也并非完全基于事件,不可预控;而是将一个预设时间段内的请求积累起来,定时启动一个工作将其批次处理。而其缺点相较于流式数据工作也十分明显,客户的请求不会被马上处理,结果并非实时反馈。此外,当一个时间段内工作量积累过多,无法按时完成时,会造成工作积压延后,延迟后续时段工作的运行。

(4)资源池工作:此类工作与编排预设工作类似。其区别在于,编排预设工作直接处理数据或是客户请求;而资源池工作会根据时段内积累的工作量,触发一系列子工作,并将工作切割分配给它们,所以资源池工作并非只有一个工作被定期重启,而是一组工作群。其优点十分明显,既工作子集的规模会随时段内工作量的变化而变化;但其运算结果亦并非实时数据,且并行子工作群使得实现难度大幅上升。

本章节就Hadoop2.0 系统的架构与Spark 框架中的工作种类进行了解释说明。下一章节会就系统资源的不当分配,在平台资源紧张时期,大概率造成系统死锁这一问题的产生机理进行分析与说明。

3 系统死锁的原理分析

本章节将会对多样化Spark 工作集在Hadoop2.0 平台上,于平台高负载资源紧张时,极易出现的两种系统死锁问题及其产生机理进行系统地分析说明。这两种系统死锁分别为:

(1)Oozie/YARN 死锁;

(2)AM/YC 死锁。

3.1 Oozie/YARN死锁

根据2.1.3 章节的介绍可知,Oozie 会为每一个运行于Hadoop2.0 平台上的Spark 工作创建一个监控程序Oozie_launcher。Oozie_launcher 作为Oozie 启动的监控程序,Spark 工作其本质是由Oozie_launcher 启动的子工作。这其中有几个特征非常重要:

(1)Oozie_launcher 必定先于Spark 工作被启动;

(2)Oozie_launcher 启动后,才会与YARN 商榷以获取新资源,用以启动Spark 工作。倘若此时平台空闲资源不足,Oozie_launcher 无法获取足够资源,则Spark 工作无法被启动。此时,Oozie_launcher 会一直与YARN 保持通信,等待分配资源;

(3)Oozie_launcher 会一直保持运行状态,并在整个Spark 工作的生命周期期间对其进行持续的监控。其只有确保Spark 工作结束后,才会结束,并释放被自己占用的资源。

由公式(3)已知,在Oozie 参与编排的Spark 工作流于Hadoop2.0 平台上运行时,其系统总资源RYARN是由Oozie_launcher占用的总资源∑0mRoozie_launcher,Spark 工作群占用的总资源∑0mRspark,与系统空闲资源Ridle三个部分构成。当平台遇到一个巨大的负载高峰时,Oozie 会于极短时间内启动大量Oozie_launcher,占用大量系统资源。当Ridle小于Rspark时,公式(3)可演化为公式(6)。

当公式6 所描述的现象在Hadoop2.0 平台中出现时,根据之前介绍的特征2 可知,Oozie_launcher 会一直保持运行状态,等待其他工作结束并释放资源,而后平台为其分配空闲资源以启动相关的Spark 工作。然而由特征3 亦可知,任何Oozie_launcher 都不会在相关Spark 工作结束前,释放资源。于是,在此情况下,Oozie/YARN 死锁生成:所有Oozie_launcher 都在等待其他Oozie_launcher 结束并释放资源来启动自有Spark 工作,但任一Oozie_launcher 都不会在自有Spark 工作结束前释放资源。

3.2 AM/YC死锁

除了Oozie/YARN 死锁这种情况外,还存在另外一种死锁现象,既AM/YC 死锁。顾名思义,这是发生在每个工作的AM 与YC 模块之间因资源争抢而发生的死锁现象。

由公式4 可知,在多租户条件下工作层级粒度中,平台总资源RYARN由Oozie_launcher 的AM和YC分别消耗的总资源以及Spark 工作的AM 和YC 分别消耗的总资源外加空闲资源Ridle,五个部分构成。其中,由公式(5)可知,Oozie_launcher 工 作与Spark 工作的AM 部分都不会涉及到真实的数据处理,而只负责相关工作系统级与工作内的监控与调度;只有Spark 工作的YC 模块会在Hadoop2.0 平台上并行地处理客户的实际请求。

由图2 的工作启动流程中可知,每个工作的AM 模块都是第一个被启动的,而后由AM 来启动、监控YC 模块,分配作业,并在YC 模块结束后收集整合结果,既AM 模块的生命周期会覆盖整个工作流程(所有YC 模块的生命周期)。当平台遇到一个巨大的负载高峰时,在所有Oozie_launcher 启动后,部分Spark 工作的AM模块也被创建出来,而后,平台的空闲资源不足以让任何Spark 工作启动任一YC 模块时,AM/YC 死锁便出现了。Oozie_launcher在等待Spark 工作结束,Spark 工作的AM 模块在等待YC 模块结束并返回结果;然而YC 模块因空闲资源不足,只能等待Oozie_launcher 和Spark 工作的AM 模块释放资源,才能够得以启动。此情况如公式(7)所示。

其实YARN 中提供了一系列参数(例如AMFairShare),以控制AM 模块的资源消耗量,为YC 模块留出足够资源余量以避免此种死锁现象。在种类单一的Hadoop 工作流中,这一机制运行良好,几乎完美地规避了AM/YC 死锁现象。然而如2.2 章节中所展示,在Oozie 参与的Spark 工作流中,工作种类并不单一,甚至许多种类间的资源消耗与运行模式差异极大。这就使得AMFairShare 这类简单的资源划分规则,无法有效阻止AM/YC 死锁以及与之类似的现象在复杂多样性高负载工作流运行期间频繁出现。

假设一个Spark 工作流中包含流式数据(SparkStreaming)与微型存储式数据(SparkStorage)两种工作类型(为了简化案例,此例中的所有Oozie_launcher 工作均被剔除)。那么正常情况下,Hadoop2.0平台的资源消耗应当如公式8 所示。可是通常流式数据工作资源消耗量极大,即便在所有AM 模块的资源消耗总量依然小于AMFairShare 设定的阈值时,整个平台的空闲资源可能已经无法为微型存储式数据工作的YC 模块提供足够资源,如公式(9)所示。由于流式数据工作会长期运行并占用资源,这就导致与其伴生的微型存储式数据工作流只要数量强度达到一定范围,AM/YC 死锁现象便会出现。而Oozie_launcher 工作的加入,只会使问题更为严峻。

以上所阐述的两种死锁问题,都是(1)运行中的工作/模块等待尚未启动的工作/模块返回结果才可以结束,(2)而未启动工作/模块等待运行中的工作/模块释放资源才可以启动,这两者相互冲突而造成的系统死锁。其本质上相同,都是整体平台缺乏对资源的合理科学分配而引起的混乱资源争抢行为所导致的结果。此类问题在平台空闲或非繁忙时段不会产生任何影响,但在平台高负载时段,却极有可能导致整个平台系统死锁,运算服务中止。此外,因为系统死锁的产生原因并非Hadoop 平台构件问题导致,也非Spark 框架内部缺陷引起,这就使得系统死锁发生时,所有系统部件与工作日志都显示正常,与平台实际工作状态不符。

以下两个章节将重点讲解用以解决此问题的按队列分配资源原理,以及依托第三方监控软件Nagios 及其脚本插件所实现的动态监控。经长时间应用得以证明,正确有效的资源管理可以大幅降低系统死锁的发生概率。即便在系统死锁发生初期,得益于对YARN资源队列的动态监控,系统本身也可以正确有效地预警此类问题。

4 Hadoop2.0/YARN平台的资源分列分配

由第三章节的论述可知,Hadoop2.0 大数据集平台在面对多样性大规模Spark 工作流负载时,极易产生系统死锁。而产生的核心本质就是平台运算资源在各种Spark 工作间的不合理分配,导致资源争抢,进而产生系统死锁。本文中所指出的资源不合理分配行为包含两点:

(1)所有种类的Spark 工作被推送入同一运行队列,并未按照特定规则分类管理;

(2)在可用资源划分上也只是简单划分为两部分,并不能有效保证在各种情况下运算资源对特定工作/模块的可用性。

Spark 工作流的队列分类规则主要按照其工作种类划分制定,但是平台运算资源在各个工作流分列的分配原则却必须依照其工作性质与重要程度决定。

4.1 Spark各类型工作重要程度分析

此小节将主要依据各类Spark 工作的实时性与工作量来分析其重要程度并排序。

(1)最重要的工作类型便是流式数据工作(SparkStreaming)。此类工作资源消耗量极大且长久,主要因为它们需要实时处理网络中传输的流式数据,并在服务质量限定的范围内尽快给出结果。此类工作大多可被视为长效运行于Hadoop 平台上的微服务,为内部其他构件甚至外部客户提供稳定高效的运算服务。在此情况下,YARN 需要优先满足此类工作的资源需求。

(2)编排预设工作(SparkOrchestration)与资源池工作(SparkThread-pool)的重要程度仅次于流式数据工作。这两类工作的本质,都是将预设时间段内的工作量积累起来,于事先设定好的时间节点启动一个大型或一组微型工作进行集体处理,所以实时性逊于流式数据工作,甚至弱于微型存储式数据工作。然而,由于此二类工作的负载积累模式,每次工作启动时平台都已经堆积了数量相当可观的待处理请求或数据。而且鉴于尽量降低平台资源争抢,提高资源利用率的考量,预设时段的设定往往会在安全阈值范围内尽可能贴近服务质量下限。这些特性就导致此类工作启动时,YARN 必须尽快安排其开始运行,并在不影响高优先级工作服务质量的前提下,尽量满足其资源需求。

(3)微型存储式数据工作(SparkStorage),此类工作本质上也是实时运算。然而,由于其资源需求量通常极小且运行时间往往很短,在数量庞大的情况下也可以实现快速迭代。除极端情况下,纯粹此类工作组成的高负载峰值并不会发生拥堵。故将此类工作置于独立工作队列内并保证其拥有少量的固定资源以使用,其造成系统死锁的概率几乎为零。因此,与其他种类的Spark 工作相比,此类工作的重要性最低。

综上所述,四大类Spark 工作的重要性I 排序如下所示:

4.2 Hadoop2.0/YARN中的资源队列分配规则

大规模多种类混合Spark 工作流在单一资源队列中很容易于高负载资源紧张时期遭遇系统死锁威胁。因此,此类复杂工作流在Hadoop2.0 平台上运行时,需要被拆开剥离,不同种类的工作分流至适当队列中去以避免潜在威胁。同时,在Hadoop2.0/YARN 中,提出了资源弹性[2]的概念。一个队列的资源被分为稳定资源(Steady Fair Share)与瞬时资源(Instantaneous Fair Share)两类。这两类资源并无实际联系。其中稳定资源是一个队列独有且不容侵占的,是经由YARN 配置的固定值。瞬时资源则会根据整个平台的资源总量与队列的数量和权重而实时产生相应变化,队列数量越多,权重越大,所得瞬时资源便会越多,但是瞬时资源在特定条件下可以被其他队列占用,既当某队列资源使用率接近满负荷时,如果其他队列的瞬时资源多余稳定资源且相对空闲,那么此队列可以超负荷占用其他队列的瞬时资源。然而,当稳定资源大于瞬时资源时,此队列的资源弹性消失,既任何情况下,此队列的资源不可被其他队列占用。

根据上一章节的分析,Spark 工作依据种类划分的重要程度有三个等级,故而队列规则的制定与其相对应,亦有三个种类:

4.2.1 拥有足量资源的专有队列

此类队列专供流式数据工作使用,并根据用户的配置为其预留足够的运算资源。当YARN 发现流式数据工作被提交后,此类工作的所有组件都会被调度在此队列之内。此队列所拥有的稳定资源总量应与所有流式数据工作的资源需求总量相当。这种队列设置有两点优势:

(1)在任何情况下,都能优先保证流式数据工作的资源需求以满足其服务质量的要求;

(2)这种资源强制划分会使此类队列的稳定资源大于瞬时资源,有效降低了其他队列在资源规划调控阶段对于此队列弹性资源的依赖。

4.2.2 专有队列

此类队列主要应对编排预设工作和资源池工作。专有队列的优势在于,独立的队列就会有独立的稳定资源被预留下来。当工作被触发时,这些稳定资源可以确保Oozie_launcher 与Spark 工作的正常启动。在平台资源空闲时,此类队列中的工作可以通过Hadoop2.0 的资源弹性机制通过获取其他同类队列的瞬时资源以满足自身需求;而当平台出现高负载资源紧张状况时,此类队列中工作的启动行为亦不会受到负面影响,同时尽可能维持工作的运行而不会出现长时间吊起等待的阻塞现象。

4.2.3 共享队列

此类队列专供微型存储式数据工作。根据微型存储式数据工作的特点,此类队列会包含两个子队列,分别为Oozie_launcher 专有队列与Spark 专用队列。顾名思义,在此类工作流到来时,其Oozie_launcher 工作与附属的Spark 工作会运行在各自的专有队列中,从而有效防止了这两类工作之间的资源争抢。与此同时,对于每种工作单独而言,又被转化为了单种类单队列问题,Hadoop 系统默认的资源分割机制可以完美避免AM/YC 死锁问题。

通过如上的队列资源管理规则,当Oozie 参与编排的复杂大规模Spark 工作流运行于Hadoop2.0 平台上时,系统潜在的死锁问题被专有队列与种类筛选分离机制转化为一组简单的单种类单队列问题,从而得以被Hadoop 系统的原生安全机制覆盖。

5 基于Nagios及其脚本的动态监控

作为一个开发社区极为活跃的开源监控软件,Nagios 为监控脚本提供了充足的定制化空间。相对于其他固定规则的监控软件(例如Cloudera[3]),拥有动态阈值的自定义监控脚本在Nagios 上更容易实现。因为Hadoop 平台的资源被划分为不同的子队列,且工作流亦被分配至相应队列,这个动态监控脚本将基于子队列监控,而非整个Hadoop 平台的总队列。

动态监控脚本包含两个部分:

5.1 队列阻塞预警

监控系统死锁需要拉取大量平台数据,包含每个队列中等待工作数量,此队列支持的每个运行工作中AM 与YC 模块的运行状态与数量等。这会对Hadoop 平台造成额外的工作负担,进而影响平台性能,而且频繁的监控数据筛选累加也会对Nagios 本身提出很高的性能要求。故而应尽量降低系统死锁的检测频率。根据章节三的介绍可知,系统死锁只会于平台资源紧张时发生。因此,队列阻塞预警被引入动态监控脚本,既当队列于资源紧张时期发生阻塞时,Nagios 才会对当前队列进行死锁检测;否则跳过。根据当前队列中等待的工作数量Ncurrent,Nagios 将实时地计算出一个当前预警阈值Tcurrent,其与基准阈值Tbaseline的关系由Ncurrent与基准等待数量Nbaseline决定,如公式(10)所示。当任一等待工作的滞留时间长于Tcurrent时,Nagios 便会向运维人员预警队列阻塞。而Tcurrent的意义在于,在高负载时期,使用者可以容忍有限度的工作超时现象。

5.2 基于队列的死锁预警

当确认队列出现阻塞现象后,Nagios 会开始对当前队列进行系统死锁检测。这里使用的预警阈值为Tbaseline,既在符合死锁特征的条件下,只要有超时等待的工作/模块,即示警。检测规则步骤如下:

(1)Oozie/YARN 死锁检测:

1.是否有Spark 工作处于等待状态;

2.若是,是否有Spark 工作处于工作状态;

3.若否,是否存在任一等待状态的Spark 工作,其滞留时间长于Tbaseline;

4.若是,队列可能出现Oozie/YARN 死锁,Nagios 发出预警。

(2)AM/YC 死锁

1.是否每个运行工作都只有一个模块处于运行状态(只有AM运行);

2.若是,是否存在任一等待状态的模块,其滞留时间长于Tbaseline;

3.若是,队列可能出现AM/YC 死锁,Nagios 发出预警。

基于如上脚本,Nagios 可以持续对Hadoop 平台每个队列的阻塞状态与系统死锁进行持续监控和预警,并尽可能避免大幅增加平台系统的运算负担。

6 基于Hadoop2.0大数据平台的MarinOne系统实践

MarinOne 是Marin Software(每锐软件)公司推出的新一代数码广告平台系统,其基于Hadoop2.0 大数据平台、微服务框架与虚拟化技术为客户提供更直观与专业的数据展示与广告建议。在公司内部测试平台QA2 上经过检验,证明此动态监控与资源分列配置不会对系统造成任何负面影响后,生产环境的Hadoop 平台得以应用如上更改。此Hadoop平台的YARN部分由200台大型服务器构成,总共拥有37.37 TB 的内存资源,长期保持大约130 个工作同时运行,最多时会有超过230 个工作并行运行,其最高内存资源利用率超过91%。

在应用本文介绍的内存资源队列分配规则与动态监控之前,平台一旦出现高负载就会发生阻塞现象,耗费大量人力与时间成本后可以断定基本是由系统死锁引发。在应用这项技术后,仅2020年一年间,Nagios 成功预警队列阻塞143 次,系统死锁26 次。系统死锁的发生概率降低了81.8%,仅剩约18.2%。其他的系统阻塞大都是由于工作流过于巨大而导致等待时间过长所触发,期间系统并未死锁,但是阻塞的成功预警也使人工干预得以及时介入,从而避免了系统服务质量的下降。

7 相关工作

作为被广为接受的大数据运算平台,学术界与工业界已经围绕Hadoop2.0 系统进行了非常多的相关研究与改良工作。例如AROMA[4]和FMEM[5]都主张在Hadoop 系统之上嵌套一层新的自动化系统以实现平台资源的合理配置,Gunther[6]更是将遗传基因算法引入系统监控与资源管理中。Filip Křikava 等与本人也曾于15-16年发表文章[7-8]展示了基于内存监控的自适应配置优化工具。Gil Jae Lee 等也发表多篇文章[9-10]提出了基于CPU 运算资源的Hadoop系统优化建议。Jenn-Wei[11]也提出了新的依据工作重要性与预设截止时间等相关属性进行资源分配管理的调度器。但这些研究的应用环境相对苛刻,稳定性与可行性并未得到业界的深入验证,并不适合在短时间内应用于生产环境。相反,基于Hadoop 已经提供的调配接口与成熟的监控软件,本文所论述的资源配置方法与动态监控脚本拥有可靠的稳定性与可行性,这一点也在Marin 的生产平台上已经得以验证。

8 总结

本文系统化地介绍了Hadoop2.0 系统中由于复杂大规模Spark工作流引发的系统死锁与其生成机理。并据此提出了切实可行的大数据平台资源分配规则,既依据Spark 工作种类与重要程度将平台整体资源划分为不同类型队列的分配原则。再辅以基于Nagios 系统的动态监控脚本,运维团队可以对平台系统阻塞与死锁进行实时监控及快速准确的反应排查。最终使系统的可靠性与基于此大数据平台的服务质量都得到切实保证。相较于其他已有资源管理方式与研究,本文介绍的系统资源分配规则与动态监控实现相对简单,对应用环境没有特殊要求,现均已应用于Marin Software(每锐软件)的实际生产环境(MarinOne)并得到了良好反馈。

猜你喜欢

流式队列运算
重视运算与推理,解决数列求和题
有趣的运算
队列里的小秘密
辐流式二沉池的结构优化研究
在队列里
丰田加速驶入自动驾驶队列
微球测速聚类分析的流式液路稳定性评估
自调流式喷管型ICD的设计与数值验证
流式在线直播视频的采集