写点什么

减少超十万 CPU 内核,省下数千台主机,Uber 弄了个自动化 CPU 垂直扩展年省数百万美元

  • 2022-08-04
  • 本文字数:3493 字

    阅读完需:约 11 分钟

减少超十万 CPU 内核,省下数千台主机,Uber 弄了个自动化CPU垂直扩展年省数百万美元

本文描述了一个自动化的 CPU 垂直扩展系统的实现,在该系统中,优步(Uber)上运行的每个存储工作负载都被分配到了理想数目的内核。如今,该框架已被用于调整超过 50 万个 Docker 容器,自其建立以来,已净减少了超过 12 万个内核的分配,从而每年节省了数百万美元的基础设施支出。


优步(Uber),我们在容器化环境中运行所有的存储工作负载,如 Docstore、 Schemaless、M3、MySQLCassandra、Elasticsearch、etcd、Clickhouse 和 Grail。总的来说,我们在将近 7.5 万台主机上运行了超过 100 万个存储容器,其中 CPU 内核数超过了 250 万个。为了降低相邻组件间互相干扰的风险,每个工作负载都分配了一组独立的 CPU 内核,并且主机不会超额配置。我们还运行了一个多区域复制设置,它允许数据流量作为事件响应的一部分从整个区域中流出。


图 1:优步状态管理平台的关键指标。


一个主要挑战是为每个容器分配正确数量的 CPU 内核 直到最近,为每个容器设置的适当内核数量都是由负责每种存储技术的工程师手动确定的。


这种方法的优点是,领域专家有责任监控他们的每项技术并做出正确的决策。缺点是,需要人工来完成这项工作,而且当设置会导致成本或可靠性问题时,这往往会成为一种响应式的扩展策略,而不是一种主动的方式,即根据实际使用情况垂直扩缩容器,以确保以尽可能低的成本实现一致的性能。

为 CPU 垂直扩展选择正确的度量指标


正确调整容器大小的第一步是定义我们所说的“合适大小”。简而言之,我们希望在不影响容器中运行的工作负载的性能的情况下,为每个容器分配尽可能少的资源。


可以使用不同的策略来确定要分配给每个存储容器的正确内核数目。一种非常直接的方式是在核心业务指标(例如,P99 延迟)和容器分配之间建立反馈回路。如果反馈回路足够紧凑和快速,则可以提高或降低分配,以确保始终能有正确分配。然而,这种方式不太适合管理存储工作负载,原因如下:


  • 在主机之间移动存储工作负载可能需要数小时。由于数据需要与计算资源一起携带,因此必须避免使用在主机之间频繁移动工作负载的模型。

  • 负载在一周之内可以很容易地改变 2-5 倍。由于负载变化如此之大,很难创建一个模型来确定要分配的最佳内核数量,因为大多数情况下,容器都会被超额配置。

  • 不同的用例将有不同的关键指标来进行监控。构建一个适用于批处理工作负载的模型将与低延迟用例(比如,为 Uber Eats 应用程序提供餐厅菜单)大不相同。



图 2:展示了存储容器的 CPU 利用率(蓝色)、整个期间测量的峰值利用率(绿色)、当前分配(橙色)和要达到的最佳分配(红色)。在数周的时间内,扩缩器在几周内逐渐将分配收敛到最优值。


我们没有监控关键业务指标,而是基于每个存储容器的外部测量 CPU 利用率构建了一个模型。该模型确保了历史测量的峰值 CPU 利用率和分配给容器的内核数量之间的特定比率。峰值使用率和分配之间的比率将被称为 CPU 使用率。图 2 显示了基于过去 14 天 CPU 使用率的模型如何确定峰值使用率(绿色),并由此计算目标分配(红色)。该图还显示了当前 CPU 分配(黄色)如何逐渐收敛到绿线的。

这种方式的好处如下:


  • CPU 利用率指标始终可用。这确保了我们可以创建一个“适合所有人的模型”,避免了为每种存储技术或用例创建模型的耗时工作。

  • CPU 利用率指标每周都相当稳定,因此在大多数情况下,过去两周就能相当准确地预测未来几周的峰值使用情况。

  • 在区域故障转移(failover)期间,CPU 利用率往往会以可预测的方式增加。通过设定目标,比如 40% 的 CPU 利用率,可以相当肯定的是,在区域故障转移期间,CPU 利用率不会超过 80%,在最坏的情况下,负载会短暂地增加一倍。有关如何计算峰值 CPU 利用率的更多详细信息将会在下一节中介绍。



图 3:对大多数 Schemaless 实例应用 CPU 扩展前后的峰值 CPU 利用率直方图。低(Low)是指峰值使用率低于 25%,高(High)是指峰值利用率高于 45%。处于低类别从来都是不理想的,但有时是必要的。对于不受事件 / 故障转移影响的存储实例来说,处于高类别是有意义的。


图 3 显示了 Schemaless 技术启用 CPU 垂直扩展前后的峰值 CPU 使用率的直方图。默认情况下,扩缩器设置为以 40% 的峰值 CPU 使用率为目标。选择 40% 是为了确保有空间进行区域故障转移(可能会使负载增加一倍)。之所以选择 40%,是因为我们不想超过大约 80% 的 CPU 利用率。由于启用了超线程,当 CPU 利用率超过 80% 时会出现拥塞问题。


对比图 3 中的前后,我们可以观察到超额配置分配(低类别)的比率显著下降了。它之所以没有完全消失,主要是因为 Schemaless 运行在基于 Raft 的领导者 / 追随者 (Leader/Follower) 设置中,每个集群只有一个领导者(leader)。只有领导者可以提供一致的读取,并且对于某些用例,它的请求率明显高于其他用例。在任何给定的时间里,任何其他容器都可以成为领导者,因此,来自同一集群的所有容器都要均衡扩缩。


从图 3 也可以清楚地看出,高类别容器的比例有所上升。这实际上是有意为之的,因为我们已经意识到,在区域故障转移期间,一些存储集群的负载不会增加太多。因此,对于这些集群,我们可以设定一个明显更高的峰值使用率。


正确调整与 Schemaless 相关的所有容器的大小的最终效果是总体减少了大约 10 万个内核,即约 20%。Uber 使用的典型主机有 32 核或 48 核,分配率在 83% 左右,在大多数情况下,CPU 内核是瓶颈。因此,这 10 万个内核可以节省 3000 台主机(终端用户的延迟不变)。


CPU 垂直扩缩器 不仅节省了大量的成本,而且还确保了全面一致的性能和可靠性。在区域故障转移期间,这一影响非常明显,因为现在容器普遍地被分配了所需的资源,因此不会像过去那样产生延迟下降。

计算分配目标


上一节讨论了为什么可以使用 CPU 容器指标来垂直调整存储工作负载的大小。在本节中,我们将更详细地介绍如何准确地计算目标。术语 Pod,借用自 Kubernetes,在下文中它将用于描述在单个主机上运行的存储工作负载的容器集合。


如前所述,计算每个 Pod 要设置的 CPU 分配模型是:基于计算峰值 CPU 利用率,然后将其转换为确保给定峰值 CPU 利用率的分配。另一个重要的注意事项是,同一存储集群中的所有 Pod 必须分配相同数量的内核。原因是存储集群内的职责可能会随着时间的推移而变化,因此必须为所有 Pod 分配足够的资源,以便它们能够成为集群中最繁忙的 Pod。



图 4:计算给定存储集群的峰值 CPU 利用率所涉及的步骤。默认情况下,总是回溯两周,以确保周末峰值在数据集中得到很好的体现。


图 4 显示了如何根据过去 14 天的 CPU 利用率数据计算峰值 CPU 利用率。CPU 利用率数据是使用 cexporter 收集的,并作为时间序列发布到我们的监控堆栈 M3 中。该算法的步骤如下:


  1. 从同一存储集群所有 Pod 的原始 CPU 利用率信号开始。使用两周的窗口与优步系统负载变化的时间尺度相匹配,因为我们以每周模式为主,峰值负载发生在周五和周六晚上。使用 2 周回溯可以确保数据集中始终包含 2 个周末。

  2. 将原始时间序列降采样(downsample)到 8 小时分辨率。在此步骤中,每个 Pod 的原始时间序列被降采样为 8 小时分辨率,计算每个时间窗口的 P99 CPU 利用率。8 小时时间间隔的 P99 确保 CPU 利用率在每 8 小时的窗口中最多有 5 分钟超过这个值。我们已经尝试了从 4 小时到 24 小时的不同采样窗口。使用 8 小时似乎可以提供良好的信噪比,可以避免过度索引异常值,但也不会错过重要的峰值。

  3. 将每个 Pod 信号压缩为集群信号。在此步骤中,根据时间戳来选择最繁忙的 Pod 的值。这会将每个 Pod 的信号压缩为集群级信号。对于像 Cassandra 这样的存储技术,每个集群有大量的 Pod,因此取而代之的是根据时间戳选择 P95 值。

  4. 将第三高峰值定义为集群的峰值 CPU 利用率。在最后一步中,从集群的 42 个数据点(14 天 *3 个数据点 / 天)中提取峰值 CPU 利用率。峰值 CPU 利用率被定义为第三高的数据点。通过选择第三高的数据点,我们避免了对异常值的过度索引。在确定了每个集群的峰值 CPU 利用率后,我们将配额计算为:



配额被四舍五入到最接近的整数,以避免小数内核分配。我们希望避免由于使用 cpusets 进行工作负载分离而导致的小数内核分配。

总  结


自 2021 年初启用 CPU 垂直扩展以来,优步通过该工具减少了超过 12 万个内核分配,节省了数百万美元的硬件开支。同时,我们通过确保所有存储 Pod 的大小一致性,提高了平台的整体可靠性。

由于工程师现在只需要表达所需的利用率,而不必手动计算和执行分配更改,因此在正确调整存储集群大小方面所花费的工程工作也大大减少了。他们正在进行根据故障转移行为和临界性确定每个存储群集要设置的最佳利用率的工作。


原文链接:

https://eng.uber.com/vertical-cpu-scaling/

2022-08-04 17:052684
用户头像
李冬梅 加V:busulishang4668

发布了 578 篇内容, 共 214.3 次阅读, 收获喜欢 752 次。

关注

评论

发布
暂无评论
发现更多内容

Java开发之线程、多线程,线程池面试题

@零度

多线程 线程池 JAVA开发

DM 分库分表 DDL “乐观协调” 模式介绍丨TiDB 工具分享

PingCAP

从新手到专家:如何设计一套亿级消息量的分布式IM系统

WorkPlus

解决 GitLab 报错:You are not allowed to force push code to a protected branch on this project

AlwaysBeta

git gitlab

愉悦圣诞 暖意融心

龙智—DevSecOps解决方案

“数”驰天下,华为云DRS 高效支撑T3出行平稳迁移

华为云开发者联盟

数据库 数据迁移 华为云DRS T3出行

拿捏SQL数据分析:从基础破冰到面试题解

博文视点Broadview

React vs Angular,到底那个更好用

编程江湖

前端开发

在线上传图片二维码识别解析

入门小站

工具

HDFS(Hadoop分布式文件系统)

编程江湖

大数据 hdfs

服务器数量从21台降至3台,TDengine在跨越速运集团的落地实践

TDengine

数据库 tdengine 时序数据库

Log4j2 消停了,Logback 开始塌房了?

程序猿DD

Java 日志 漏洞

Linux之tail命令

入门小站

Linux

大数据开发之sparkSQL的使用分享

@零度

大数据 Sparksql

云小课|DGC数据开发之基础入门篇

华为云开发者联盟

大数据 数据湖治理中心 云数据开发 DLF

腾讯云商用密码合规解决方案,亮相2021商用密码应用创新高端研讨会

腾讯安全云鼎实验室

商用密码 云上安全 数字生态 安全服务

TCP 两次握手为什么无法阻止历史连接?

华为云开发者联盟

TCP 报文 握手 RST 报文 两次握手

Linux之tail命令

入门小站

Linux

给弟弟的信第22封|写技术博客有哪些益处?

大菠萝

28天写作

AI新手语音入门:认识词错率WER与字错率CER

华为云开发者联盟

语音识别 词错率 WER 字错率 CER

打造“智慧之眼”与“创新之轮”,华睿科技助推制造业智能升级

科技新消息

群聊泄密敲响警钟,WorkPlus织密信息安全“防护网”

WorkPlus

学习乐器的好处

Tiger

28天写作

python 数据分析找到老外最喜欢的中国美食【完整代码】

1_bit

Python

DataPipeline与海量数据完成产品互认证,助推数据管理信创生态新进程

DataPipeline数见科技

数据库 中间件 数据融合 数据迁移 数据管理

图解带你掌握`JVM`运行时核心内存区

华为云开发者联盟

Java JVM 内存 堆内存

如何用建木CI生成Allure报表

Jianmu

CI/CD Allure 国产开源

如何有效使用预训练语言模型

云智慧AIOps社区

算法 智能运维 云智慧 语言模型 南加州大学

Linxu云计算这样学效率更快,Linux基础篇,expect-正则表达式-sed-cut的使用

学神来啦

Linux centos sed linux运维 expect

前端开发之JS中编写For循环的方法

@零度

JavaScript 前端开发

减少超十万 CPU 内核,省下数千台主机,Uber 弄了个自动化CPU垂直扩展年省数百万美元_文化 & 方法_Lasse Vilhelmsen_InfoQ精选文章