Mesos和Yarn都是非常优秀的资源调度框架,社区也有很多的人分析二者的区别以及使用场景。之前InfoQ也有发问聊过二者的关系。目前业界用的较多的是Mesos,这篇文章就是为了解释为什么作者选择使用Yarn而不是Mesos,并介绍了如何基于Yarn开发分布式程序。本文首发于 祝威廉的博客 ,经授权由InfoQ转载发布。
Mesos其实我不是非常熟悉,所以有些内容可能会有失偏颇,带有个人喜好。大家也还是需要有自己的鉴别能力。
Mesos和Yarn都非常棒,都是可编程的框架。一个硬件,不能编程,就是死的,一旦可以编程就活了,就可以各种折腾,有各种奇思妙想可以实现,同样的,一个软件,只要是可编程的,基本也就活了,容易形成生态。
我先说说在做容器调度引擎的时候,为什么选择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这个大数据的“始作俑者”项目,所以在大数据领域具有先天优势。
谈及长任务(long running services)的支持,有人认为早先Yarn是为了支持离线短时任务的,所以可能对长任务的支持有限。其实大可不必担心,譬如现在基于其上的Spark Streaming就是7x24小时运行的,跑起来也没啥问题。一般而言,要支持长任务,需要考虑如下几个点:
大家感兴趣可以先参考 Jira 。我看这个Jira 13年就开始了,说明这事很早就被重视起来了。下面我们队提到的几个点做下解释。
日志收集在2.6版本已经是边运行边收集了。
资源隔离的话,Yarn做的不好,目前有效的是内存,对其他方面一直想做支持,但一直有限。这估计也是很多人最后选择Mesos的缘由。但是现在这点优势Mesos其实已经荡然无存,因为Docker容器在资源隔离上已经做的足够好。Yarn和Docker一整合,就互补了。
Mesos 和 Yarn 都是非常优秀的调度框架,各有其优缺点,弹性调度,统一的资源管理是未来平台的一个趋势,类似的这种资源管理调度框架必定会大行其道。
脱胎于Hadoop,继承了他的光环和生态,然而这也会给其带来一定的困惑,首先就是光环一直被Hadoop给盖住了,而且由于固有的惯性,大家会理所当然的认为Yarn只是Hadoop里的一个组件,有人会想过把Yarn拿出来单独用么?
然而,就像我在之前的一篇课程里,反复强调,Hadoop是一个软件集合,包含分布式存储,资源管理调度,计算框架三个部分。他们之间没有必然的关系,是可以独立开来的。而Yarn 就是一个资源管理调度引擎,其一开始的设计目标就是为了通用,不仅仅是跑MR。现在基于Yarn之上的服务已经非常多,典型的比如Spark。
这里还有另外一个误区,MR目前基本算是离线批量的代名词,这回让人误以为Yarn也只是适合批量离线任务的调度。其实不然,我在上面已经给出了分析,Yarn 是完全可以保证长任务的稳定可靠的运行的。
本文不会具体教你如何使用Yarn的API,不过如果你想知道Yarn的API,但是又觉得官方文档太过简略,我这里倒是可以给出两个建议:
接下来的内容会探讨以下两个主题:
肯定不能撸起袖子就开始干。开始动手前,我们需要知道哪些事情呢?
如果你想愉快的开发Yarn的应用,那么对Yarn的API进行一次封装,是很有必要的。 Yarn为了灵活,或者为了能够满足开发者大部分的需求,底层交互的API就显得比较原始了。自然造成开发难度很大。这个也不是我一个人觉得,现在Apache的Twill,以及Hulu他们开发的时候Adaptor那一层,其实都是为了解决这个问题。那为什么我没有用Twill呢,第一是文档实在太少,第二是有点复杂,我不需要这么复杂的东西。我觉得,Twill与其开发这么多功能,真的不如好好写写文档。
Yarn只是一个底层的资源管理和调度引擎。一般你需要基于之上开发一套解决特定问题的Framework。以Spark为例,他是解决分布式计算相关的一些问题。而以我开发的容器调度程序,其实是为了解决动态部署Web应用的。在他们之上,才是你的应用。比如你要统计日志,你只要在Spark上开发一个Application 。 比如你想要提供一个推荐系统,那么你只要用容器包装下,就能被容器调度程序调度部署。
所以通常而言,基于Yarn的分布式应用应该符合这么一个层次:
Yarn -> Adapter -> Framework -> Application
Adapter 就是我第一条说的,你自个封装了Yarn的API。 Framework就是解决一类问题的编程框架,Application才是你真正要解决业务的系统。通过这种解耦,各个层次只要关注自己的核心功能点即可。
Spark是个典型,他可以跑在Mesos上,也可以跑在Yarn上,还可以跑在自己上面(Standalone),实时上,泡在Yarn上的,以及跑Standalone模式的,都挺多的。这得益于Spark本身不依赖于底层的资源管理调度引擎。
这其实也是我上面说的两条带来的好处,因为有了Adaptor,上层的Framework可以不用绑死在某个资源调度引擎上。而Framework则可以让Applicaiton 无需关注底层调度的事情,只要关注业务即可。
另外,你费尽心机开发的Framework上,你自然是希望它能跑在更多的平台上,已满足更多的人的需求,对吧。
首先我们需要了解两个概念:
在容器调度系统中,如果Yarn的NodeManager直接去管理Docker则需要Yarn本身去做支持,我觉得这是不妥的。Yarn的职责就是做好资源管理,分配,调度即可,并不需要和特定的某个技术耦合,毕竟Yarn是一个通用型的资源调度管理框架。
那基于上面的理论,我们基于Yarn,开发一套框架,这个框架会是典型的 master-slave结构(这是Yarn决定的)。这个框架的 slaves 其实都是Docker 的伴生对象。master 可以通过这些Slave 对容器实现间接的管理。
我们简单描述下他们的流程:
这里还有一个问题,如果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的更新,从而实现后端服务的自动变更和通知。
现在看来,是不是这种概念完美的覆盖了应用之间的交互呢?