一提 mesos, 很多人知道双层调度, 但是大多数理解都在表面, 不然试一下下面五个问题
问题一: 如果有两个 framework, 一万个节点, 按说应该平均分配给两个 framework, 怎么个分法? 一人一台这样分, 还是前五千给一人, 后五千给第二个人, 还是随机分, 随机分怎么个分法?
问题二: 在没有 reserved 情况下, 每个节点是只能得给一个 framework, 还是可以分给多个 framework?
问题三: 如果两个 framework 的权重比例为 1 比 2, 是如何保证资源分配是这个比例?
问题四: 如果两个 framework 的权重比例为 1 比 2, 当第二个用完了三分之二, 在第一个没有任务运行的时候, 第二个能多用一些么? 如何平衡别人不用多用, 别人要用保持比例呢?
问题五: 将资源提供给多个 framework 的时候, 是一个节点的资源给第一个 framework, 第一个 framework 说我不用, 然后再给第二个 framework 么?
好了, 接下来我们来看 Mesos 双层调度的基本原理
一入门级理解 Mesos 双层调度
Mesos 的调度过程如图所示:
Mesos 有 Framework, Master, Agent, Executor, Task 几部分组成这里面有两层的 Scheduler, 一层在 Master 里面, allocator 会将资源公平的分给每一个 Framework, 二层在 Framework 里面, Framework 的 scheduler 将资源按规则分配给 Task
二进阶级理解 Mesos 双层调度
Mesos 采用了 DRF(主导资源公平算法 Dominant Resource Fairness),Framework 拥有的全部资源类型份额中占最高百分比的就是 Framework 的主导份额 DRF 算法会使用所有已注册的 Framework 来计算主导份额, 以确保每个 Framework 能接收到其主导资源的公平份额
举个例子
考虑一个 9CPU,18GBRAM 的系统, 拥有两个用户, 其中用户 A 运行的任务的需求向量为 {1CPU, 4GB}, 用户 B 运行的任务的需求向量为 {3CPU,1GB}, 用户可以执行尽量多的任务来使用系统的资源
在上述方案中, A 的每个任务消耗总 cpu 的 1/9 和总内存的 2/9, 所以 A 的 dominant resource 是内存; B 的每个任务消耗总 cpu 的 1/3 和总内存的 1/18, 所以 B 的 dominant resource 为 CPUDRF 会均衡用户的 dominant shares, 执行 3 个用户 A 的任务, 执行 2 个用户 B 的任务三个用户 A 的任务总共消耗了 {3CPU,12GB}, 两个用户 B 的任务总共消耗了 {6CPU,2GB}; 在这个分配中, 每一个用户的 dominant share 是相等的, 用户 A 获得了 2/3 的 RAM, 而用户 B 获得了 2/3 的 CPU
以上的这个分配可以用如下方式计算出来: x 和 y 分别是用户 A 和用户 B 的分配任务的数目, 那么用户 A 消耗了 {xCPU,4xGB}, 用户 B 消耗了 {3yCPU,yGB}, 在图三中用户 A 和用户 B 消耗了同等 dominant resource; 用户 A 的 dominant share 为 4x/18, 用户 B 的 dominant share 为 3y/9 所以 DRF 分配可以通过求解以下的优化问题来得到:
- max(x,y) #(Maximize allocations)
- subject to
- x + 3y <= 9 #(CPU constraint)
- 4x + y <= 18 #(Memory Constraint)
- 2x/9 = y/3 #(Equalize dominant shares)
最后解出 x=3 以及 y=2, 因而用户 A 获得 {3CPU,12GB},B 得到 {6CPU, 2GB}
三代码级理解 Mesos 双层调度
首先理解几个概念容易混淆: Quota, Reservation, Role, Weight
每个 Framework 可以有 Role, 既用于权限, 也用于资源分配
可以给某个 role 在 offerResources 的时候回复 Offer::Operation::RESERVE, 来预订某台 slave 上面的资源 Reservation 是很具体的, 具体到哪台机器的多少资源属于哪个 Role
Quota 是每个 Role 的最小保证量, 但是不具体到某个节点, 而是在整个集群中保证有这么多就行了
Reserved 资源也算在 Quota 里面
不同的 Role 之间可以有 Weight
Mesos 的代码实现中, 不是用原生的 DRF, 而是使用 HierarchicalDR, 也即分层的 DRF.
调用了三个排序器 Sorter(quotaRoleSorter, roleSorter, frameworkSorter), 对所有的 Framework 进行排序, 哪个先得到资源, 哪个后得到资源
总的来说分两大步: 先保证有 quota 的 role, 调用 quotaRoleSorter, 然后其他的资源没有 quota 的再分, 调用 roleSorter
对于每一个大步分两个层次排序: 一层是按照 role 排序, 第二层是相同的 role 的不同 Framework 排序, 调用 frameworkSorter
每一层的排序都是按照计算的 share 进行排序来先给谁, 再给谁 Share 的计算就是按照 DRF 算法
接下来我们具体分析一下这个资源分配的过程
1. 生成一个数据结构 offerable, 用于保存资源分配的结果
hashmap<FrameworkID, hashmap<SlaveID, Resources>> offerable;
这是一个 MAP, 对于每一个 Framework, 都会有一个资源的 MAP, 保存的是每个 slave 上都有哪些资源
2. 对于所有的 slave 打乱默认排序, 从而使得资源分配相对均匀
std::random_shuffle(slaveIds.begin(), slaveIds.end());
3. 进行第一次三层循环, 对于有 quota 的 Framework 进行排序
- foreach (const SlaveID& slaveId, slaveIds) {
- foreach (const string& role, quotaRoleSorter->sort()) {
- foreach (const string& frameworkId_, frameworkSorters[role]->sort()) {
对于每一个 slave, 首先对 role 进行排序, 对于每一个 role, 对于 Framework 进行排序, 排序靠前的 Framework 优先获得这个 slave
排序的算法在 DRFSorter 里面实现, 里面有一个函数 calculateShare, 里面的关键点在于进行了一个循环, 对于每一种资源都计算如下的 share 值:
share = std::max(share, allocation / _total);
allocation 除以 total 即一种资源占用的百分比, 这里之所以求 max, 就是找资源占用百分比最高的资源, 也即主导资源
但是这个 share 不是直接进行排序, 而是 share / weights[name] 除以权重进行排序如果权重越大, 这个值越小, 这个 role 会排在前面, 分配更多的资源
排序结束后, 对于每一个 Framework, 将当前 slave 的资源分配给它
Resources available = slaves[slaveId].total - slaves[slaveId].allocated;
首先查看这个 slave 的可用资源, 也即总资源减去已经分配的资源
Resources resources = (available.unreserved() + available.reserved(role)).nonRevocable();
每个 slave 上没有预留的资源和已经预留给这个 Framework 的资源都会给这个 Framework, 当然如果上面有预留给其他 Framework 的资源是不会给当前的 Framework 的
- offerable[frameworkId][slaveId] += resources;
- slaves[slaveId].allocated += resources;
分配的资源会保存在数据结构 offerable 中
4. 进行第二次三层循环, 对于没有 quota 的 Framework 进行排序
- foreach (const SlaveID& slaveId, slaveIds) {
- foreach (const string& role, roleSorter->sort()) {
- foreach (const string& frameworkId_,frameworkSorters[role]->sort()) {
5. 全部分配结束后, 将资源真正提供给各个 Framework
- foreachkey (const FrameworkID& frameworkId, offerable) {
- offerCallback(frameworkId, offerable[frameworkId]);
- }
这里的 offerCallback 是调用 Master::Offer, 最终调用 Framework 的 Scheduler 的 resourceOffers, 让 Framework 进行二次调度
最后, 让我们来解答一下这些问题:
问题一: 如果有两个 framework, 一万个节点, 按说应该平均分配给两个 framework, 怎么个分法? 一人一台这样分, 还是前五千给一人, 后五千给第二个人, 还是随机分, 随机分怎么个分法?
答: 是随机分, 怎么分呢? 是将节点随机排序, 但是排好序之后, 就不再随机分了, 而是开始排序, 比如随机后的节点队列中的第一个节点分给了第一个 framework, 等下次循环再排序的时候, 第二个 framework 由于没有拿到资源, 排在了第一个 framework 的前面, 于是第二个节点就分配给了第二个 framework, 然后 for 循环到第三个节点的时候 (这是外层循环), 内层循环对 framework 排序的时候, 第一个 framework 又排在了第二个前面, 于是第三个节点分给了第一个 framework 就这样你一个, 我一个, 实现了平均分配
问题二: 在没有 reserved 情况下, 每个节点是只能得给一个 framework, 还是可以分给多个 framework?
答: 是的, 在没有 reserved 的情况下, 一个节点是只给一个 framework, 如果有 reserved 的情况下, reserved 的那部分会给 reserve 它的那个 framework, 其他的部分, 还是只能给一个 framework, 不一定是哪一个, 看谁排在前面
问题三: 如果两个 framework 的权重比例为 1 比 2, 是如何保证资源分配是这个比例?
答: 也是通过排序来的, 对节点的 for 循环是外层循环, 对 framework 的排序和循环是内层循环, 第一次排序的时候, 权重为 2 的 framework 排在前面, 于是第一个节点是它的, 第二次排序的时候, 还是权重为 2 的 framework 排在前面, 于是第二个节点也是它的, 第三次排序的时候, 权重为 1 的 framework 由于从来没拿到过资源, 排在了前面, 于是第三个节点是它的就这样你两个, 我一个, 你两个, 我一个, 实现了资源按权重分配
问题四: 如果两个 framework 的权重比例为 1 比 2, 当第二个用完了三分之二, 在第一个没有任务运行的时候, 第二个能多用一些么? 如何平衡别人不用多用, 别人要用保持比例呢?
答: 能的如果权重为 2 的 framework 用完了三分之二, 则每次排序, 它都会排在权重为 1 的但是没有得到资源的 framework 后面, 按说它永远得不到资源但是算法中会有一个 filter 机制, 当一个节点分给某一个 framework 之后, 如果这个 framework 不用, 退回来, 则下次再遇到这个 framework 的时候, 先 filter 掉, 这样另一个 framework 就有机会得到这个节点了下次又不会 filter 掉了
问题五: 将资源提供给多个 framework 的时候, 是一个节点的资源给第一个 framework, 第一个 framework 说我不用, 然后再给第二个 framework 么?
答: 不是的统一运行一遍分配算法, 把资源都全部分配好, 才统一发送给 framework, 如果需要再次分配, 是下次统一计算的时候了
来源: https://www.cnblogs.com/popsuper1982/p/8571270.html