写点什么

[大厂实践] Pinterest 通用计算平台实践

作者:俞凡
  • 2023-12-03
    上海
  • 本文字数:8440 字

    阅读完需:约 28 分钟

Pinterest 平台团队开发实现了名为 PinCompute 的高性能通用计算平台,支持 Pinterest 的大量异构用例和服务。本文介绍了团队在开发这一平台过程中的经验和实践,对于其他平台团队来说,具有很好的参考意义。原文: PinCompute: A Kubernetes Backed General Purpose Compute Platform for Pinterest


https://unsplash.com/photos/a-group-of-blue-boxes-ZfVyuV8l7WU

概述

现代计算平台是加速创新和高效运行应用程序的基础。我们正在 Pinterest 发展自己的计算平台,为 90%的用例提供以应用为中心、完全托管的计算 API,通过平台敏捷性、扩缩容性以及更低的系统更新成本来加速创新,并在基于 Kubernetes 的计算平台上运行用户应用程序来提高效率。我们将这个下一代计算平台称为 PinCompute,愿景是让 PinCompute 运行 Pinterest 最关键的应用程序和服务。


PinCompute 与平台即服务(PaaS)云计算模型保持一致,抽象了管理基础设施和 Kubernetes 的繁重工作,使用户能够专注于其应用。PinCompute 利用云原生原理(包括容器、微服务和服务网格)改进了 Pinterest 架构,通过提供和管理不可变基础设施、操作系统升级和 Graviton 实例,降低了维护系统更新的成本,并通过将增强的调度功能应用于大型多租户 Kubernetes 集群(包括超额订阅、bin 压缩、资源分层)来节省成本。


本文将讨论 PinCompute 的原语、架构、控制平面和数据平面功能,并展示 PinCompute 为 Pinterest 的创新和效率所带来的价值。

架构

PinCompute 是建立在 Kubernetes 之上的区域性平台即服务(PaaS),由一个主机 Kubernetes 集群(主机集群)和多个成员 Kubernetes 集群(成员集群)组成。主机集群运行区域联合控制平面,跟踪该区域的工作负载。成员集群是分区的,用于实际的工作负载运行。每个区域可以有多个成员集群,严格遵循云提供商定义的故障域,明确了平台的故障隔离和运行边界,确保可用性以及控制爆炸半径。所有成员集群在控制平面和数据平面功能之间共享标准的 Kubernetes 设置,并且支持异构功能(例如不同的工作负载类型和硬件选择)。PinCompute 支持多租户,运行不同团队和组织的各种类型的工作负载共享同一个平台,因此需要提供必要的隔离,以确保可以在租户之间安全有效的共享。


图 1: PinCompute 的高层架构


用户通过 Compute API 访问平台,对其工作负载执行操作。我们利用自定义资源(CR)来定义平台支持的工作负载类型,提供一系列工作负载编排功能,以各种形式支持批处理作业和长时间运行的服务。当工作负载被提交到平台时,首先通过主机集群的 Kubernetes API 进行持久化。然后,联邦控制平面将开始执行区域级别所需的工作负载管理任务,包括配额执行、工作负载分片和成员集群选择。然后,将工作负载分片分发到成员集群执行。成员集群控制平面由负责编排不同类型工作负载的内部和开源 operator 组合而成。联邦控制平面还从相应的成员集群中收集工作负载执行状态并聚合,以便通过 PinCompute API 消费。


图 2: PinCompute 执行和状态聚合工作流

PinCompute 原语

图 3: PinCompute 工作负载架构


PinCompute 原语服务于 Pinterest 上的异构工作负载,类型包括 long running(长时间运行)、run-to-finish(从运行到完成)、ML training(机器学习训练)、scheduled run(运行计划)等。这些用例本质上分为三类:(1)通用计算和服务部署,(2)运行到完成作业,以及(3)基础设施服务。Pinterest 运行到完成任务和基础设施服务由现有的Kubernetes原生资源和Pinterest特定资源支持。基于我们关于如何定义简单、直观和可扩展的计算原语的最新想法,PinCompute 引入了一组用于通用计算和服务部署的新原语,包括 PinPod、PinApp 和 PinScaler。


PinPod 是 Pinterest 通用计算的基本构建块。像原生 Kubernetes Pod 一样,PinPod 继承了 Pod 作为基础构建块的本质,同时提供了额外的特定于 Pinterest 的功能,包括容器更新、管理边车、数据持久化、故障转移等功能,这些功能使 PinPod 可以轻松用作 Pinterest 各种生产场景下的构建块。PinPod 的目的是在应用程序和基础设施团队之间建立明确的界限,同时仍然保持运行容器的轻量级性质。它解决了许多痛点,例如,每个容器更新可以加速应用程序滚动更新,减少资源消耗,消除在基础设施边车升级期间对用户容器的干扰。


PinApp 是一个抽象,提供了在 Pinterest 上运行和管理长期运行应用程序的最佳方式。通过利用 PinPod 作为应用程序副本,PinApp 继承了 PinPod 的所有集成和软件交付最佳实践。多亏了联邦控制平面,PinApp 提供了一组内置的编排功能,以满足常见的分布式应用程序管理需求,包括基于区域的部署以及区域容量平衡。PinApp 支持 Kubernetes 原生原语(如 Deployments 和 ReplicaSets)提供的功能,也支持对部署语义的扩展,以满足业务需求并增强可管理性。


PinScaler 是一个抽象,支持应用的自动缩放。它集成了 Pinterest 的本地指标仪表板 Statsboard,允许用户配置应用级指标与所需阈值,以触发缩放以及缩放保护措施,如冷却窗口和复本的最小/最大限制。PinScaler 支持简单的 CPU 和内存指标缩放、计划缩放和自定义指标缩放,以支持各种生产场景。


图 4: PinCompute 原语:PinPod、PinApp 和 PinScaler。PinPod 作为独立工作负载运行,也是高阶原始 PinApp 的可重用构建块。PinScaler 自动缩放 PinApp。


回到更大的图景,PinCompute 利用下一代原语(PinPod, PinApp, PinScaler)、本地 Kubernetes 和开源社区的构建块,以及与联邦架构的深度集成,提供以下用例:


(1)通用计算和服务部署: 由 PinCompute 的新原语类型处理。PinApp 和 PinScaler 帮助长时间运行的无状态服务快速部署和扩展。PinPod 作为通用计算单元,目前为 Pinterest 开发人员提供 Jupyter Notebook。


(2)运行到完成作业: PinterestJobSet 利用作业为用户提供一种执行运行到完成、无框架并行处理的机制; PinterestTrainingJob 基于Kubeflow社区的TFJob和PyTorchJob进行分布式训练; PinterestCronJob 基于CronJob来执行基于 cron 表达式的调度任务。


(3)基础设施服务: 基于DaemonSet的 PinterestDaemon,以及专有的 PinterestSideCar 支持不同的基础设施服务部署模式。能够被多个租户共享的组件(例如,日志代理、指标代理、配置部署代理)被部署为 PinterestDaemons,确保每个节点有一个副本,被该节点上所有 pod 所共享。不能共享的服务将基于 PinterestSideCar 部署在用户 pod 中的 sidecar 容器中。


PinCompute 原语使 Pinterest 开发人员能够托管基础设施管理以及相关的故障排除和运维问题,从而能够专注于不断发展的业务逻辑,以更好地为用户服务。

访问 PinCompute

用户通过 PinCompute 的平台接口访问 PinCompute 原语,该平台接口由 API 层、API 客户端层和支持这些 API 的底层服务/存储组成。


图 5: PinCompute 平台接口层的高层架构

PinCompute API

PinCompute API 是用户访问平台的网关,提供了三组 API: 工作负载 API、运维 API 和洞察 API。工作负载 API 包含在计算工作负载上执行 CRUD 操作的方法,调试 API(提供流日志或打开容器 shell 等机制),以对实时工作负载进行故障排除,洞察 API 为用户提供运行时信息,如应用程序状态变更和系统内部事件,以帮助用户了解现在和过去工作负载的状态。

为什么使用 PinCompute API

在原始 Kubernetes API 之上引入 PinCompute API 有很多好处。首先,当 PinCompute 联合许多 Kubernetes 集群时,PinCompute API 将用户请求与联合集成,并聚合跨集群信息,形成计算平台的整体用户端视图。其次,PinCompute API 高效访问 Kubernetes API,其包含缓存层可以有效提供读 API,从而从 Kubernetes API 服务器中卸载昂贵的列表和查询 API 调用。最后,作为网关服务,在访问不同的 PinCompute 后端服务(如 Kubernetes、节点服务、洞察服务、项目治理服务等)时,PinCompute API 确保了统一的用户体验。


图 6: PinCompute API 数据流

整合 Pinterest 基础设施

PinCompute API 层结合了 Pinterest 的基础设施功能,如速率限制和安全实践,以简化 Kubernetes API 的使用,并为 API 消费者和开发人员提供稳定的接口。PinCompute API 利用流量团队的速率限制边车和可重用的 Pinterest 组件,实现了速率限制机制,以确保公平使用资源。PinCompute API 还与 Pinterest 的专有安全原语完全集成,以确保身份验证、授权和审计机制遵循现有路径。集成这些能力使我们能够为 Pinterest 开发人员提供 API 调用和 API 资源级别粒度的统一访问控制体验,对于确保 PinCompute API 的可靠性、安全性和兼容性至关重要。

API 语义增强

PinCompute API 在 Kubernetes API 之上提供了增强的 API 语义,以改善用户体验。其中一个重要改进是以简化方式呈现了原始 Kubernetes 数据模型,在其中只包含与 Pinterest 构建软件相关的信息,这不仅减少了专注于构建高级应用程序逻辑的开发人员的基础设施学习曲线,还提高了 API 服务的数据效率。例如,删除托管字段将 PinCompute API 调用减少了多达 50%的数据。我们还以一种更具描述性的方式设计了 API,用于暂停、停止、重新启动容器等用例,这些用例在许多场景中都是直观且易于使用的。PinCompute 提供 OpenAPI 文档和自动生成的客户端、文档和 SDK,帮助用户在 PinCompute 上自助构建应用程序。

PinCompute SDK

为客户构建 SDK,从而标准化对 PinCompute 的访问,是我们的战略投资方向。通过 SDK,我们能够将最佳实践(如错误处理、带回退的重试、日志记录和度量)封装为可重用构建块,确保这些最佳实践始终应用于客户端。我们还发布和管理版本化 SDK,并提供如何基于 SDK 开发的明确指导。我们与用户密切合作,确保采用最新版本的 SDK,以优化与 PinCompute 的交互。

在 PinCompute 中管理资源

资源模型

PinCompute 支持三种资源层: 预留(Reserved)、按需(OnDemand)和可抢占(Preemptible),用户为每一层定义其项目的资源配额。预留级配额由固定大小的资源池和专用工作负载调度队列支持,保证调度吞吐量和容量可用性。按需级配额利用全局共享和动态大小的资源池,以先到先服务的方式为工作负载提供服务。抢占层是为了有机会利用未被使用的预留层和按需层的资源,这些资源将在相应的层需要时被回收。PinCompute 集群还配备了一个由活跃但未被使用的资源组成的缓冲空间,以适应突发的工作负载。下图说明了 PinCompute 的资源模型。


图 7: PinCompute 资源模型

调度架构

PinCompute 由两层调度机制组成,以确保有效调度工作负载。集群级调度在 PinCompute 的区域联邦控制平面上执行,集群级调度接受工作负载,选择一个或多个成员集群执行。在集群级调度期间,工作负载首先通过一组过滤器,过滤掉不适合的集群,然后通过一组计分机制对候选集群进行排序。集群级调度在保证高层次布局策略和资源需求得到满足的同时,还考虑了负载分布、集群健康等因素进行区域优化。节点级调度发生在成员集群内部,其中工作负载由相应的 operator 转换为 pod。创建 Pod 之后,使用 Pod 调度器将 Pod 放置到节点上执行。PinCompute 的 Pod 调度器利用 Kubernetes 的调度器框架,结合上游和专有插件,以确保调度器支持开源 Kubernetes 中可用的所有功能,但同时针对 PinCompute 的特定需求进行了优化。


图 8: PinCompute 调度架构

PinCompute 成本效率

成本效率对 PinCompute 来说至关重要。我们制定了各种方法,在不影响用户体验的情况下成功降低了 PinCompute 基础设施成本。


我们通过消除不必要的资源预留以及将用户工作负载迁移到跨联邦环境共享的按需资源池来促进多租户共享。我们与主要平台用户合作,以平滑工作负载提交模式,避免请求过多资源。我们还启动了一个平台级计划,将使用的 GPU 从 P4 系列实例切换到更具成本效益的替代品(即 G5 系列)。下图展示了 PinCompute GPU 成本与容量趋势,我们在支持业务增长的同时成功降低了成本。


图 9: PinCompute GPU 成本与容量的对比


展望未来,PinCompute 有几个正在进行的项目,以进一步提高成本效率。1)引入可抢占工作负载,鼓励更灵活的共享资源。2)加强平台资源分级和工作负载排队机制,在用户工作负载调度时兼顾公平性和效率,做出更明智的决策。

PinCompute 节点运行时

节点架构是一个关键领域,我们在其中投入了大量资金,以确保应用能够在容器化的多租户环境中安全、可靠和高效的运行。


图 10: PinCompute 节点和基础设施集成的高级体系架构

PinCompute 的 Pod

Pod 被设计用于隔离节点上的租户。当 Pod 启动时,被自动授予独立的网络标识、安全主体和资源隔离边界,这些在 Pod 的生命周期中是不可变的。


在 Pod 中定义容器时,用户可以指定两个生命周期选项: 主容器和边车容器。主容器遵循 Pod 级重启策略,而边车容器则确保在主容器需要运行时可用。此外,用户还可以定义边车和主容器之间的启动、终止顺序。PinCompute 中的 Pod 还支持容器级更新,这样就可以在 Pod 中应用新定义并重新启动容器,而不需要终止并再次启动 Pod。边车容器生命周期和每个容器更新是批处理作业执行可靠性和服务部署效率的关键特性。


PinCompute 有专有网络插件来支持各种容器网络需求。主机网络仅用于系统应用。"桥接端口(Bridge Port)"为不需要服务流量的 Pod 分配节点本地的、不可路由的 IP。对于需要服务流量的 Pod,提供从共享网络接口分配的可路由 IP,或者 Pod 可以请求"专用 ENI"进行完整的网络分段。通过云资源控制平面对 ENI、IP 分配等网络资源进行整体、高效管理。


PinCompute 支持各种卷,包括 EmptyDir、EBS 和 EFS。具体来说,我们有专有日志记录插件,集成了内部日志记录流水线,以确保高效可靠的日志收集。

整合 Pinterest 基础设施

PinCompute 节点包含用户容器和 Pinterest 的基础设施生态系统之间的关键集成点,即安全性、流量、配置、日志记录和可观察性。这些功能具有与 PinCompute 正交的独立控制平面,因此不局限于任何"Kubernetes 集群"边界。


基础设施功能以三种方式部署: 主机级守护进程、边车容器或双模式。守护进程由节点上运行的所有 Pod 共享,日志记录、指标和配置分发被部署为守护进程,因为它们不需要依赖 Pod 的租户,也不需要驻留在 Pod 中运行的应用程序的关键数据路径中。边车容器在 Pod 租户中运行,被依赖于 Pod 租户或需要流量和安全性等性能保证的功能所使用。


用户容器通过文件系统共享与基础设施功能(如日志记录、配置、服务发现)交互,或者通过网络(本地主机或 unix 域套接字)与流量和度量等功能进行交互。Pod(以及相关的租户定义)确保以安全有效的方式集成各种基础设施功能。

增强可运维性

PinCompute 节点拥有专有的节点管理系统,增强了节点的可见性和可运维性,包含节点级探测机制,为节点运行状况提供补充信号,涵盖容器运行时、DNS、设备、各种守护进程等领域。这些信号用作节点就绪判定,以确保新节点只有在所有功能就绪后才可调度,并且在应用运行时期间用于协助自动化和调试。作为节点服务质量(QoS)的一部分,当一个节点被标记为预留工作负载时,可以提供增强的 QoS 管理,例如配置预下载或容器镜像缓存刷新。节点还公开了诸如容器 shell 和实时日志流之类的运行时 API,以帮助用户分析工作负载故障。


图 11: PinCompute 的专有节点管理系统

管理 PinCompute 基础设施

优先级自动化

当涉及到减少人为错误和提高生产力时,自动化具有巨大的投资回报。PinCompute 集成了一系列旨在简化日常操作的专有服务。

自动修复

运维人员经常被琐碎的节点运行状况问题所困扰。PinCompute 配备了自动修复服务来自我修复这些问题。运行在节点管理器上的运行状况探测器检测节点问题,通过特定的信号注释对其进行标记,这些信号被监控并被解析为动作。然后,补救服务执行锁定或终止等操作。用于检测、监视和修复服务的组件符合解耦和可扩展性原则。此外,还可以执行限速或断路机制,从而为节点健康管理提供系统的方法。


图 12: PinCompute 自动修复体系架构

应用程序感知集群轮换

PinCompute 升级服务的主要功能是以一种安全、全自动的方式支持 Kubernetes 集群轮转,同时遵守 PinCompute 平台 SLO、轮转协议和优雅终止的用户协议。在处理集群轮转时,关注的范围包括轮转不同类型节点的顺序、节点的同时轮转、并行或单独轮转的节点以及节点轮转的特定时间。这种担忧源于在 PinCompute 平台上运行的用户工作负载的多样性。通过 PinCompute 升级服务,平台运维可以明确指定希望如何进行集群轮转,通过配置定义精心管理的自动进程。

发布 PinCompute

验证平台

PinCompute 发布流水线由四个阶段组成,每个阶段都是一个单独的联合环境。变更通过阶段性部署,并在发布之前进行验证。端到端测试框架在 PinCompute 上持续运行,以验证平台的准确性。框架模拟了真正的用户,并作为恒定的金丝雀来监督平台的正确性。


图 13: PinCompute 发布过程

机器镜像(AMI)管理

考虑到用户对硬件系列、可管理性和成本效益的需求,PinCompute 选择性的提供有限的节点类型集。负责引导这些节点的 AMI 分为三类: 通用 AMI、专注于机器学习的 AMI 和可定制 AMI。从父 AMI 和配置继承的概念大大简化了对其的管理。每个 AMI 都根据类型和版本进行标记,利用升级服务启动自动部署。

面向运维和用户的工具

在 PinCompute 中,我们为平台用户和运维人员提供了一组工具,以方便的操作平台及其上运行的工作负载。我们构建了一个实时调试系统,为最终用户提供基于 UI 的容器 shell,以便在 Pod 中进行调试,同时提供流控制台日志和基于文件的日志,以了解应用运行情况。该工具利用专有的节点级 API 将用户调试与关键控制路径(如 Kubernetes API 和 Kubelet)解耦,并确保故障隔离和可伸缩性。自助服务项目管理和教程还减少了用户加载新项目或调整现有项目属性(如资源配额)的开销。PinCompute 的集群管理系统为编辑集群属性提供了交互机制,使得迭代新硬件或调整容量设置变得非常方便。易于使用的工具链提供了高效和可扩展的运维,并随着时间推移大大改善了平台的用户体验。

可伸缩性和 SLO

PinCompute 旨在支持 Pinterest 规模的计算需求。可伸缩性是一个复杂的目标,对我们来说,每个 PinCompute 的 Kubernetes 集群都被优化到最佳点,即每分钟 3000 个节点、120K 个 Pod 和 1000 个 Pod 变更操作,工作负载端到端启动延迟的 P99 为 25 秒。这些可伸缩性目标是由 Pinterest 上大多数应用程序的需求定义的,并且是平衡多个因素的结果,包括集群大小、工作负载敏捷性、可运维性、爆炸半径和效率。这个目标使每个 Kubernetes 集群成为整体计算的坚实构建块,并且 PinCompute 架构可以通过添加更多成员集群来水平扩展,以确保足够的可伸缩性以满足 PinCompute 的持续增长。


PinCompute 以两种形式定义 SLO: API 可用性和平台响应性。PinCompute 确保其关键工作负载编排相关 API 的可用性达到 99.9%。PinCompute 提供控制平面调用延迟 SLO,专注于系统采取行动的延迟。根据工作负载复杂性和相应的业务需求,这种延迟从几秒到几十秒不等。对于预留层的服务质量,PinCompute 提供了工作负载端到端启动速度的 SLO,不仅关注平台采取的行动,还包括这些行动能够多快生效。这些 SLO 是平台级性能和可用性的重要信号,也为平台开发人员以高质量迭代平台功能设定了高标准。

学习和未来的工作

在过去几年里,我们已经在架构和 Pinterest 所需的一系列功能方面使这个平台成熟起来。引入计算作为平台即服务(PaaS)被视为 Pinterest 开发者的最大胜利。一项内部研究表明,超过 90%的用例以及 60%的基础设施占用可以从利用 PaaS 来迭代的软件中受益。作为平台用户,PaaS 抽象了拥有和管理基础设施和 Kubernetes 的繁重工作,使用户能够专注于应用程序的独特方面。作为平台运营商,PaaS 通过标准化实现了整体基础设施管理,为提高效率和降低维护基础设施更新的成本提供了机会。PinCompute 支持"API 优先",定义了清晰的支持合约,使平台支持可编程性和可伸缩性。此外,平台中"租户"的可靠定义在用例之间以及与基础设施功能的交互之间建立了清晰的边界,这对于多租户平台的成功至关重要。最后,通过加强自动化,改善了支持响应时间,减少了团队 KTLO 和随叫随到的开销。


随着 PinCompute 在 Pinterest 的使用不断扩大,有很多令人兴奋的机会。资源管理和效率是我们正在努力的一个大领域;多租户成本归属、高效装箱、自动扩缩容和容量预测等项目对于支持 Pinterest 高效和负责任的基础设施至关重要。编排有状态应用程序在技术上具有挑战性,对 Pinterest 的业务来说也很重要,虽然 PinPod 和 PinApp 为编排应用程序提供了坚实的基础,但我们正在积极与有状态系统的利益相关者合作,开发可复用的解决方案,以提高运营效率并降低维护成本。我们也认识到能够访问 Kubernetes API 的用例的重要性。随着 Kubernetes 及其社区的积极发展,遵循行业趋势并采用行业标准实践是一个很大的好处,因此我们正在积极与合作伙伴团队和供应商合作,使更多的 Pinterest 开发人员能够这样做。与此同时,我们正在努力回馈社区,因为我们相信广泛信任的社区是建立共享理解,贡献功能和改进,分享和吸收生产中的经验和学习的最佳平台,可以造福所有人。最后,我们正在评估利用托管服务进一步将基础设施管理工作移交给云供应商的机会。




你好,我是俞凡,在 Motorola 做过研发,现在在 Mavenir 做技术工作,对通信、网络、后端架构、云原生、DevOps、CICD、区块链、AI 等技术始终保持着浓厚的兴趣,平时喜欢阅读、思考,相信持续学习、终身成长,欢迎一起交流学习。为了方便大家以后能第一时间看到文章,请朋友们关注公众号"DeepNoMind",并设个星标吧,如果能一键三连(转发、点赞、在看),则能给我带来更多的支持和动力,激励我持续写下去,和大家共同成长进步!

发布于: 2023-12-03阅读数: 2
用户头像

俞凡

关注

公众号:DeepNoMind 2017-10-18 加入

俞凡,Mavenir Systems研发总监,关注高可用架构、高性能服务、5G、人工智能、区块链、DevOps、Agile等。公众号:DeepNoMind

评论

发布
暂无评论
[大厂实践] Pinterest通用计算平台实践_架构_俞凡_InfoQ写作社区