抖音动态体验优化实践与思考

一、背景与困境

过去几年,抖音的业务边界持续拓宽,从核心短视频延伸至直播、电商、本地生活等多元场景,用户规模与交互复杂度持续增长。设备端需同时承载高性能渲染、低延迟推流、多线程预加载等密集任务,内存峰值与并发任务数激增,传统资源调度机制难以为继,面临以下挑战:

picture.image

Android 动态性能框架(ADPF )为解决感知和调度问题提供了一种思路,其可提供从硬件层面反馈实时热信息、硬件负载等精细化数据,支持应用响应和调整。ADPF 虽提供精细化硬件信号,但原生能力适配游戏场景,难以满足抖音多资源维度综合调度需求,我们需要在抖音内部深度自定义一套属于抖音自己的框架才能突破调度难题。

在此背景上,基于抖音的动态性能框架 Douyin Dynamic Performance Framework(DDPF 应运而生 )。DDPF方向核心围绕动态性能框架建设,持续收敛和建设端上的所有时机信号和调节能力,将端上产生的业务、性能时机抽象成信号,将二三方动态能力整理和标准化,通过一种 DSL 语法在 A/B 平台上快速开展策略调节,过去一年取得了不少的进展和收益。接下来会从框架设计与演进、感知&决策能力的加强与应用、系统调度能力挖掘几个维度深度展开介绍。

二、DDPF框架设计与演进

1.1 演进链路

我们首先关注框架建设的演进链路,整体框架的演进过程分三个核心阶段,梳理如下:

picture.image

picture.image

1.2 框架结构

回到框架本身的结构上,在演进的过程中逐渐形成以下几个核心的概念:

picture.image

整体的框架逐渐演变成下图所示:

picture.image

1.3 核心链路

在这样的框架下,一个典型的动态调优的链路整体如下所示:

  1. 信号产生与分发: 当应用内发生特定事件时(如用户开始滑动 ),对应的场景(Scenario )会捕获该事件,并向全局的信号总线发送一个携带了事件参数的信号对象。

  2. 规则加载与信号订阅: 在应用启动阶段,信号的 Session 会从内部实验与配置平台拉取最新的 JSON 格式的治理规则。它解析这些规则,明确哪种信号对应着哪些过滤条件和哪些动作,然后向信号总线订阅这些它关心的信号。

  3. 多维度组合过滤: 当 Session 接收到其订阅的信号后,它会启动一个三层组合过滤程序:

  • 信号过滤器: 检查信号自身携带的参数是否满足预设条件。例如,规则可能要求只有当滑动速度(作为信号参数 )大于某一阈值时才继续。

  • 状态过滤器: 读取框架内维护的全局状态,判断当前应用或设备的状态是否符合要求。例如,规则可能要求仅在设备电量高于 50% 时才执行。

  • 规则过滤器: 此为最灵活的一层,它通过内置的表达式计算器执行一段动态下发的逻辑表达式。该表达式可以引用信号参数、全局状态、甚至可以获取服务器下发预测分

  1. 决策与动作提交: 只有当上述所有过滤器的条件全部满足时,决策结果才为“通过”。此时,会话会根据规则实例化一个或多个动作(Action )对象,并将其提交给核心调度器。如果任一条件不满足,则流程终止,不执行任何操作。

  2. 异步安全执行: 核心调度器接收到动作提交请求后,并不会立即在当前线程执行,而是将其放入一个统一的、低优先级的后台线程池中排队执行。这确保了性能治理逻辑本身不会阻塞主线程或关键业务线程,保证了框架的稳定性和安全性。

picture.image

picture.image

1.4 框架之外

经过 DDPF 框架从静态解耦到动态链路,再到千人千面的三阶段演进,我们在框架动态性上实现了从“代码硬编码”到“云端灵活配置”,再到“多维度条件精准过滤”的跨越。但正如阶段三演进暴露的局限性所言,具备极致动态性的框架并不是做好动态性能优化的全部,更多的是一个起点 ——框架为动态优化提供了标准化的信号传递、状态管理和动作执行的基础设施,但要让这些能力真正落地为用户可感知的体验提升,还需要长期在以下两个核心方向的能力建设上持续深耕,这也是后续实践展开的关键主线。

  • 感知能力和动态决策:让框架“看得准、判得明”

动态性能优化的前提是精准感知“何时需要优化、因何需要优化”。当前框架虽能通过信号总线捕获基础事件,但面对复杂业务场景(如用户低交互沉浸式观看、多任务并发资源冲突 )时,传统的离散信号难以准确刻画“用户意图-设备状态-业务负载”的动态关联关系。因此,我们需要构建更深度的感知能力:一方面通过场景模型(如低交互模式识别、内存负载分级 )将原始事件转化为业务语义明确的复合信号;另一方面引入端智能技术(如 GC 风险预测、端侧大模型深度诊断 ),让系统从“被动响应”转向“主动预判”,实现从“信号触发动作”到“数据驱动决策”的升级。

  • 可调度能力建设专项:让框架“调得动、控得稳”

动态优化的落地依赖可调度能力的建设专项,包括对底层资源的灵活调度能力。尽管DDPF定义了标准化的 Action 接口,但面对虚拟机(如 GC 参数调节、JIT 编译阈值 )、渲染引擎(如线程优先级调整 )、硬件层(如 CPU/GPU 调频 )等不同维度的调度需求,仍需挖掘和封装更细粒度的原子能力。

💡接下来,我们将围绕这两个核心方向展开具体实践:在“三、感知与决策”中,详细介绍复杂场景感知模型的构建方法、端智能如何驱动动态决策;在“四、虚拟机调节专项”中,深入拆解虚拟机层面可调度能力的挖掘过程与典型调节案例,最终呈现一套从“感知-决策-调度”到“验证-迭代”的完整动态性能优化闭环。

三、感知与决策

1. 复杂感知能力建设

1.1 低交互场景建设

以抖音业务场景为例,我们观察到用户使用习惯在短视频和中长视频场景完全不同,短视频伴随着频繁的滑动,而长视频一旦进入沉浸式观看,几乎没有交互。基于这个观察结论,中长视频观看完全可以抽象形成信号,并基于此对抖音性能策略进行调节,以优化沉浸式观看的效果。

低交互场景的识别核心依据是用户的停留时长交互频率 。场景系统通过规则模型随时间进行加分,对用户交互行为(如点击、滑动 )进行扣分。当评分达到累积到达阈值时,自动进入低交互模式;若交互行为频繁,到达退出阈值时则退出。

picture.image

进入该模式后,会通过对应 Scenario 发送信号,表明用户目前正处在低交互模式,通过预先下发的策略配置即可完成对应的策略优化。

低交互模式的应用

低交互模式的价值在于,提供了一个准确的闲时时机 ,闲时在App中起着不可或缺的作用,一系列预加载和清理型的优化都对 CPU、内存、IO 有着一定的要求。用户正常操作 App 时若触发,则会造成卡顿。低交互模式恰好提供了这样一种时机信号,供此类型策略发挥。

1.2 性能负载分级

上文提到,为了突破信号离散的局限,实时感知核心资源的负载,可以通过周期性采样、计算,并通过多个阈值对指标进行分级,产生二次加工后的分级指标,形成连续的负载分级信号,作为策略指导的上游。

以内存指标为例,内存作为连续值,其单次取值容易受到“尖峰”影响,并且对内存指标的持续监控也是众多性能策略依赖的上游信号,因此内存指标作为首要负载分级指标建设。

内存指标负载分级的优点

  • 轻量采集: 仅采集最核心的 JavaHeapNativeHeap 数据,相比传统方式开销更小。
  • EWMA 抗波动: 采用指数加权移动平均(EWMA ) 算法平滑瞬时内存波动,使水位判断结果更稳定、更趋势化。

picture.image

  • AB 阈值校正与多维下发: 分级阈值支持通过AB 实验 进行动态调整和按机型等多维度下发,便于精细化运营和规避特定设备上的 badcase。

  • 统一信号利于标准化调度: 将内存状态抽象为Low / Medium / High / Extreme 四个标准等级信号,供所有业务方统一感知和响应,推动了内存调度的标准化。

  • 策略快速迭代: 作为 DDPF(动态性能框架 )的标准输入信号,使得内存相关优化策略的验证、调参和迭代可以脱离版本发布 ,通过云端配置快速进行。

核心实现流程

  1. 数据采集: 轻量级采集JavaHeap (通过 Runtime API )和NativeHeap (通过 mallinfo )的核心数据。

  2. EWMA 平滑: 将采集到的离散数据点通过EWMA 算法 进行加权平均,生成一个平滑的、能反映内存使用趋势的水位值。

  3. 阈值比较: 将计算出的平滑水位值与云端下发的配置阈值 进行比较。

  4. 负载分级: 根据比较结果,将当前内存负载状态划分为Low / Medium / High / Extreme 四个等级之一。

  5. 状态同步与驱动: 将分级结果作为标准化的DDPF 信号 广播出去,下游已接入的各种动态调整策略(Action )根据此信号进行响应,执行相应的调度操作。

2. 端智能的应用

随着 DDPF 框架演进,我们构建了基于“信号-工厂-动作”的动态链路,实现了场景与策略的解耦。然而,当面临多场景、多参数、多状态交织的复杂决策时,单纯依赖静态规则配置(filter )的“动态化”设计遇到了新的瓶颈。

一方面,性能问题往往由多状态共同作用触发,使用静态 if-else 规则描述复杂关系,会导致配置急剧膨胀,难以维护。另一方面,框架缺乏对未来趋势的有效预测,基于静态规则下发预测结果,容量有限且难以应对快速变化的线上场景。

为突破上述瓶颈,我们引入了端智能技术。端智能恰好能弥补 DDPF 在多维数据处理与未来预测上的短板:

  • 低延迟决策:模型在端侧运行,能基于实时特征(如内存分配速率 )进行秒级预测,抢在性能问题发生前干预。

  • 隐私保护:用户敏感数据在本地完成特征提取到模型推理,无需上传云端,天然符合隐私合规要求。

  • 端云协同:端智能模型预测用户意图或风险,将高维、模糊的“未来”信息转化为 DDPF 可理解的确定性信号,实现精准的“就地决策”;云端则专注于模型训练与策略下发,形成高效配合。

因此,将端智能的预测能力与 DDPF 的动态执行能力相结合,是突破性能优化瓶颈、迈向“智能化”调度的必然选择。

2.1 打通端智能与 DDPF

为了将端智能的预测能力无缝对接到 DDPF 的决策框架中,我们设计了一套完整的端到端通道,在 DDPF 上的架构如下:

picture.image

基于线上配置,在应用程序满足触发条件时,触发端智能的模型预测。在转换层进行前置筛选,筛选通过后将端智能的预测结果,具体参数,转换为 DDPF 能够响应的信号输入或者直接的动作输入交给 DDPF 来响应和执行。

同时在 DDPF 中,也可以基于线上配置的信号,主动触发端智能特定模型的预测,结合 DDPF 本身的特定状态和数据,共同生效,达到更好的优化效果。

2.2 GC 多参数智能决策

为了更具体地理解端智能如何驱动性能决策,我们以一个典型的应用场景——GC(垃圾回收 )多参数智能决策——为例,拆解其完整的闭环流程。

在复杂的业务场景下(如高频信息流滑动 ),GC 的时机与参数对用户体验影响巨大。不当的 GC 策略可能导致应用卡顿甚至 ANR。通过端智能,我们可以从“被动响应”转变为“主动预测”,在 GC 阻塞发生前进行干预。

完整的决策与执行如下:

  1. 触发信号: 感知层监测到 GC 压力信号(如 Java 内存水位持续走高 ),并将其发送至智能层作为模型预测的触发器。同时,通过频控和防重入配置,避免短时重复预测。

  2. 端智能输出: 虚拟机打分模型结合上下文特征(如历史 GC 耗时、近期内存分配速率等 ),输出未来(如 8s 内 )发生 GC 卡顿风险的预测结果,包含定性的标签 (label)、可信的置信度 (confidence)以及包含建议参数的扩展输出 (extOut)。

  3. 条件过滤与表达式映射: 预测结果进入 DDPF 转换引擎。首先,通过 filter / eval 条件(如 label == '1' && confidence > 0.8 )判断是否响应;随后,利用表达式将模型输出值映射为优化动作的具体参数,例如,将预测分数值 value 转换为 [-20, 19] 范围内的线程优先级。

  4. 动作组装与执行: DDPF 的动作工厂将转换后的参数组装成一个或多个 Action,并在执行前进行合法性裁剪,确保参数在安全范围内。随后,调度中心执行这些 Action,如提升 GC 线程优先级或调整 GC 步长。

  5. 状态记录与闭环反馈: 动作执行后,记录当前调整状态作为后续预测的特征,并派生新信号用于日志上报。同时,性能监控组件回采干预后的效果数据(如实际 GC 耗时 ),作为奖励(Reward )信号,与当时的预测输入共同构成新的训练样本,用于模型的持续迭代。

picture.image

2.3 端侧大模型

传统端智能模型是为特定任务训练的专用小模型,而端侧大模型具备更强的上下文理解与多维特征推理能力,在处理非结构化、长周期的复杂性能问题时价值独特。

例如当应用持续处于高 CPU、高内存且伴随连续卡顿的恶劣状态时,简单触发单个优化动作收效甚微。此时,可调用端侧大模型,并将一段时间的性能快照序列、用户操作日志等信息作为上下文输入。大模型通过综合分析应用程序的各种不规则数据,识别性能恶化的可能根源,如“用户在直播间高频滑动评论,同时后台在进行视频预下载,导致 CPU 竞争与内存压力”。大模型基于对问题的理解,生成临时的、多步骤的组合优化策略,如输出结构化的 JSON 指令来顺序执行暂停预取、设置渲染线程优先级、调整 GC 类型等操作。并且在输出决策的同时附带自然语言解释,帮助研发人员理解决策依据。

尽管前景广阔,但将端侧大模型应用于实时性能决策仍面临工程挑战。在与厂商的合作探索中,我们明确了几个关键边界:

  • 输出格式的稳定性: 性能框架要求模型输出严格的结构化数据(如 JSON ),但当前端侧大模型直接输出合规 JSON 仍存在挑战,常出现格式错误,需要通过提示工程、工具调用微调或增强输出校验来优化。

  • 推理时延: 端侧大模型的推理时延(数百毫秒甚至数秒 )远高于专用小模型,决定了它更适用于应对持续性状态恶化的准实时场景,而非瞬时高优先级响应。

  • 上下文长度与成本: 端侧大模型受限于设备内存和算力,可接受的上下文长度有限。如何在有限的 Token 预算内高效压缩和传递关键信息,是决定决策质量的核心。

  • 模型能力与部署: 厂商提供的模型能力、部署方式、资源占用及接口友好度,都直接影响接入的可行性与成本。

因此,当前阶段我们将其定位为对未来专用模型体系的补充,待其端侧模型工程稳定性提高后,再继续实验“小模型快速响应 + 大模型深度诊断”的模式,以构建更智能的性能优化体系。

四、虚拟机调节专项

💡下文将围绕可调度能力建设专项,以虚拟机调节专项为典型案例深入展开,整体开展的思路如下

  • 数据体系: 通过埋点建设、数据分析,精细化和体系化的提升对虚拟机特定模块的认知

  • 调节能力: 持续收敛现有的调节能力并且建设新的动态调节接口,建立虚拟机的动态调节体系

  • 策略挖掘: 在1、2的基础上结合 DDPF 框架能力持续挖掘适用于精细化(宿主、场景、时机 )的策略

1. 调节能力挖掘

1.1 数据埋点建设

我们首要任务便是针对虚拟机的几个核心技术模块,建立完善的数据体系,整体的盘点如下。注:这里每个技术模块的埋点建设均可以展开,这里便不一一介绍。

picture.image

💡有了上面的埋点和基于埋点的数据分析,下文继续从技术盘点的角度进一步梳理虚拟机内

  • 内存管理和 GC
  • 代码执行和编译

两个具有代表性方向的技术细节,探索和建设这两个核心技术模块中的可调节能力

1.2 内存管理和 GC

我们通过上述的埋点建设发现:针对的GC的任何一个细小的调节都有可能影响到用户的使用体验,放到大盘用户中,就有可能产生显著的性能差异。

一个简化的 GC 流程图如下所示:

picture.image

我们可以将 GC 的发生总体分为前、中、后三个阶段,每个阶段都可以动态的调节系列的设定,可调节方向盘点梳理见表格最右一列,整体如下:

picture.image

1.3 代码执行和编译

另外一个核心方向,就是虚拟机整体负责的 Java/Kotlin 的代码执行、热点方法识别、编译优化等链路。

picture.image

围绕着 JIT(Just-in-Time编译器 )的设定和组成,总体有以下方向可以进行调节建设:

picture.image

除了运行时编译,ProfileSaver 写入的 Profile 文件,整体也会影响系统执行的 AOT(ahead of time )的运行情况来影响抖音的性能表现,整体流程如下:

picture.image

围绕着 Profile 文件生成有以下方向可以进行调节建设:

ProfileSaver

|

含义

|

可应用方向

| |

AddMethod过滤

|

ProfileSaver写入profile文件的原子方法

|

控制profile写入的数量和质量

| |

Profile转译

|

将profile转译成可识别的代码symbol

|

热点方法的记录和diff

| |

ProfileSaver Options

|

ProfileSaver写入的时机、频次

|

控制ProfileSaver的写入行为

|

2. 动态调节案例

在 DDPF 框架、数据埋点分析、可调节能力建设的基础上我们逐渐产出了一些整体具有大盘性能优化收益的策略和案例,一部分整理如下:

picture.image

五、总结和畅想

当然除了感知与决策能力的深化和可调度能力的持续建设之外,还有以下两个方向需要核心关注

  • 动态诊断: DDPF 挂载的调节能力可以是优化能力,当然也可以是诊断能力,无论是线上 Trace 抓取还是深度的内存镜像还原,目前这样的诊断能力均已完成与DDPF的对接,后续精细化的动态业务诊断和问题消费同样是重点发展的方向。
  • 数据挖掘: 持续的能力建设,我们逐渐收敛数百种时机、信号和状态,上百种调节能力,理论上可以延伸出无数种策略组合,如何在这些组合中找到最具价值的策略,也是后续数据分析和智能调度需要考虑的课题。

整体逐渐演变成如下的框架,未来,我们希望 DDPF 能形成“感知更精准、决策更智能、调度更灵活”的完整体系,不仅支撑抖音多元场景下的性能优化,也能为行业动态性能治理提供可复用的技术范式。

picture.image

0
0
0
0
评论
未登录
暂无评论