千家信息网

为什么我要选择使用 Yarn 来做 Docker 的调度引擎

发表于:2024-11-22 作者:千家信息网编辑
千家信息网最后更新 2024年11月22日,原文链接作者: 祝威廉编者按Mesos 和 Yarn 都是非常优秀的资源调度框架,社区也有很多的人分析二者的区别以及使用场景。之前 InfoQ 也有发问聊过二者的关系。目前业界用的较多的是 Mesos
千家信息网最后更新 2024年11月22日为什么我要选择使用 Yarn 来做 Docker 的调度引擎


原文链接


作者: 祝威廉

编者按

Mesos 和 Yarn 都是非常优秀的资源调度框架,社区也有很多的人分析二者的区别以及使用场景。之前 InfoQ 也有发问聊过二者的关系。目前业界用的较多的是 Mesos,这篇文章就是为了解释为什么作者选择使用 Yarn 而不是 Mesos,并介绍了如何基于 Yarn 开发分布式程序。本文首发于祝威廉的博客,经授权由 InfoQ 转载发布。

前言

Mesos 其实我不是非常熟悉,所以有些内容可能会有失偏颇,带有个人喜好。大家也还是需要有自己的鉴别能力。

Mesos 和 Yarn 都非常棒,都是可编程的框架。一个硬件,不能编程,就是死的,一旦可以编程就活了,就可以各种折腾,有各种奇思妙想可以实现,同样的,一个软件,只要是可编程的,基本也就活了,容易形成生态。

Yarn VS Mesos

我先说说在做容器调度引擎的时候,为什么选择 Yarn 而不是 Mesos。

可部署性

先说明下,这里探讨的是 Yarn 或者 Mesos 集群的部署,不涉其上的应用。Yarn 除了依赖 JDK,对操作系统没有任何依赖,基本上放上去就能跑。Mesos 因为是 C/C++ 开发的,安装部署可能会有库依赖。 这点我不知道大家是否看的重,反正我是看的相当重的。软件就应该是下下来就可以 Run。所以 12 年的时候我就自己开发了一套 Java 服务框架,开发完之后运行个 main 方法就行。让应用包含容器,而不是要把应用丢到 Tomcat 这些容器,太复杂,不符合直觉。

二次开发

Yarn 对 Java/Scala 工程师而言,只是个 Jar 包,类似索引开发包 Lucene,你可以把它引入项目,做任何你想要的包装。 这是其一。

其二,Yarn 提供了非常多的扩展接口,很多实现都是可插拔。可替换的,在 XML 配置下,可以很方便的用你的实现替换掉原来的实现,没有太大的侵入性,所以就算是未来 Yarn 升级,也不会有太大问题。

相比较而言,Mesos 更像是一个已经做好的产品,部署了可以直接用,但是对二次开发并不友好。

生态优势

Yarn 诞生于 Hadoop 这个大数据的"始作俑者"项目,所以在大数据领域具有先天优势。

  1. 底层天然就是分布式存储系统 HDFS,稳定高效。

  2. 其上支撑了 Spark、MR 等大数据领域的扛顶之座,久经考验。

  3. 社区强大,最近发布版本也明显加快,对于长任务的支持也越来越优秀。

长任务支持

谈及长任务(long running services)的支持,有人认为早先 Yarn 是为了支持离线短时任务的,所以可能对长任务的支持有限。其实大可不必担心,譬如现在基于其上的 Spark Streaming 就是 7x24 小时运行的,跑起来也没啥问题。一般而言,要支持长任务,需要考虑如下几个点:

  1. Fault tolerance,主要是 AM 的容错。

  2. Yarn Security,如果开启了安全机制,令牌等的失效时间也是需要注意的。

  3. 日志收集到集群。

  4. 还有就是资源隔离和优先级。如果资源隔离做的太差,会对长时任务产生影响。

大家感兴趣可以先参考Jira。我看这个 Jira 13 年就开始了,说明这事很早就被重视起来了。下面我们队提到的几个点做下解释。

Fault tolerance
  1. Yarn 自身高可用。目前 Yarn 的 Master 已经实现了 HA。

  2. AM 容错,我看从 2.4 版本(看的源码,也可能更早的版本就已经支持)就已经支持 keep containers across attempt 的选项了。什么意思呢?就是如果 AM 挂掉了,在 Yarn 重新启动 AM 的过程中,所有由 AM 管理的容器都会被保持而不会被杀掉。除非 Yarn 多次尝试都没办法把 AM 再启动起来(默认两次)。 这说明从底层调度上来看,已经做的很好了。

日志收集到集群

日志收集在 2.6 版本已经是边运行边收集了。

资源隔离

资源隔离的话,Yarn 做的不好,目前有效的是内存,对其他方面一直想做支持,但一直有限。这估计也是很多人最后选择 Mesos 的缘由。但是现在这点优势 Mesos 其实已经荡然无存,因为 Docker 容器在资源隔离上已经做的足够好。Yarn 和 Docker 一整合,就互补了。

小结

Mesos 和 Yarn 都是非常优秀的调度框架,各有其优缺点,弹性调度,统一的资源管理是未来平台的一个趋势,类似的这种资源管理调度框架必定会大行其道。

一些常见的误解

脱胎于 Hadoop,继承了他的光环和生态,然而这也会给其带来一定的困惑,首先就是光环一直被 Hadoop 给盖住了,而且由于固有的惯性,大家会理所当然的认为 Yarn 只是 Hadoop 里的一个组件,有人会想过把 Yarn 拿出来单独用么?

然而,就像我在之前的一篇课程里,反复强调,Hadoop 是一个软件集合,包含分布式存储,资源管理调度,计算框架三个部分。他们之间没有必然的关系,是可以独立开来的。而 Yarn 就是一个资源管理调度引擎,其一开始的设计目标就是为了通用,不仅仅是跑 MR。现在基于 Yarn 之上的服务已经非常多,典型的比如 Spark。

这里还有另外一个误区,MR 目前基本算是离线批量的代名词,这回让人误以为 Yarn 也只是适合批量离线任务的调度。其实不然,我在上面已经给出了分析,Yarn 是完全可以保证长任务的稳定可靠的运行的。

如何基于 Yarn 开发分布式程序

本文不会具体教你如何使用 Yarn 的 API,不过如果你想知道 Yarn 的 API,但是又觉得官方文档太过简略,我这里倒是可以给出两个建议:

  1. 代码使用范例可以参看 Spark Yarn 相关的代码。算的上是一个非常精简的 Yarn 的 adaptor。

  2. 买本 Yarn 相关的书,了解其体系结构也有助于你了解其 API 的设计。

接下来的内容会探讨以下两个主题:

  1. 基于 Yarn 开发分布式程序需要做的一些准备工作

  2. 基于 Yarn 开发容器调度系统的一些基本思路

基于 Yarn 开发分布式程序需要做的一些准备工作

肯定不能撸起袖子就开始干。开始动手前,我们需要知道哪些事情呢?

Yarn 原生的 API 太底层,太复杂了

如果你想愉快的开发 Yarn 的应用,那么对 Yarn 的 API 进行一次封装,是很有必要的。 Yarn 为了灵活,或者为了能够满足开发者大部分的需求,底层交互的 API 就显得比较原始了。自然造成开发难度很大。这个也不是我一个人觉得,现在 Apache 的 Twill,以及 Hulu 他们开发的时候 Adaptor 那一层,其实都是为了解决这个问题。那为什么我没有用 Twill 呢,第一是文档实在太少,第二是有点复杂,我不需要这么复杂的东西。我觉得,Twill 与其开发这么多功能,真的不如好好写写文档。

最好是能开发一个解决一类问题的 Framework

Yarn 只是一个底层的资源管理和调度引擎。一般你需要基于之上开发一套解决特定问题的 Framework。以 Spark 为例,他是解决分布式计算相关的一些问题。而以我开发的容器调度程序,其实是为了解决动态部署 Web 应用的。在他们之上,才是你的应用。比如你要统计日志,你只要在 Spark 上开发一个 Application 。 比如你想要提供一个推荐系统,那么你只要用容器包装下,就能被容器调度程序调度部署。

所以通常而言,基于 Yarn 的分布式应用应该符合这么一个层次:

Yarn -> Adapter -> Framework -> Application

Adapter 就是我第一条说的,你自个封装了 Yarn 的 API。 Framework 就是解决一类问题的编程框架,Application 才是你真正要解决业务的系统。通过这种解耦,各个层次只要关注自己的核心功能点即可。

保证你上层的 Framework/Application 可以移植

Spark 是个典型,他可以跑在 Mesos 上,也可以跑在 Yarn 上,还可以跑在自己上面(Standalone),实时上,泡在 Yarn 上的,以及跑 Standalone 模式的,都挺多的。这得益于 Spark 本身不依赖于底层的资源管理调度引擎。

这其实也是我上面说的两条带来的好处,因为有了 Adaptor,上层的 Framework 可以不用绑死在某个资源调度引擎上。而 Framework 则可以让 Applicaiton 无需关注底层调度的事情,只要关注业务即可。

另外,你费尽心机开发的 Framework 上,你自然是希望它能跑在更多的平台上,已满足更多的人的需求,对吧。

基于 Yarn 开发容器调度系统的一些基本思路

首先我们需要了解两个概念:

  • 哑应用。所谓哑应用指的是无法和分布式系统直接进行交互,分布式系统也仅仅透过容器能进行生命周期的控制,比如关闭或者开启的应用。典型的比如 MySQL、Nginx 等这些基础应用。他们一般有自己特有的交互方式,譬如命令行或者 socket 协议或者 HTTP 协议。

  • 伴生组件。因为有了哑应用的存在,分布式系统为了能够和这些应用交互,需要有一个代理。而这个代理和被代理的哑应用,具有相同的生命周期。典型的比如,某个服务被关停后,该事件会被分布式系统获知,分布式系统会将该事件发送给 Nginx 的伴生组件,伴生组件转化为 Nginx 能够识别的指令,将停止的服务从 Nginx 的 ProxyBackend 列表中剔除。

在容器调度系统中,如果 Yarn 的 NodeManager 直接去管理 Docker 则需要 Yarn 本身去做支持,我觉得这是不妥的。Yarn 的职责就是做好资源管理,分配,调度即可,并不需要和特定的某个技术耦合,毕竟 Yarn 是一个通用型的资源调度管理框架。

那基于上面的理论,我们基于 Yarn,开发一套框架,这个框架会是典型的 master-slave 结构(这是 Yarn 决定的)。这个框架的 slaves 其实都是 Docker 的伴生对象。master 可以通过这些 Slave 对容器实现间接的管理。

我们简单描述下他们的流程:

  1. 用户提交 Application,申请资源;

  2. Yarn 启动 Framework 的 master;

  3. Yarn 启动 Framework 的 slave;

  4. slave 连接上 master,并且发送心跳,从而 master 知道 slave 的状况 slave 启动 Docker,slave 与被启动的这个 docker container 一一对应;

  5. slave 定时监控 Container;

  6. slave 发现 container crash,slave 自动退出,Yarn 获得通知,收回资源;

  7. master 发现有节点失败,发出新的节点要求,重新在另外一台服务器上启动 slave,重复从 2 开始的步骤。

这里还有一个问题,如果 slave 被正常杀掉,可以通过 JVM ShudownHook 顺带把 Container 也关掉。 但是如果 slave 被 kill -9 或者异常 crash 掉了,那么就可能导致资源泄露了。目前是这个信息是由 master 上报给集群管理平台,该平台会定时清理。你也可以存储该信息,譬如放到 Redis 或者 MySQL 中,然后启动后台清理任务即可。

了解了这个思路后,具体实施就变得简单了,就是开发一个基于 Yarn 的 master-slave 程序即可,然后 slave 去管理对应的 Docker 容器,包括接受新的指令。master 提供管理界面展示容器信息,运行状态即可。

当然,你还可以再开发一套 Framework B 专门和 Nginx 交互,这样比如上面的系统做了节点变更,通知 B 的 master,然后 B 的 master 通过自己的伴生组件 Slave 完成 Nginx 的更新,从而实现后端服务的自动变更和通知。

现在看来,是不是这种概念完美的覆盖了应用之间的交互呢?


0