• -------------------------------------------------------------
  • ====================================

由浅入深 | 如何优雅地写一个Mesos Framework

mesos dewbay 6年前 (2019-04-12) 2029次浏览 已收录 0个评论 扫描二维码

上周小数羞涩出镜,和数人云架构师春明一起为大家进行了在线直播的干货分享,今天小数抱来了实录,大家可以一睹为快啦!
本文从 Mesos 的基础概念讲起,不懂 Mesos 的小伙伴也完全没有问题,一步一步教你写出优雅的Framework,让 Mesos 更加强大好用:)

今天主要和大家聊一聊 Mesos、Marathon,以及数人云刚刚开源不久的一个 Mesos Framework——Swan。

什么是 Mesos

微服务概念起来之后,很多大型互联网公司需要把资源(比如说几千台机器、几万台机器)抽象工作,让更多人来使用。之前大家的做法比较粗暴,一个部门分几百台机器,一个项目分几百台机器,然后把程序裸跑在一些硬件或者虚拟机上,但这个过程中资源的利用率不是很高。

另一方面,有些增加资源的场景中,增加一些机器非常缓慢,安装、做机器的 provision 等等都很困难。因此一些聪明的工程师就萌生了一个想法:能不能把这些资源都抽象,需要的时候分配给不同的人来使用?这个背景诞生了 Mesos,即资源调度的工具。资源调度器 Mesos 不是创新,它源自于 Google Omega 的论文,由 Twitter 的公司最早推出来。

最近一段时间使用 Mesos 的 API 以及看代码时间比较多,接下和大家分享一下我对 Mesos 内部的理解。

Mesos 的内部构成

Mesos master&slave

首先,Mesos 是一个分布式的架构,它分 Mesos master 和 Mesos slave,slave 和 master 分别有不同的职责。从 Mesos 的源代码可以看出 Mesos 实现得比较优雅——它是一个 C++代码。代码中有大量的关键词叫 process,它不是传统意义上的进程,而是一种抽象的 libprocess,libprocess 是它最核心的库。如果大家以前使用过 Erlang 的语言就知道 libprocess 实际是对 Erlang 的 IO 和通讯模型的一个抽象。

libprocess,在 Erlang 里面也叫进程,实际上是一个虚拟进程,在运行 Erlang 的 VM 上。它最优的特点是消息在不同的 process 之间传递,它抽象了 process,消息传递其实是一个事件的库。向 process 里发一个消息,这个消息不是直接打到 process,而是中间有一个 buffer 的过程。

这样做的优点是特别适合分布式的系统,以前最常用的做法是监听网络端口,有包来了,有一个模块专门负责解这个包,解开一个协议后把这个协议发到后面一个处理进程,这个处理的进程可能是 IO 操作,可能去做其它事情,然后里面有很多 IO 上的 Block,最后构造出一个 response,通过一个 socket 传给客户端。这是最常用的一个写网络程序的办法,但是这里有一个大的 IO 上 Block 的地方——后面处理的逻辑依赖于解包的逻辑。如果处理逻辑很快,但解包逻辑很慢,后面会拖慢,都在等解包。

后来人们想到一种 IO 处理的方式,让任何一个东西都是分离的,比如从某一个端口收到一个消息,有一个单独的进程,一个线程或者其它的东西去处理这个唯一的请求。这个线程很重,后来大家又发明了一些其它的东西,比如 golang 里面去搞一个 channel,Erlang 里面去搞一个 process。libprocess 实际上做了 IO 方面的事情, Mesos 大量使用这个模型。

Zookeeper

Mesos 底层实际上依赖于 Zookeeper,为了保证分布式存储最终一致性。在 Mesos 运行过程中产生了一些数据,最终都会落在 Zookeeper。因为 Mesos 是多个 master,为了达到 HA 的需求,只要一个 master 活的,那么整个服务就能得到保证。

protobuf

Mesos 内部在通信里面选择了 protobuf 协议。好处是比较流行,各个语言的库都比较多,结构化的语义也比较强,所以 Mesos 内部选择了 protobuf。

至此,简单介绍了 Mesos 内部的一些动作。接下来介绍 Mesos 提出的一些概念。

Mesos 概念解析

Mesos master&slave

Mesos 是一个分布式的系统,分 master 和 slave, master 的部分主要协调任务的分发、一些资源的调度。slave 是负责执行的部分,比如一个任务最终是 slave 去执行的。当然,可以配在 master 执行。Mesos 是一个双层调度,slave 处于下层,也就是说可以动态的增加或者减少一些 slave 而不影响整个的任务池资源的变化,不影响上一层的任务。

Executor

Executor 是真正的执行任务的逻辑。Mesos 平台不太区分需要执行什么任务,所以它给用户一些灵活性,可以写不同的 Executor。比如最常用的 Mesos 运行容器的部分,就是一个 Executor。还有 Map Reduce 的大型任务,一个 Map、一个 Reduce, Executor 都可以执行。它的表现形式可以是一个二进制,Mesos 在运行时,slave 会把 Executor 从远程一个 URL 上拉下来,然后开始执行 Executor。

Scheduler

Scheduler 的意思是调度, Mesos master 和 slave 把资源收上来之后,再把这些任务交给 Scheduler,由 Scheduler 决定应该运行什么 Task。

Framework

Framework是双层调度的上一层,也就是由Framework来决定到底该执行什么任务,然后执行多少这样的任务。

Offer

Offer 是 Mesos 资源的抽象,比如说有多少 CPU、多少 memory,disc 是多少,都放在 Offer 里,打包给一个Framework,然后Framework来决定到底怎么用这个 Offer。

Task

Task 实际上是运行的小任务。有两大类 Task,一大类我们叫 Long Running Task,比如 Docker 的一个进程或者其它的进程。另外一类是 Batch 类型任务,这类应用非常广泛,比如说 Map Reduce 这么一个小任务或者是定时任务。

Mesos 内部工作原理

这里分别介绍一下刚才提到的这些名词,说一说它们都是如何工作的。

Mesos master & slave

Mesos master 是整个集群的核心,master 为了保证高可用其实是可以跑多个 master,分布式系统为了保证尽量的高可用,其实是可以有多个 master 在那儿运行的。比如倒了几个 master,不会影响整个服务。Mesos master 主要内部的工作有:Framework 注册或者 Framework 出了什么问题,它来保证 Framework 的生命周期;slave 的添加、slave 的异常、slave 的任务分配,我把它叫做 slave 的 Lifecycle;Task Management,比如说 Mesos master 可能记录了哪些 Task 运行在哪些 slave 上;Resource Allocation&Offer,就是说 slave 有什么资源汇报给 master,然后由 master 把这些任务交给注册在这个 master 上的一些 Framework。

slave 可以动态添加和减少,它 lost 不会影响整个服务,只是把这个事件(比如说一个 slave 掉了)由 master 去通知 Framework。在 Mesos slave 代码里有大量执行器,即 Executor 的逻辑,因为所有 Executor 都是在 slave 上执行的,包括把 Executor 从远程拉下来、开始执行 Executor、开始执行 launch task,维护 task 的生命周期,task fail 了如何去做等等。

Mesos Framework

Mesos 的定位是一些资源的调度,它把任务的调度交给了 Framework 来做,Mesos 只关心资源以及把资源给了谁, Framework 来决定哪些资源怎么去使用。Mesos 鼓励 Framework 在上面共生。想象一下,作为一个大型公司,有很多的资源,有核心的一组人来维护 Mesos 的集群,不断的往 Mesos 上添加资源和减少资源,而把 Framework 执行的能力交给其它的组、需要资源的那些组,各个组就可以写自己的 Framework,丢到整个大的 Mesos 集群上来执行了。Mesos 框架上和执行上各种各样的 Framework,而 Mesos 本身也不了解为什么 Framework 工作,它只是知道把 Offer 给 Framework,然后 Framework 告诉它来执行什么样的 Executor。

两个比较流行的 Framework

Marathon Framework,它的任务偏 Long Running,核心是 application。因为 Mesos 只关注 task 本身,task 偏向于小任务,不会产生什么巨大的效应,而在企业里面尤其是弹性应用,更多是一个应用,它有很多的实例来执行,这就是 Marathon 来做的。

Chornous 是一个偏 Job、定时任务类型,如果把定时任务以 Docker 形式发出来,这个 Chornous 是非常适合的。传统的的 Cron Job 也是解决这类问题, Cron Job 其实有很大的痛点,因为 Cron Job 是跑在主机上的,主机有 limit 的限制,如何把 Cron Job 放在多机上,需要有一个很好的哈希算法。到底如何把一堆单台机器很难执行的多个 job 水平分布在很多机器上,很麻烦。但是有了这个 Chornous 的 Framework,事情就变得简单多了。

Scheduler/Scheduler Driver

它们俩区分度不是太大,有一些区分。Scheduler 是做任务分配的,它从 master 上得到一个 Offer 的事件,拿到 Offer 后,决定到底接受这个 Offer 还是拒绝,接受这个 Offer 之后,把什么样的 Task 放在这个 Offer 上, Framework 也开始占用这个 Offer,这是 Scheduler 做的事情。Scheduler Driver 其实是偏消息通信的那一部分,而 Scheduler 可定制化特别强,在代码里看到 Scheduler 其实是一个 java 的 abstract glass,相当于一个 interface,Framework 自己去实现这么一个东西。如果想写一个 Framework,其实大部分时间在如何写好一个 Scheduler 实现这一部分。

Executor/Executor Driver

如果 Executor 和 Scheduler 是对应的, Executor 就是执行的这一部分。Mesos container 这个 Executor 是 Mesos 自己提供的,不用写 Executor 就可以 launch 一个 Docker 的任务。但如果有一些自己的需求,就需要去实现一个 Executor,比如七牛和乐视实现了一些 Executor。

举例来说,处理图片、处理文件的 Executor,偏向于这种小任务,写一个 Executor 来实现这个 interface,最终打成一个二进制,放在一个 URL 里面。在 Framework,slave 就可以把这个 Executor 拉下来,然后执行这个 Tasks。Executor 是一个独立的二进制,它和 master、和 slave 之间的通信是要支持 RBC 的。

Marathon

刚才已经提到了 Marathon 基本的功能,Marathon 作为一个 Long Running 上一层的调度机制,为用户做了很多有意义的事情。单纯一个 Mesos 的话做不了什么,因为 Task 的力度特别小,Mesos 的功能更偏重于资源的管理、资源的调度,Marathon 更偏向于一些任务。

Marathon 提出了几个概念,最核心的概念叫 application,还有 Group 的 application,是一组的 application。一个 application 是什么呢?比如一个 Rails 的任务、NodeJS 任务或者其它的一些任务,在部署的时候并不是部署一个 Task,而是部署非常多的 Task,application 就是一组 Task。这个 Task 在 Marathon 里面叫 instance,可以选择 scale down 或者 scale up 这些 instance,这些任务最终交给 Mesos,Mesos 调度到不同的 slave 上。

围绕着这个 application,Marathon 就提供了一些概念叫 Group,Group 是一组 application。举例来说,在内部可能有很多的微服务,这些微服务达到同一个目标,比如说服务之间还有调用、还有依赖,这时去发一个 Group application 就比较好用。但实际工作中,因为生产级别的服务对稳定性的要求很高, Group 之间其实假设服务和服务之间是有一定的依赖。

Marathon 提供了一个有意思的 feature—— rolling update。假如有 APP 的新版本上来,它可以通过一定的机制去发多个版本,而且可以多个版本共存。如果那个新版本没有问题的话,可以继续 preceeding deployment。如果有问题的话,可以 Rollback。这时有两个概念 Deployment 和 Version,可以选定哪一个 Version,想 Rollback 哪个 Version。Deployment 是每次 update,每次更新、每次重新的 Deployment、每次 scale,都会在内部生成一个 Deployment,和应用一对多有关。有趣的是 Deployment 之间是不可以重叠的,Deployment 是一种部署排队的机制,Deployment 不可以多个同时进行,既想 update 又想 scale,会让 Marathon 崩溃。

Marathon scale 和 rolling update 的功能都非常有用,比如新浪微博现在有一个大的事件,需要更多的 Task 顶上来,立刻 scale up,只要资源足够就可以无限多的 Task 生成。Rollback,如果有一个版本有问题,可以瞬间 Rollback 到以前一个健康的版本。

虽然 Mesos 对下面的资源做了一些抽象,但是有时候有一些倾向性,比如希望 CPU 使用率比较高的一些任务调度到 CPU 比较好的机器上,需要一种在调度上的倾向性来满足刚才的场景。很多调度器都有类似的功能,叫 Constraints,比如一台主机的 label,要把 Task 打到一组主机这样的 Label 上或者是 Host name like,这是 Marathon 做的,Mesos 不用做这类的事情。

Marathon 的接口非常友好,都是 HTTP 的接口。Mesos 的接口 by design 不是面向最终用户,所以它的接口并不是那么友好。马拉松的 UI 也非常漂亮,尤其是新版。

Mesos 调度器 Swan

最后介绍一下 Swan(https://github.com/Dataman-Cl… )这个项目,Swan 是最近数人云做的一个 Mesos 的 Framework,定位是做一个 General Purpose Long Running Task 的 Framework。数人云使用马拉松较长时间,发现不太满足需求,比如很难做一些定制化,控制不住它的发展趋势。我们希望研发一款工具既有马拉松的功能又自主可控、添加一些想要的 featur,具体的 feature 会在下文中逐一介绍。

我们希望这个通用性的 Framework 在任何情况下,服务不会受到影响。因为 Mesos HA 这方面已经做得很好,所以 Framework 不会是单点,首先 Swan 要支持 HA,因为受到 Swarmkit 启发比较大, Swarmkit 天生就是 Raft 协议,在一堆 manager 中只要有一个活的,就能健康的对外服务。

Marathon 没怎么做服务发现,无非是把端口暴露出来,哪个任务在哪些 IP 和端口上,通过 API 的形式告诉给外面。Swan 里内置服务发现,会有一个列表告诉外面哪些服务跑在哪些端口、哪些 APP 上。

DNS 是服务发现的另一种。主流的一些 Framework 都把 DNS 这个功能放在了比较核心的位置,比如 K8s 里面的 SkyNet,Mesos 曾经以前有 Mesos DNS,以及 Swarmkit,Swarm 的服务发现分为 DNS Round Robin 和 IPVS 两种,把 DNS 放在 Swan 这个模块里更加的可控。它不单是一个 DNS,同时是一个 DNS 的代理。这样最终能实现的效果,在企业内部通过我们的 DNS 和用户的 DNS 来混搭,来达到一种 Mesos 内部和外部互相调用,在浏览器上既可以访问 Mesos 内部的东西又可以访问外面的东西,达到比较完美的效果。

Proxy,并不单是 Proxy,还有负载均衡。最常见的 Proxy 的工具有 HAProxy 或者 nginx。 HAProxy 和 nginx 虽然很优秀、性能很好,缺点是可控性太差,很难控制它。HA 可编程的能力很差,Nginx 可编程的能力不错,新浪微博有一个项目叫 upsync-module,非常优秀。之前评估过这个项目,发现集成这两个的难度很大。

我的分享就到这里,谢谢大家。


露水湾 , 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:由浅入深 | 如何优雅地写一个Mesos Framework
喜欢 (0)
[]
分享 (0)
关于作者:
发表我的评论
取消评论

表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址