空闲/后台工作类别设计文档

目前,我们在空闲时的行为并不理想,它是为持续负载下的服务器设计的,目的是将待处理的工作保持在“中等”水平,让工作积累起来,以便我们能够以更高效的批处理方式进行处理,同时也能为负载突增留出余量。

但对于桌面或移动设备——工作不太持续且功耗更重要的场景——我们希望以不同的方式运行,即“快速进入空闲”,以便系统可以进入休眠状态。我们不希望在系统应该空闲时仍然零星地处理后台工作。

复杂因素在于存在许多后台任务,它们形成了一个层级结构(或一个有向图,取决于你如何划分)——一个后台任务可能会为另一个任务生成工作。

因此,正确的空闲检测需要对这种层级结构进行建模。

  • 前台写入

  • 页缓存回写

  • Copygc, rebalance

  • 日志回收

当我们实现空闲检测并快速进入空闲时,我们需要注意不要过多地扰乱系统在持续负载下运行良好(或在 rebalance 的情况下可能改进它,它目前没有主动尝试让工作批量处理)的现有行为。

持续负载状态

当系统处于持续负载下时,我们希望这些作业持续运行——这可能最好用 P/D 控制器来建模,它们会尝试将目标值(即碎片化磁盘空间、可用日志空间)大致保持在某个范围的中间。

在持续负载下的目标是平衡我们处理负载峰值的能力,同时不耗尽 x 资源(空闲磁盘空间、日志中的空闲空间),并让一些工作积累起来进行批处理(或变得不必要)。

例如,我们不希望过于激进地运行 copygc,因为那样它会清空那些无论如何都会变空(被覆盖或删除)的桶,我们也不希望等到几乎没有可用空间时才运行,因为那样系统会表现得不可预测——突然我们需要做更多的工作来服务每次写入,系统变得慢得多。

空闲状态

当系统变为空闲时,我们应该开始更快地刷新待处理的工作,以便系统可以进入休眠状态。

请注意,“空闲”的定义取决于任务在层级结构中的位置——当任务上方的任务停止生成新工作时,该任务应开始更快地刷新工作。

例如,当页缓存回写空闲时,rebalance 应该开始更快地刷新;只有当 copygc 和 rebalance 都空闲时,日志回收才应该开始更快地刷新。

当有更多工作正在进行中且我们仍有空间时,让工作积累起来是很重要的,因为如果我们允许其批量处理,刷新总是更高效的。新的写入可能会在 rebalance 移动数据之前覆盖它,并且任务可能会为日志回收需要刷新的 btree 节点生成更多更新。

在空闲时,我们在每个时间间隔内完成的工作量应与我们空闲的时间长度成比例。如果我们只空闲很短时间,我们不应该立即刷新所有内容;系统可能很快就会唤醒并开始生成新工作,立即刷新最终可能会做很多本来不必要的工作,如果我们允许更多地批量处理的话。

总而言之,我们将需要

  • 一个生成工作的后台任务类别列表,其中包括一个“前台”类别。

  • 对每个类别的跟踪——“我正在工作,还是已经进入休眠状态?”

  • 并且每个类别在决定发出多少工作时,都应该检查其上方的类别。