结合Cepb自身的特点, 较为合理的做法是将QoS机制直接嵌入每个OSD中来实现。
dmclock基本原理
mclock算法
mClock基本原理主要包含以下两个方面。
1) 为客户端设置一套QoS模板, 并在每个1/0请求中携带该QoS模板。
2) 服务器计算每个VO请求的时间标签, 并分成两个不同的阶段处理1/0请求:首先进入基于预留时间标签的Constraint-Based阶段, 处理所有预留时间标签满足条件e 的 I/0请求;然后进入基于上限和权重时间标签的Weight-Based阶段, 处理上限时间标签满足条件的I/0请求, 如果有多个客户端同时满足条件 , 则依据权重时间标签的大小决定处理顺序, 即权重时间标签较小的客户端I/0请求将被优先处理。
dmClock
dmClock在mClock算法的基础上, 针对分布式系统的特点做了相应修改。 其在分布式系统的每个服务器上运行一个改进的mClock-server, 在客户端驻留改进的mClock-client以统计各个服务器完成的I/0请求个数,并据此调整服务器处理I/0请求的速率,以期在总体上达到客户端的QoS限制目标。
与mClock的差别主要体现在以下儿个方面:
I)分布式系统的各个服务器在回应1/0请求时,返回其是在哪个阶段(phase)被处理完成的(即Constraint-Based阶段或Weight -Based阶段)。
2)客户端统计各个服务器完成的I/0请求个数,在向某个服务器下发I/0请求时,携带自上次下发I/0请求之后,除目标服务器以外的其他服务器完成的1/0请求个数之和,即两次I/0下发之间的I/0请求完成数的增量,分别使用p(rho)和o(delta)表示以上两个阶段的增量。
3)服务器计算I/0请求的时间标签时,不再根据步长均匀递增,而是使用p和6作为调整因子,从而动态调整各个服务器处理该客户端I/0的频度,使得总体处理速率满足QoS设置的约束条件。
I/0 请求入队
客户端的I/0请求发送至服务器后,首先进入client对应的子队列排队, 同时服务器计算该请求的时间标签值, 然后 依据时间标签的大小调整其在二叉树中的位置。 这个过程称为I/0请求入队。
具体来说, 如果某个client的I/0请求子队列中还存在未处理的请求, 则新的I/0请求直接挂入子队列尾部即可;如果client的子队列中不存在未处理的请求, 或者是一个全新的client的请求(此时需要先创建相应的子队列), 则除了将该I/0请求挂入其子队列外, 还需要将client加入时间标签二叉树,并依据时间标签的大小将其调整至正确的位置(该I/0请求是client子队列的第一个元素)。各时间标签二叉树的调整规则如下。
□ 预留二叉树:以节点的队首元素的预留时间标签为依据,值较小的节点尽量调整至树的上层, 反之调整至下层, 最终根节点的预留时间标签最小。
□ 上限二叉树: 用ready标记来表明每个1/0请求是否满足出队条件(上限时间标签是否小于或等于当前时间),默认为false, 满足条件的请求 ready标记为true, 并将相应的节点往下层调整;反之则往上层调整,标记相同的节点依据时间标签的大小 决定位置。
□ 权重二叉树:同样以ready标记来区分请求,与上限二叉树不同的是, 队首元素的 ready标记为true的节点往上层调整,ready标记为false的节点往下层调整;标记相同的节点则 依据权重标签大小, 值较小的置于上层,反之置于下层。
I/0 请求出队
I/0请求出队是指在client队列中选择适当的client, 从其1/0请求队列中出队一个元素的过程。 通过前面原理部分的阐述我们知道, 这个流程首先进入Constraint-Based阶段,取预留二叉树根节点的I/0请求队列, 判断其队首元素的预留时间标签是否满足出队条件(小于或等于当前时间)。 如果条件满足,则选取该根节点对应的client, 从其请求队列的队首出队一个元素;否则进入Weight-Based阶段, 从上限二叉树根节点开始,逐个判断队首元素的上限时间标签是否小千或等于当前时间, 并设置满足条件的请求的ready标记为true, 以决定其是否可参与随后的权重竞争。 所谓权重竞争, 是指对所有上限时间标签满足条件的client, 依据其队首元素的权重时间标签大小, 调整自身在权重标签二叉树中位置的过程, 最终位于权重标签二叉树根节点的client竞争胜出。 最后, 从竞争胜出者的1/0请求队列的队首出队一个请求。
dmClock 的实现中支持突破上限 (allow limit break) 模式, 能在不满足上限或预留时间标签条件的情况下出队请求, 这在某些对 QoS 上限没有严格要求的场景下, 可以让服务器的VO资源充分得到利用。 不过大部分应用场景都有限制上限的要求, 因而本书主要阐述关闭了该模式的情况。
dbclock支持带宽限制
dmClock是一种I/0调度算法, 它主要关注1/0个数而非I/0大小。但是I/0大小对于一个 I/0 请求的影响不容忽视。 例如, 两个 QoS 模板相同的客户端同时运行, 但客户端A 都是 1MB 的大块 I/0 读写, 而客户端B 都是 8kB 的小块 I/0 读写, 显然客户端 A 可能抢占客户端B 的 I/0 带宽资源。 为此, dmClock 以 8kB作为 I/0 块大小的基准, 依据磁盘的平均寻道时间和磁盘的传输带宽, 将大块 1/0 转换为 8kB 的倍数(计算公式请参考 mClock 算法论文)作为调整因子, 作用在该 I/0 请求的时间标签上, 以推迟该请求的处理时机, 从而减少由千 I/0 大小悬殊带来的不利影响。 然而, 这种做法并不完美,依然存在如下一些问题:
1) 无法实现对客户端 I/0 带宽的精确限制需求。 上述对 I/0 大小进行转换是一种定性的计量方式而且实际应用的 I/0 大小并不固定, 这样显然无法实现 I/0 带宽精确限制。
2) 影响原有 QoS 的准确性。 比如某个客户端的 QoS 上限设置为 100, 当其以较大的 I/0 块大小(例如 64kB) 读写时, 由于转换成 8kB 大小而调整了时间标签, 使得每个 I/0 请求都被延迟处理, 最终客户端得到的 I/0 上限必将低于 100, 这通常不是客户所期望的结果。
3) 在 dmClock 算法刚提出的时候, 机械硬盘是主流的存储介质, 而随着 SSD 等高速设备逐渐普及, 上述采用寻道时间的计算方式也不再适用。
基于上述种种因素, 目前 Ceph 中的 dmClock 并未实现这种方式, 也不支持对 I/0 带宽的限制。 然而, 作为一个完整的 控制策略, 带宽限制是一项必不可少的需求。特别是对块设备而言, 顺序 I/0 通常会被客户端的操作系统合并, 导致 QoS 的 IOPS 控制不准确气而 I/0 带宽的限制则不受此类合并操作的影响。