用户登录

技术文章

外部链接将在新标签页打开。

F3 Lightning 拆解:把特征发布从共享执行里拆出来,Meta 如何让 ML 特征更快上线

一句话回答

F3 把全部特征编译成一张合并图,靠共享计算降低执行成本,但合并图同时是发布单元,一个错误定义会阻塞整条发布流水线。F3 Lightning 把发布边界与执行边界分开:每个特征独立编译、验证、发布和回滚;再用内容派生的稳定标识符、启动时构建的单一执行计划、共享内存缓冲与稠密索引映射找回共享计算带来的效率。Meta 称可比特征上线速度约为原 F3 的 3.6 倍且基础设施计算成本未增加,但材料未给出测量方法、环境与统计窗口,具体口径待核实。

核心要点 TL;DR
  • F3 的高效来自合并图去重共享计算;代价是合并图即发布单元,单个坏定义阻塞全部特征。
  • F3 Lightning 的关键不是“拆”,而是拆完还能共享:编译器按操作、参数和输入标识符派生稳定 ID,运行时据此去
  • 启动时构建单一执行计划并扁平化为有序列表,请求期只做一次正向遍历;失败只把下游标记为未就绪。
  • 倍是 Meta 自述的汇总结果,比较对象是原 F3 的可比特征,测量细节在本次材料中未提供。

F3 Lightning 要解决的问题可以一句话说清:在 Meta 的广告排序特征体系里,把“一个特征能不能上线”和“所有特征怎么一起算”这两件事分开。原来二者被同一张合并图绑死,现在发布按特征走,执行仍在启动时统一编排。代价是必须用一套新机制把共享计算重新找回来,否则 CPU 会明显上升——这正是材料里着墨最多的部分。

需要先说明材料边界:以下内容基于 Meta 工程博客 2026 年 11 月 3 日的文章及其提供的片段(Engineering at Meta)。抓取内容在“共享内存缓冲”一节处被截断,因此步骤 3 的实现细节与步骤 4 的稠密索引映射只能按文中概述交代,不补写推测。文中性能数字为 Meta 自述,未见测量方法与统计窗口,按待核实处理。

先看 F3 原本为什么快,又为什么卡#

Facebook Feature Framework(F3)是 Meta 用来编写、编译和服务广告排序模型底层特征的框架。材料给出的规模量级是:单次请求可能需要 20,000 个以上特征;F3 最早在 AI @ Scale 2020 上公开,当时只服务几百个特征。

它的核心设计是把特征抽取表达成有向无环图(DAG):节点做一件小事,比如读一个输入、套一个时间窗过滤、做一次聚合;边表示依赖;图的输出就是模型消费的特征值。工程师用高层语言各自写特征,编译器先把每个定义变成一张小图,再把某个服务用到的所有特征图合并成一张大图,重复的操作折叠成一个节点,每个请求只跑一次。

共享是真实的收益:一个“7 天点击计数”和“7 天曝光计数”可能读同一份事件源、套同一个时间窗过滤,点击率特征还会复用这两者的结果。如果每个特征独立执行,这些过滤会在每次请求里被重复做很多遍。

但合并图同时也是发布单元。材料用一个七特征(A 到 G)的例子说明后果:D 和 G 各自有无关的错误,第一次构建卡在 D,七个特征一个都发不出去;修好 D 后第二次构建卡在 G;直到第三次两个定义都改对,整张合并图才上线。随着特征数量涨到两万以上,这种阻塞被放大:不同特征类型有各自的校验要求,已被模型消费的特征还要跑与模型相关的测试,这类测试计算代价高,只能放在发布流程的较后阶段,而由于合并图整体发布,其它特征也得一起等。

两个改动:发布粒度和执行效率#

材料把 F3 Lightning 的设计归纳为两点,缺一不可:

  • 发布粒度:每个特征是一份可独立发布的配置,独立验证、独立上线、独立回滚,互不影响。
  • 效率对齐:合并图没了,共享计算的来源也就没了,必须用别的方式补回来。

隔离从编译器开始:每个特征单独编译成一份配置,这份配置自带它需要的全部节点,按顺序排列,不从邻居那里借任何东西。所以特征 C 出问题,特征 A 照样发布,因为两份配置之间没有关系。

发布路径也随之从“一批全发或全不发”变成按优先级排序的队列,排序依据是这次改动能解锁什么、风险多大。尚未被任何模型消费的新特征,走标准校验后可以较快上线;改动一个线上模型已经在读的特征,则要先过额外测试。这是工程上很实际的一条:发布速度不是一个统一数字,而是按风险分层的。

把共享计算找回来:四步里的前三步#

早期只拆发布、不共享执行的原型,CPU 明显高于原 F3——每份独立配置各自成图、各自执行,把合并图消掉的读取、过滤、聚合又重复做了一遍。材料给出的补救是四项优化:稳定计算标识符、单一执行计划、跨特征共享内存缓冲、稠密索引映射。前三项有较具体的描述。

步骤 1:标识符由“做什么”决定,而不是“排在第几”

要在运行时去重,先得能认出两个独立编译的配置里存在同一份计算。节点编号做不到:编号是每张特征图内部的局部编号,同一个 7 天过滤在一份配置里是节点 2,在另一份里可能是节点 7,而且插入一个节点会让它后面的编号全部平移。原 F3 不存在这个问题,因为一次编译就能看到所有特征,可以全局分配编号。

F3 Lightning 的做法是让编译器从计算本身派生标识符:操作、参数,以及各输入的标识符。由于输入的标识符已经包含了它上游的全部信息,这个标识符就覆盖了产出该结果的整条计算链。对结果无影响的输入顺序会被归一化;聚合类计算还会把时间窗、分组键这类定义行为的属性纳入。于是,即便两个特征相隔数周编译和发布,只要它们对相同输入定义了相同操作,就得到相同标识符;而一旦计算含义变了,标识符随之改变。

把这段逻辑写成伪代码大致如下(示意,未执行,仅用于说明派生顺序,不代表 Meta 的实现细节):

def ident(node):
    op = node.operation            # 例如 "filter_time_window"、"count"
    params = canonical(node.params) # 参数归一化,如时间窗 7d
    deps = [ident(d) for d in node.deps]
    deps = canonical_order(deps)    # 顺序无关的输入先排序
    return digest(op, params, deps) # 占位函数名,实际算法未公开

步骤 2:启动时建一张计划,再压成一条直线

服务启动时,F3 Lightning 不重建合并图,而是取当前所有活跃特征配置,用拓扑排序把每个节点排在其依赖之后,形成一份跨全部特征的执行计划。当多个特征包含同一标识符的节点时,计划只保留一份并把所有消费者接上去,于是这份计算无论被多少特征使用都只执行一次。

但计划本身仍是图,请求期逐指针遍历也有开销。所以同一次启动过程还会把它扁平化为有序列表,每个请求只需沿列表做一次正向遍历,不必走图。

共享计划带来新风险:一份计算失败可能波及所有特征。这里的处理是把故障范围限制在依赖关系内——某份计算失败或其输入不可用,就把它的全部下游标记为“未就绪”并跳过,独立分支继续执行。这个思路对做特征服务的人应该不陌生:失败隔离的边界应当是数据依赖边界,而不是业务模块边界。

步骤 3 与步骤 4:内存与索引

完成前两步后,已经没有计算被执行两次,但 CPU 仍高于原 F3,剩余成本来自内存相关环节——材料在此处被截断,具体机制未在本次可见内容中展开。第四项优化在开头的概述中被列为“稠密索引映射,用于直接数组访问”,同样只有概述、没有实现细节。可以确认的是这两项与标识符、执行计划同属“效率对齐”的一部分,具体做法待补充材料核实。

把 F3 与 F3 Lightning 放在一起看#

维度F3F3 Lightning
发布单元整张合并图单个特征配置
单个定义出错阻塞全部特征上线仅该特征不发布,其它照常
共享计算来源编译期合并去重启动期按稳定标识符去重,并压成有序列表
回滚范围整图单特征
发布节奏一批按影响与风险的优先级队列

关于收益,材料称采用 F3 Lightning 后,可比的特征抽取上线速度约为原 F3 的 3.6 倍,且基础设施计算成本没有增加,更短的发布周期也让同期内可以多做几轮模型迭代。这里的限定词很重要:比较对象是“可比特征抽取”、基线是“原 F3”、成本口径是“基础设施计算成本”。材料未提供测量环境、样本量、统计窗口和“上线速度”的起止定义,这些数字应视为厂商自述的汇总结论,复现性待核实。

对自建特征平台的读者,哪些做法可以借鉴#

  1. 把发布边界与执行边界当成两个独立决定。 常见误区是“为了共享计算必须一起发布”,F3 Lightning 说明这两件事可以拆开,代价是需要在执行侧补一套去重机制。
  2. 用内容派生的标识符替代位置编号。 只要计算语义不变,跨编译批次、跨发布时间的同一份工作就能被识别;语义变了标识符自然失效,缓存和去重的正确性都由它兜住。
  3. 把编排成本挪到启动期。 拓扑排序、去重、扁平化都在服务启动时做一次,请求路径上只剩一次正向遍历,这是典型的用启动时间换请求期开销。
  4. 发布队列按“解锁了什么”排序。 未上线的特征走轻量校验,线上模型在用的特征走重校验,比给所有特征设同一道门槛更符合实际风险分布。
  5. 先验证拆分是否真的没变贵。 材料明确记录了早期原型 CPU 上升,说明拆分本身会带来效率回退,需要先建立基线再判断是否达标。

读完仍待确认的部分#

三处不确定性值得保留:其一,3.6 倍与“成本未增加”缺测量细节,不宜直接当作自己系统的预期收益;其二,共享内存缓冲与稠密索引映射的实现方式在本次可见材料中未展开,涉及内存占用与请求并发的取舍无法评估;其三,材料提到不同特征类型有各自校验、模型相关测试成本高,但没有给出测试时长或流水线阶段划分,无法判断瓶颈是否真的被消除,还是只是不再互相阻塞。这些问题需要原文完整版本或后续技术分享来补齐。

常见问题(FAQ)

F3 Lightning 是替换 F3 吗?
不是。材料把它描述为构建在 F3 之上的一层基础设施,用来解耦特征发布与共享执行;特征的编写与编译仍沿用 F3 的高层语言与图模型。
拆成独立发布后,为什么 CPU 没有按预期上升?
早期只拆发布的原型确实 CPU 显著升高,因为每个配置各自成图、重复执行读取、过滤与聚合。后续靠稳定标识符、单一执行计划、共享内存缓冲和稠密索引映射把共享计算找回来,材料称达到与 F3 持平。

参考来源

  1. F3 Lightning: How Meta Accelerates Ads ML Features to Production at Scale

以上为本文写作时的参考资料,引用观点以原文为准。

作者:沐小悠

本文约 10 分钟读完 · 关键词:F3 Lightning、Meta F3、特征工程、ML 特征服务、DAG 编译

更多文章 GET 示例接口