Netflix 如何正确计算docker中containers的CPU分配( 二 )


· 避免将容器分散到多个NUMA套接字(避免潜在的缓慢的跨套接字内存访问或页面迁移)
· 除非需要,否则不要使用超线程(以减少L1/L2抖动)
· 尝试平衡L3缓存上的压力(基于对容器硬件使用的潜在测量)
· 不要在不同的位置决策之间做太多的调整
考虑到系统的低延迟和低计算需求(我们当然不希望花费太多的CPU周期来弄清楚容器应该如何使用CPU周期!),我们实际上能在实践中实现这一点吗?
实现(Implementation)我们决定通过Linux cgroups(http://man7.org/linux/man-pages/man7/cgroups.7.html)实现该策略,因为CFS完全支持它们,方法是根据容器到超线程的所需映射修改每个容器的cpuset cgroup 。通过这种方式,用户空间进程定义了一个"围栏",CFS在其中对每个容器进行操作 。实际上,我们消除了CFS启发式算法对性能隔离的影响,同时保留了它的核心调度功能 。
这个用户空间进程是一个名为Titus - isolation的Titus(https://github.com/Netflix-Skunkworks/titus-isolate)子系统,其工作原理如下 。在每个实例上,我们定义三个触发布局优化的事件:
· add: Titus调度程序为这个实例分配了一个新的容器,需要运行它
· remove:一个正在运行的容器刚刚完成
· rebalance:容器中的CPU使用量可能发生了变化,因此我们应该重新评估我们的位置决策
当最近没有其他事件触发位置决策时,我们会定期对重新平衡事件进行排队 。
每次触发一个放置事件时,Titus -隔离都会查询一个远程优化服务(https://en.wikipedia.org/wiki/Turtles_all_the_way_down),从而解决容器到线程的放置问题 。
然后,该服务查询一个本地GBRT(https://en.wikipedia.org/wiki/Gradient_boosting)模型(每隔几小时对从整个Titus平台收集的数据进行重新培训),该模型预测未来10分钟内每个容器的P95 CPU使用情况(条件分位数回归) 。该模型既包含上下文特性(与容器关联的元数据:谁启动了它、图像、内存和网络配置、应用程序名称……),也包含从主机定期从内核CPU会计控制器(https://www.kernel.org/doc/Documentation/cgroup-v1/cpuacct.txt)收集的容器的历史CPU使用量的最后一个小时中提取的时间序列特性 。
然后,这些预测被输入到一个MIP中,该MIP将被动态求解 。我们使用cvxpy(https://www.cvxpy.org/)作为一个很好的通用符号前端来表示问题,然后可以将其输入各种开源或专有的MIP解决程序后端 。由于MIPs是np困难的,因此需要采取一些谨慎的措施 。我们对求解程序施加了一个艰难的时间预算,以将分支和削减策略驱动到低延迟状态,并在MIP缺口周围设置护栏,以控制找到的解决方案的总体质量 。
然后,服务将位置决策返回给主机,主机通过修改容器的cpuset来执行该决策 。
【Netflix 如何正确计算docker中containers的CPU分配】例如,在任何时候,一个包含64个逻辑CPU的r4.16xlarge可能看起来是这样的(颜色比例表示CPU使用量):

Netflix 如何正确计算docker中containers的CPU分配

文章插图
 
结果(Results)该系统的第一个版本带来了令人惊讶的好结果 。我们平均将批处理作业的总体运行时减少了几个百分点,同时最重要的是减少了作业运行时差异(隔离的一个合理代理),如下所示 。在这里,我们看到一个实际的批处理作业运行时分布,有和没有改进的隔离:
Netflix 如何正确计算docker中containers的CPU分配

文章插图
 
请注意,我们主要是如何使长时间运行的异常值问题消失的 。不幸的吵闹邻居的右尾巴现在不见了 。
在服务业方面,增长更为显著 。一个专门为Netflix流媒体服务的Titus中间件服务在高峰流量时减少了13%的容量(减少了1000多个容器),以满足相同负载所需的P99延迟SLA!我们还注意到,由于内核在缓存失效逻辑上花费的时间要少得多,因此计算机上的CPU使用率也有了大幅下降 。我们的容器现在更容易预测,速度更快,机器的使用也更少了!鱼与熊掌不可兼得的情况并不常见 。
下一个步骤(Next Steps)我们对该领域迄今取得的进展感到兴奋 。我们正从多个方面着手扩展本文提出的解决方案 。
我们希望扩展系统以支持CPU超订阅 。我们的大多数用户都不知道如何正确设置应用程序所需的cpu数量 。事实上,这个数字在容器的生命周期内是变化的 。由于我们已经预测了容器未来的CPU使用情况,所以我们希望自动检测和回收未使用的资源 。例如,如果我们能够沿着下图的各个轴检测用户的灵敏度阈值,则可以决定将特定容器自动分配给未充分利用cpu的共享cgroup,从而更好地提高总体隔离和机器利用率 。


推荐阅读