XFaaS 是 Meta 为内部使用而开发的函数即服务(FaaS)系统,它与像 AWS Lambda、Google Cloud Functions 和 Azure Functions 这样的 FaaS 平台有很多相似之处。
我很幸运提前看到了他们关于这个主题的论文。
计算机科学家在命名上似乎并没有太大创意,因为今年有两篇介绍 XFaaS 的论文。一篇是 Meta 的,另一篇是由 IISC Bangalore 的科学家所写。
这两套系统截然不同。因此,当你在 Google 上搜索 “XFaaS” 时,就知道这篇论文是描述 Meta 的系统版本。
在这篇文章里,我首先给出了一些高屋建瓴的总结和启示,适合那些想要快速了解的读者。
接着,我会更详细地解读论文,帮助那些想要理解 XFaaS 背后架构的读者。
#01
Meta 发现,尽管某些功能的调用具有很大的波动性,但仍存在一定的规律。公司利用这些规律来使得功能的调用在工作负载上更为稳定。
XFaaS 的效率如何?
XFaaS 的日均 CPU 利用率达到了 66%,这明显高于行业的平均水平。
通过在时间上延迟功能和在空间上选择负载较低的数据中心,它高效地分散了负载。
Meta 正在逐步将更多功能转移到非高峰时段执行,使负载和成本更为稳定。
由于它是内部云服务,Meta 可以进行很多独特的优化,例如在同一个进程中为不同的用户运行多个功能。
大多数功能执行时间都不到一秒,但也有例外。
XFaaS 解决了哪些问题?
问题 1:冷启动时间过长。
如果容器过早关闭,下次调用需要重新初始化整个容器;而如果过晚关闭,则会空闲浪费资源。
解决方案:XFaaS 采用即时编译等技术,确保每个工作器都能即刻执行任何功能。
问题 2:负载的高差异性。
这会导致由于过度配置造成过多的硬件成本,或者在配置不足时导致系统速度下降。
解决方案:XFaaS 将容忍延迟的功能推迟到非高峰时段运行,并在全球的数据中心分散函数调用。
问题 3:下游服务的过度负载。
例子:曾有一次,非面向用户功能的大量调用导致面向用户的在线服务出现故障。
解决方案:XFaaS 采用与 TCP 拥塞控制类似的机制来调整功能的执行。
与公有云 FaaS 的对比
其他 FaaS 平台首先考虑降低延迟,而 XFaaS 重视硬件利用率和功能调用的吞吐量。
XFaaS 为公有云带来的可能优势:
允许功能所有者为完成时间设定服务级别目标(低优先级的可以选择在更合适的时间延迟执行)。
允许功能所有者为功能设置重要性级别。
尽管公有云可能不会像 XFaaS 那样在同一进程中为不同用户执行功能,但大型云客户可以在其私有云中采纳 XFaaS 方法。少数几个 Meta 团队已占据了 XFaaS 的大部分容量,公有云中的大客户也可能从 XFaaS 的方法中受益。
#02
这是对 XFaaS 详细概览的开始。
正如之前提到的,XFaaS 处理的负载有很大的波动性。在高峰时段,一个功能可能会在一分钟内接收到 130 万次的调用。
基础设定
最关键的一点是,XFaaS 的大多数功能是由自动化流程触发的,这些流程对于延迟是可以接受的。这样,XFaaS 就可以通过时间(通过延迟功能的执行)和空间(将任务发送到负载较低的数据中心)来平衡负载。
XFaaS 支持多种运行时环境,包括 PHP、Python、Erlang、Haskell,以及为各种语言设计的基于容器的通用运行时环境。
开发者可以为函数设置多个属性,如函数名称、参数、运行时、关键性、执行开始时间、完成时间限制、资源配额、并发限制和重试策略。执行完成的期限可以从几秒到 24 小时。
最后,由于 XFaaS 在不同的区域有不同的硬件容量,因此在进行负载均衡时必须考虑这一点。
工作负载类型
Meta 在 XFaaS 上有三种工作负载:由队列触发的函数、由数据变更事件(在数据仓库和数据流系统中)触发的事件函数,以及定时函数(根据预设的时间自动触发)。
XFaaS 主要用于不直接面向用户的功能,例如异步推荐系统、日志、效率提升机器人、通知等。
#03
当客户端想要发起函数调用时,它们首先会发送请求到 “提交器”(submitter)。提交器会首先应用速率限制,然后将请求传递给 QueueLB(队列负载均衡器)。
QueueLB 的任务是将这些函数调用指引到 DurableQ 中,以存储直至它们完成。
随后,调度器周期性地从 DurableQ 中取出这些调用,将其移至其 FuncBuffer(内存中的函数缓冲器),并根据它们的紧迫性、截止日期和配额对它们进行排序。
那些准备执行的调用会被移动到 RunQ 中,而 WorkerLB(工作负载均衡器)则会将它们分配给合适的工作节点。
这些组件,如提交器、QueueLB、调度器以及 WorkerLB,都是无状态的、无分片的,同时也是复制的,且它们没有指定的领导者,这意味着它们的每一个复制都有相同的功能。
DurableQ 则是有状态的,并且具有一个分片的、高可用性的数据库。
增加更多的复制可以轻松地扩展一个无状态的组件。如果一个无状态的组件出现故障,其工作可以轻松地被其他同级组件接管。
中央控制器与容错
中央控制器与函数的执行路径是分离的。它们持续地对系统进行优化,更新关键配置参数,这些参数被像工作节点和调度器这样的关键路径组件所使用。
这些配置信息是被缓存在各组件内的,所以即使中央控制器出现故障,系统也能够正常运行(但是它就不能再被重新配置了)。
这意味着,中央控制器可以停机长达几十分钟。这展示了 Meta 如何为该系统增加弹性。
数据隔离
那些出于安全或性能原因需要强烈隔离的函数,会被分配到不同的命名空间。每一个命名空间使用独立的工作池来达到物理隔离。
多个函数可以在同一个 Linux 进程中运行,这得益于私有云内的信任机制、强制的代码审查以及其他的安全措施。数据只能从低级分类流向高级分类。
提交器(Submitter)
客户端向提交器发送函数调用请求。为了提高效率,提交器通过批处理这些调用并将它们统一写入 DurableQ。
提交器通过分布式键值存储来管理大量的参数,并内置了速率限制策略。由于客户端提交速率的差异,各区域设置了两组提交器:一组面向常规客户,另一组面向高频客户。
XFaaS 对高频客户进行了积极监控,并在进行节流或服务水平目标(SLO)调整时需要人为干预。
队列负载均衡器(QueueLB)与 DurableQ
函数调用从提交器传输到 QueueLB。Configerator(中央配置管理系统控制器)为 QueueLB 提供路由策略,以在各区域之间平衡负载,因为不同区域的 DurableQ 硬件容量不同。
DurableQ 使用 UUID 来分片函数调用,确保均匀分配。DurableQ 根据调用者设置的执行时间将函数调用进行分类和存储。
调度器持续从 DurableQ 中查询即将到期的函数调用。一旦函数调用被 DurableQ 交给调度器,除非执行失败,否则它会独占该调度器。
调度器与 DurableQ 之间的交互如下:
对于执行失败的尝试,调度器发送 NACK。这样,该函数调用会重新在 DurableQ 中变得可用,等待另一调度器进行处理。
调度器
调度器的核心任务是基于它们的重要性、截止时间以及配额来对函数调用进行排序。
它从 DurableQ 中提取函数调用,然后将它们整合到 FuncBuffers 中(首先按重要性排序,然后按执行截止时间),随后再将它们排入 RunQ 以待执行。FuncBuffers 和 RunQ 都是内存中的数据结构。
为了管理高效的执行并避免系统滞后,RunQ 控制函数调用的流向。系统还确保了负载均衡,通过全球流量导向器(中央控制器)根据需求和能力跨地区指导函数调用流量,确保了整体的工作负载平衡。
WorkerLB 和 Worker
调度器的 RunQ 会将函数传递给 WorkerLB,它随后再由工作器池中的工作器运行。
在 XFaaS 系统中,使用同一种编程语言的函数会被隔离,并且具有专用的运行时及工作器池。
该系统的设计意图是确保任何工作器都能立即执行函数,无需任何启动延迟。XFaaS 始终保持一个活跃的运行时环境,并确保工作器的本地 SSD 上的函数代码始终是最新的。
合作的即时编译(JIT)以降低开销
XFaaS 引入了合作式即时编译,周期性地将函数代码打包并传送给工作器。由于代码经常更新,因此这一步骤是必要的。
JIT 编译包含三个执行阶段:
在接受函数调用前完成即时编译,从而避免了延迟。
使用合作的即时编译,一个工作器在函数代码更新后的 3 分钟内达到其最大请求率,而如果没有使用 JIT 编译,则需要 21 分钟。
局部组以实现高效的内存使用
由于内存限制,存储每个函数的 JIT 代码是不现实的。
局部优化器(中央控制器)将函数和工作器分组,以确保内存密集型的函数得到合理分配。
通过使用局部组,内存使用率降低了 11-12%,这也使工作器能够更加高效且稳定地利用内存。
如何有效地处理 XFaaS 的负载峰值
函数配额:每个函数都有一个配额,该配额由其所有者确定,并定义了其每秒的 CPU 循环。此配额进一步被转化为每秒请求(RPS)的限制。中央速率限制器基于函数的 RPS 上限来判断是否进行节流。
时间位移计算:XFaaS 提供了预留的(用于立即执行)和机会性的配额(在 24 小时内的低需求时段执行)。利用控制器根据工作负载使用情况动态地调整函数调用速率。
函数的动态 RPS 限制:为了不给下游服务带来过大负担,XFaaS 采用了类似 TCP 的 AIMD(加性增加,乘性减少)策略来动态地调整 RPS 上限。它可以调整并发水平,并采用渐进启动方法来管理 RPS 的变化。
以前,如一个 XFaaS 函数过载了 TAO 数据库,导致了一系列的服务失败,这突显了这种防护措施的必要性。现在,正如实际事件中所见,当其背压机制预先遏制了潜在的过载时,XFaaS 成功地保护了下游服务,确保了服务的稳定。
#04
这是一篇卓越的论文。Meta 为我们深入展示了他们的无服务器平台,同时为开发者和希望优化自己无服务器功能使用的公司提供了宝贵的经验。
论文链接:
https://dl.acm.org/doi/abs/10.1145/3600006.3613155
另外,如高效的 CPU 使用这样的硬件优化在业界并没有得到足够的重视。虽然像 Google、Facebook 这样的公司在他们自己的系统上这样做,但与软件优化相比,这并不是一个常被提及的话题。
同时,如果你对其他实际应用的分布式系统感兴趣,我还写了一篇关于 Meta 如何通过建立世界上最大的 Memcached 系统来处理每秒数十亿次的请求。
文章链接:
https://engineercodex.substack.com/p/how-facebook-scaled-memcached
以上内容包含广告