我们发现公司的服务器 cpu, memory 等资源利用并不充分;如果能够充分利用这些机器上的空闲资源同时又能保证业务服务的正常运行,将会节省不少的机器资源;所以我们研究了 Mesos 来构建多任务调度系统。接下来就为大家介绍下我们的 Mesos 系统。
背景
公司内部的云平台为各个业务线提供了大量的实体机和虚拟机来运行业务的服务,经过统计发现,这些分配给业务的机器 cpu, memory 等资源利用并不充分;
如果能够充分利用这些机器上的空闲资源同时又能保证业务服务的正常运行,将会节省不少的机器资源;
选型
一提到多任务运行和调度,大部分人可能首先都会想到 Kubernetes(k8s) + Docker, 跑起来如清风拂面, 顺畅无比。然而我们的业务机器大部分为 centos 6.2, linux kernel 2.6 的环境,而 docker 的运行需要 Linux kernel 的版本是 3.10+
(可参考: https://docs.docker.com/engine/faq/#how-do-i-connect-docker-containers)
因为想利用业务正在使用的机器,又不能影响现有已在跑的服务, 所以不能升级内核, 不能重启机器,显然 k8s 这条路走不通;
还好,这个世界总是提供给我们多样的选择,除了 Kubernetes(k8s) + Docker, 我们还有 mesos;
Mesos 简介
先放上官方网站, 上面有很详细的说明;
简单来说,Mesos 就是用于整个计算中心的操作系统,它统一管理计算中心所有机器的 cpu, memory, disk, network 等计算资源,按任务所需分配资源,调度任务,支持故障转移等等;
Mesos 特性
Mesos 最大特点是两级资源调度, 如下图:
上面架构图的简要说明如下:
1.各个 Agent 上报自已的计算资源给 Master;
2.Master 给各个二级调度框架 Framework 发送 resource offer;
3.Framework 将其上等待调度的 task 与收到的 resource offer 作匹配,反馈给 Master;
4.Master 将相应 Framework 反馈的 task 和 resource offer 发送到对应的 Agent;
5.Agent 使用 Executor 来运行 task, 并限定资源使用;
在 Mesos 上可以运行 Spark, Storm, Hadoop, Marathon 等多种 Framework;
Mesos 系统架构
官方文档:
针对任务隔离这块, Mesos 除了支持 docker 容器技术,还提供了它自己的 Mesos Containerizer, 这正是我们所需要的.其实 Mesos Containerizer 目前也是利用 Linux Cgroup 作资源限制, 用 Linux namespace 作资源隔离.
Mesos Containerizer:
http://mesos.apache.org/documentation/latest/mesos-containerizer/
面临挑战
我们的多任务调度系统需要解决的几个问题
1.Mesos agent 在业务机器上需要非侵入式地部署,不能污染所部署的机器的环境;
2.实时监控和调整 Mesos Agent 所能使用的计算资源;
3.Task 的快速部署和资源隔离;
4.集群整体运行情况的监控;
多任务调度系统总体架构
架构设计图
1.各组件简介:
1.1 主体还是 Mesos master + Mesos agent;
1.2 二级调度框架使用的是 Marathon;
1.3 在部署了 Mesos agent 的机器上同时部署 monitor 用于实时监控和调整 Agent 的可用计算资源;
2.系统运行流程,按上图中标号顺序
2.1 Monitor 实时监控组件收集所在机器上的可用资源;
2.2 Monitor 根据所在机器上的可用资源动态调整 agent 的保留资源;
2.3 Agent 动态实时的将自已的保留资源上报到 Mesos master;
2.4 Mesos Master 在 resource offer 发到 Marathon;
2.5 Marathon 根据收到的 resource offer 和需要运行的 task 作资源分配, 将分配结果反馈给 Mesos Master;
2.6Mesos Master 将 task 分配到具体的 Agent 上执行;
1 Mesos agent 在业务机器上非侵入式部署
我们采用的是 Mesos 1.4.1 版本,用 C++11 编写,Mesos 项目本身非常庞大,依赖库必然也很多,解决这些运行依赖问题首当其冲;
部署原则就是不改变,不污染所部署的机器环境,针对 libstdc++和其他一些 so, 我们不会将其安装到例如/usr/local/lib 这样的系统目录, 而是在打包时采用动态更改可执行程序的 rpath 的方法,使其运行时从我们的安装目录加载相应的 so 库, 具体作法就是
1.我们将 mesos 运行所需要的所有 lib 文件都集中放在 libs 目录下;
2.编译出来的 mesos 可执行文件,使用 patchelf 来更新 rpath 路径,指向我们自已的 libs 目录即可;
3.patchelf 这个工具可以在不影响可执行文件运行的前提下,修改其 elf 文件结构中的某些属性值,具体可参考:https://nixos.org/patchelf.html
这样部署完,Mesos agent 只是一个单独的目录,卸载只需要停掉进程,删除目录就好;
说一下编译过程,虽然官网上已经介绍得比较详细,但在编译过程中还是会遇到一些问题:
1.官网编译步骤: 请参考 http://mesos.apache.org/documentation/latest/building/;
2.gcc 官方要求是 4.8.1+, 我用了 gcc 5.4, 自己在 centos 6.2,linux 2.6.32 上重新编译的;
3.编译默认是编译 java 语言的 binding 的, 但在 编译 "Build and attach javadoc"时缺 protobuffer 的 jar 包,没编译过, 解决方案:修改 src/java/mesos.pom.in,先找到 ``, 在它下面的 < configuration>下添加 < skip>true< /skip>,这样不会编译这个 javdoc, 但不影响 java binding 的使用
2 实时监控和调整 Agent 所能使用的计算资源
自行开发了 Monitor 程序,和 Agent 一同部署在业务机器上,周期性的监测机器上可用资源和 Agent 本身所用资源;
Mesos 为我们提供了动态资源保留这个超实用的功能,可以限制 Agent 当前针对某个 Role 可以使用的计算资源:
Monitor 的监控评估结果就是当前 Agent 可以使用的计算资源;
本想着到这里这个问题就结束了,测试时发现 Agent 并不能在线实时调整这个动态资源保留,需要在配置文件时更新好当前能够使用的动态资源,然后重启 Agent;
重启 Agent 是我们不能忍受的,因此我们修改了源码,通过 http 接口在线调整动态资源保留, 这部分其实不难,mesos http 接口定义十分清晰,依葫芦画瓢就好了.
3 Task 的快速部署和资源隔离
task 的部署目前我们采用 Marathon,上手简单,功能够用; 如果需要更灵活的调整策略,可能就需要自己开采框架或基于某一框架二次开发了;
task 其实是有重要,紧急之分,占用资源也不尽相同。对于重要紧急任务,为了保障任务的更好运行,我们会利用 Mesos attribute,在调度任务时让特定任务只跑在具有特定 attributes 的 agent 上, 这就需要为每个 mesos agent 设置相应的 attributes;
遇到了同样的问题,mesos 不能在线动态调整 attributes :-(, 其实也比较简单,稍微梳理下 mesos 源码结构,改起来不难;
还有一个问题,attributes 是动态调整的,agent 如果重启了怎么办?我们为此部署了 etcd 集群来管理,每台 agent 都是 etcd 上的一个 node, 通过 etcd 提供的 http 接口更新其 attribrtes, agent 会周期性的从 etcd 上同步;同时各 agent 上的 attributes 信息也很容易从 etcd 上获得;
直接操作 etcd, 删除某台 agent 上的 attribute, 那依赖于这种 attribute 部署的任务会自动别调度走,不再在这台 agent 上运行;
task 隔离问题,针对 cpu 和 memory,mesos 都是通过 cgroup 来完成,对于 cpu 的限制, 我们使用 cfs 方式,前提是需要判断当前 kernel 是否支持.对于 disk 的限制,目前 mesos 使用的是 du 命令周期性检测的方式;
对于 cpu 的限制,mesos 有两种方式:
1.cpu shared 方式:这种方式对 cpu 没有严格限制,机器上的任何 task 都可以访问机器上所有 cpu 资源,比如你限定的 cpu 使用资源是 2, 这种方式可能使用到 4,6 或更高;
2.cpu CFS 方式: 相当于配置了独占 cpu, 比如 cpu 配置为 1,那么这个任务的 cpu 使用率就不会超过 100%, 相当于设定了一个 hard limit;
在我们的大部分环境中,受限于 kernel 版本,mount namespace 不支持,因此我们采用 rootfs + chroot 的方式来作简单的资源隔离;
我们定制了若干版本的 rootfs, 任务打包就是将任务本身的依赖和相应 rootfs 结合的过程, 打包好可以放到 s3 等存储上,供 marathon 部署任务时调用。
这里我们结合 marathon 的一个任务部署的 json 配置来讲一下, 先看一个这个配置, 我将说明直接写在里面
关于 chroot, 大家可以参考下面的网址内容,简单讲就是构造了一个沙箱,和已有的文件系统隔离;
4 集群整体运行情况的监控
机器本身的基础监控一般公司还有自己的统一监控, 这部分不用投入精力;
我们主要关注 task 的调度运行情况,目前的方案是 mesos-exporter 和 mesos-agent(或 mesos-master)一起部署,上报监控信息到 prometheus,使用 grafana 来展示;
mesos 本身为我们提供了很丰富的 http api 来获取当前集群的属性,状态,Framework 情况,task 的运行状态等等,结合这些我们自己来作监控其实也不是难事,可以参考这里:
http://mesos.apache.org/documentation/latest/operator-http-api
仍然存在的问题
打包 task 没有实现自动化, 我们虽然定制了若干种不同的 rootfs, 比如 c++11 环境的, python 环境的, java 环境的等等, 但是想要运行的 task 依赖千差万别, 现在都是结合 rootfs 和业务的程序,手动合成专用的 rootfs, 基本上每个 task 都要走这个手动流程,烦锁,耗时,容易出错;
目前只引用了 marathon 一种调度框架,适用于长期运行的 task, 对于需要定时运行的 task 目前无法支持;
结束
到此我们利用 Mesos 构建的多任务调度系统就简单介绍完成,其中还有很多不完善的地方,有兴趣的同学可以一起讨论,互相学习~~~
本文转载自公众号 360 云计算(ID:hulktalk)。
原文链接:
https://mp.weixin.qq.com/s/PtqEDUDF2Jn3SY6HrmZLOQ
评论