为了知足渲染、基因测序等计算密集型服务的需求,UCloud 推出了“计算工厂”产品,让用户能够快速建立大量的计算资源(虚拟机)。该产品的背后,是一套基于 Mesos 的计算资源管理系统。本文简要介绍该系统的结构、Mesos 在 UCloud 的使用、咱们的解决方案以及遇到的问题。算法
咱们的需求主要是两方面:数据库
简单地说,咱们须要有一个平台,统一封装多个数据中心的计算资源,而且同时支持虚拟机、容器等多种形式的资源使用方式。安全
图1:计算资源管理平台的需求示意图服务器
说到虚拟机,首先想到的就是 UCloud 本身的 UHost 和开源的 OpenStack,然而,这两套系统都是针对大型公有云的场景,并且主要只针对于虚拟机这一种业务。它们功能丰富、模块众多,运维运营上都须要很大的成本。然而咱们的业务并不须要这么多功能。网络
最终,咱们选择基于 Mesos 来实现这套平台。架构
Mesos是Apache下的开源分布式资源管理框架,它是一个分布式系统的内核。框架
经过 Mesos,一个数据中心所提供的再也不是一台台服务器,而是一份份的资源。资源能够是 CPU 核数、内存、存储、GPU 等等。若是把一个数据中心当作一个操做系统的话,Mesos 就是这个操做系统的内核。运维
咱们选择 Mesos 的缘由在于它拥有高度可扩展性,同时又足够简单。分布式
做为内核,Mesos 只提供最基础的功能:资源管理、任务管理、调度等。而且每一种功能,都以模块的方式实现,方便进行定制。架构上,Master 和 Agent 两个模块就实现了资源相关的全部工做,用户只需根据本身的业务逻辑实现 Framework 和 Executor 便可。这样就支持咱们可以把计算资源封装成虚拟机、容器等各类形式。动画
采用 Mesos 来进行容器编排的方案已经被不少厂商使用,相关的资料文档也比较丰富。然而用 Mesos 来管理虚拟机,业内并无应用于生产环境的实践。本文的余下内容,主要向读者分享一下 UCloud 用 Mesos 管理虚拟机的思路和实践经验。
Mesos 采用 Master-Agent 架构。Master 负责总体资源的调度并对外提供 API。Agent 部署在全部机器上,负责调用 Executor 执行任务、向 Master 汇报状态等。
Mesos 提供了一个双层调度模型:
总体架构以下图:
图2:Mesos 的双层调度结构图
在 Mesos 的双层调度模型上,平台的总体架构以下图:
图3:基于Mesos的资源管理平台总体架构图
结构以下:
系统内的全部通讯都基于 HTTP。
首先,Mesos 内部基于 libprocess 各组件之间的通讯都都依赖 libprocess 库,该库用 C++ 实现了 Actor 模式。每一个 Actor 会监听 HTTP 请求,向 Actor 发消息的过程就是把消息体序列化后放在 HTTP 报文中,而后请求这个 Actor。
其次,业务相关的各个组件,API Server、Cluster Server 等也都经过 Restful 的 API 提供服务。
HTTP 的优势在于简单可靠、易于开发调试和扩展。
对于 Docker 容器,咱们采用 Marathon Framework 进行管理。而对于虚拟机,咱们则采用本身开发的 VM Scheduler Framework 。
VM Scheduler 从 Master 获取一个个的资源 offer 。一个资源 offer 包含了某个 Agent 上可用的资源。当有虚拟机任务须要执行是,Cluster Server 会把任务的具体信息发送给 VM Scheduler。
任务分为两类:
Task 是 Mesos 中资源分配的最小单位。Master 会告诉 Agent 须要执行哪些 Task,Agent 也会把 Task 的状态汇报给 Master。根据 Task 的信息,Agent 会下载并启动所需的 Executor,而后把具体的 Task 描述传给它。
VM Executor 是咱们开发的对虚拟机的生命周期进行管理的 Executor,实现了对虚拟机建立、删除、开关机、镜像制做等功能。
VM Executor 启动后,根据 Task 的描述,动态生成虚拟机须要的配置文件,而后调用 libvirt 进行虚拟机建立。当收到来自 VM Scheduler 的 Framework Message 时,又调用 libvirt 进行开关机等操做。
状态的管理是实现虚拟机管理的关键部分。经过 Mesos 咱们只能拿到 Task 的状态,RUNING 表示虚拟机建立成功,FAILED 表示虚拟机失败,FINISHED 表示虚拟机成功销毁。然而除此以外,一个虚拟机还存在“开机中”、“关机中”、“关机”、“镜像制做中”等其余状态。咱们经过在 VM Executor 和 VM Scheduler 之间进行心跳,把这些状态同步给 VM Scheduler。后者对状态进行判断,若是发现状态改变了,就发送一条状态更新的消息给 Cluster Server,而后再转发给 API Server,最终更新到数据库。
首先看一下一个 Task 在 Mesos 中是怎么调度的:
图4:Mesos 资源调度过程示意图
上面的示例中:
对应到虚拟机的状况,调度分两个部分:
服务器之间除了 CPU、内存、硬盘等可能不一样外,还会存在其余的差异。好比有时候业务要求必定要用某个型号的 CPU,有时候要求必定要拥有 SSD等等。为了支持更多维度的调度,咱们利用了 Mesos 的 Resource 和 Attribute 来标识不一样的资源。
Resource是 Mesos 中的一个概念,表示一切用户须要使用的东西。Agent 默认会自动添加 cpus, gpus, mem, ports 和 disk 这5种资源。另外还能够在 Agent 启动时,经过参数指定其余资源。
Attribute 以 Key-Value 形式的标签,标识一个 Agent 拥有的属性,一样能够在启动时经过参数指定。
经过 Resource 和 Attribute 的灵活运用,能够标识出更多的资源状况,知足各类资源调度需求。好比经过 Resource 指定 SSD 大小、CPU型号,经过 Attribute 标识机架位、是否拥有外网 IP,是否支持超线程等等。Framework 收到一个 resource offer 后,与待执行的任务需求进行匹配,经过 resource 判断资源是否够用,再经过 Attribute 判断是否知足其余维度的需求,最终决定是否用这个 offer 来建立 Task。
平台提供了一些基础镜像,另外用户也能够基于本身的虚拟机建立本身的镜像。这些镜像文件统一存储在一个基于 GlusterFS 的分部署存储服务中,该服务挂载在每台物理机上。
有些业务场景须要部分虚拟机可以共享同一份存储,因而咱们仍是基于 GlusterFS 开发了用户存储服务,可以根据用户的配置,在虚拟机建立时自动挂载好。
网络方面,每一个用户能够建立多个子网,各个子网之间作了网络隔离。建立虚拟机时,须要指定使用哪一个子网。
在使用 Mesos 的过程当中,咱们也遇到了其余一些问题。
当机器负载比较高,尤为是 IO 较高时,咱们发现 Marathon 集群有几率出现不能选主的状况。
咱们怀疑是因为Marathon节点和ZK的网络不稳定,触发了Marathon或Mesos的bug致使。因而经过iptables主动屏蔽Leader ZK端口的方式,成功复现出问题。
经过在Marathon的代码中加上一些Leader选举相关的最终日志,成功定位到了问题,原来是因为Mesos Driver的stop() 方法没有成功引发 start() 方法退出阻塞致使。
因为咱们的全部程序都是经过守护进程启动的,因此咱们采用了一个最简单的解决方案:修改Marathon代码,当ZK异常发生时,直接自杀。自杀后守护进程会把程序再启动起来。
咱们的服务采用 Golang 开发,使用 go-marathon 库与 Marathon 进行交互。使用过程当中发现该库有一些问题:
不支持多Marathon节点。因而咱们本身建立了一个分支,采用节点主动探测的方式,实现了多节点的支持。(原库v5.0版本之后也支持了该功能)
使用设有 Timeout 的 http.Client 进行 go-marathon 的初始化时,订阅 SSE 会产生超时问题。因而咱们作了修改,普通的 HTTP API 和 SSE 不使用同一个 http.Client,操做 SSE 的 http.Client 不设置 Timeout。
网络异常时,go-marathon 的方法调用会 Hang 住。因而咱们全部对 go-marathon 方法的调用都加上超时控制。
Mesos 在 UCloud 有着普遍的应用,对外有“计算工厂”和 UDocker 等产品,对内则支撑着公司内网虚拟机管理平台。伴随着持续的实践,咱们对 Mesos 的理解和掌控也愈来愈深刻。咱们会持续输出咱们的使用经验,期待获得各位读者的反馈。