2016年9月26日,Tik Tok 1 . 0 . 0版本上线。截至目前,Tik Tok日活跃用户已经超过6亿。短短六年,Tik Tok从无到有,实现了爆发式增长。在业务快速发展、数据海量增长、视频/直播对画质要求更高的背景下, Tik Tok基础技术团队如何以技术创新应对时代变迁,以匠人之心优化用户体验?在不被外界“看好”的iOS开发领域,Tik Tok团队交出了一份怎样的答卷?
1月22日下午,第三届字节跳动技术沙龙在线直播与观众见面。本次沙龙以“Tik Tok iOS基础技术的秘密”为主题,邀请了陈、陈、舒标、韩、朱峰五位iOS客户端工程师,从不同角度讲解亿元App Tik Tok在iOS客户端开发中的实践经验,为近4万在线观众带来了一场根植实践、面向前沿的技术盛宴。
陈显财《大型 App 开发架构演进及挑战》架构的质量决定了项目的规模和效率。Tik Tok基础技术iOS客户端架构师陈先生介绍了团队如何在不影响业务迭代和业务规模扩张的情况下,持续推动架构从模块化、组件化向插件化演进。
模块化面对开发初期代码量的扩大、业务规模的扩大、开发人员的增加和正常业务迭代之间的矛盾,技术团队首先从
提高效率的角度考虑将依赖工程、环境配置和App资源从主项目中分离出来,设计底层代码的基本依赖能力,形成一个外壳项目。团队还从源环境资源工具的角度设计了一个相对统一的模板,这样就可以基于统一的标准来创建和开发模块。
在R&D流程和工具方面,该团队支持开发
多仓库MR,并为本地R&D和CI/CD构建了一个基本的R&D环境。此外,团队根据模块标准将整个项目模块化,并确保大多数模块可以编译成二进制目标。模块化的实现不仅提高了效率,也为后续架构的不断演进奠定了基础。
随着业务的不断发展,单个业务模块中的代码也在迅速膨胀。模块化拆分后,不合理的接口依赖需要进一步分析和治理;iOS新增加的扩展和基础能力,使得Swift难免鱼龙混杂...在这种背景下,技术人员已经开始了组件化过程,
降低了团队的整体R&D能效。为了解决代码重用问题并降低依赖复杂性,团队重新定义了Tik Tok的五级架构层次:
这种架构分层将模块化带来的
网状依赖结构转化为树形依赖结构,降低了依赖复杂度,保证了层间的依赖不变质。
针对数百个组件的依赖管理,技术团队突破了常规方法“依赖调平”的局限,用
容器化方案进行了改进。容器的一个版本包括外壳工程、依赖性列表、依赖性改变记录、整体构造历史和产品发布集合信息。针对缺失或断开的依赖链,在mr子仓库中用差集的方法检查缺失依赖的问题,防止工程依赖的恶化。同时,基于新的层次架构,技术人员定义了每一层组件的依赖规范,以防止不合理的循环依赖,并确保整体依赖不会恶化。在
层次依赖规范中,上层可以依赖下层,实现可以依赖接口,接口层没有依赖,前向声明优先。最后,经过几个版本Tik Tok的迭代优化,各个组件的依赖性明显下降。
二值化带来的另一个问题是
界面层的变化。为了处理接口冲突导致的二进制污染,技术人员结合骨干的语法树信息,通过mr直接查看真实调用量,每天拦截二进制污染的问题在10%左右,有效保证了团队整体发展的稳定性。
为了应对配置问题、环境问题、异步mr接口调用和冲突对主干稳定性的影响,技术人员引入
RC(Release Candidate)分支合并多个mr代码,代码经过检查后进入稳定性主干,避免了本地编译失败和CI解包失败的问题。稳定化问题解决后,新增的业务仓库不断拆分成仓库,也成为影响开发效率的问题。技术人员已经介绍了
单仓库多组件——可以在一个基于分层架构的仓库中添加多个组件,而无需拆卸仓库。同时Swift和OC代码在接口层隔离,避免组件间的编译依赖传递。
为了提高整体R&D能效,团队还提供了一套基于二进制
的代码隔离方案,通过绑定适配器协议,获取适配器协议,将业务差异化的代码通过适配器隔离成二进制。同时,构建相关的基础设施来监控代码变化,以便感知和量化多个app的影响。
在组件化演进的过程中,Tik Tok的业务规模不断扩大,组件数量从最初的100+增加到800+,二进制化已经无法满足提高效率的需求。同时,团队在
效率、质量和成本方面面临新的挑战。在这种背景下,
为了提高在线性能和本地效率,技术人员开始了静态二进制向动态二进制转化的过程。在业务懒加载场景中,技术人员直接将非首页业务代码及其专属的基础库依赖变成动态库进行懒加载;此外,特殊代码通过动态库隔离,在iPad定制业务、大型商业街区改造等特定场景中发挥作用。
为了降低底层依赖复杂度,提高代码质量,团队还设计了
服务框架,支持抽象接口与具体实现的绑定,以及实现的急切性。该框架极大地满足了解耦、动态部署、服务组合、在编译时消除底层语言差异以及在运行时支持服务热情的能力需求。此外,技术人员在本土多模式研发方面也进行了积极探索。
陈文欢《抖音 iOS 自动化服务:容器化和规模化探索》自动化测试和持续集成对于保证软件工程的质量具有重要价值,也是保证大型项目增量开发的手段之一。来自的基础技术iOS客户端工程师陈先生介绍了iOS自动化如何实现容器化和大规模服务,以及涉及的一些技术挑战和解决方案。
iOS 容器化测试容器化测试一方面是为了提高测试的稳定性,另一方面也可以隔离不同测试任务之间的环境影响。在Tik Tok iOS集装箱化结构的
服务分层架构中,最低机架平台提供抽象的机器管理和控制功能。基于此,技术人员构建了包括单元测试、UI测试等在内的专门测试服务。平台端还提供数据报表消费和部分业务管理能力。同时,技术人员还根据公司的组件化状况和不同的CI系统访问R&D环境和CI工具链。整个架构的运行使得公司的很多项目组件都可以使用一些通用的测试服务,已经应用到 Tik Tok、直播中心、等大型项目中。
在机架平台
的服务隔离方案中,技术人员采用了Linux集群下的Docker方案(下图的左侧),Docker镜像包含了一些测试用例和工具链。通过这种方案,机架环境可以彼此独立地运行,并支持快速部署和管理的能力。下图右侧是iOS设备上技术人员使用的核心服务,最上层是字节工程师开发的iOS后台runner进程,用于接受设备控制指令,与iOS底层服务进行通信。此外,还包括安装代理、调试服务器等流程。Docker镜像与iOS设备的交互通过USB协议与lockdownd服务进行通信。
设备控制离不开UI交互。常见的点击操作、滑动手势、弹出控制、键盘输入、前台唤醒等。都是自动化测试中需要用到的基本能力。基于XCTest系统库,将测试代码集成到一个专门的App(称为UI runner)中,然后安装在测试设备上开始执行。陈老师以
XCTest的模拟点击home键的API为切入点,详细分析了iOS设备的控制机制。
分析xpc消息完整的协议交互过程,一般可以发现它使用了两组协议,其中一组是以xct
开头的 XCTest协议,其作用是直接调用testmanagerd的UI交互能力;另一组是IDE 开头的,是Xcode工具链白名单授权的过程。
在
字节自研iOS设备控制链方案中,启动一个App,通过its _IDE_authorize协议对App进程进行授权,并将其PID加入TestManager接口使用白名单,这样App就可以通过跨进程调用直接使用TestManager中与设备控制相关的所有接口。M1 模拟器规模化测试2020年11月,苹果发布了自己的M1芯片,可以在M1芯片上运行iOS程序。在此背景下,Tik Tok团队开始探索在M1设备上进行测试,以便
降低建造成本,并为提高测试稳定性提供新的可能性。如果直接在M1运行实包测试,会面临一些限制,比如App运行签名验证,同一个bundleld只能运行一个App,没有home键,固定屏幕大小,固定型号和版本等。这些问题将制约台架的规模试验。因此,
在M1模拟器上运行实包测试成为了技术团队努力探索的方向。
面对模拟器启动导致的
二进制与错误平台错误,经过验证,技术人员采用了类似于IPAPatch的处理方法,在编译产品生成后增加后处理过程,增加macho修改,注入/修改LC_BUILD_VERSION字段进行兼容,最终使Tik Tok真机包在M1模拟器上顺利运行。此外,陈老师还以
金属框架适配为例,介绍了系统库适配的处理思路和解决方案。舒彪《超级 App 构建效能提升 40%!JOJO,字节自研 iOS 构建系统》JoJo是以bazel为核心的字节自研iOS构建系统,提供从CI/CD到本地构建开发的一整套解决方案。Tik Tok基础技术iOS开发工程师舒彪先生从JoJo与bazel的关系出发,介绍了JoJo的高性能、高可扩展性、多工程架构支持、多IDE支持等四大特点
,并揭秘了JoJo帮助Tik Tok等亿级app提升40%构建效率的秘密。高性能的基石建筑的核心是由许多不同的任务和它们的相互依赖组成的。在建造系统中,通常会有一个要求,即在相同的资源、参数和工具下,为某项任务生产一个固定的产品。基于此,构造系统可以构建单任务级缓存重用,从而大大加快构造性能。
实现编译缓存机制的核心问题是构建任务的依赖计算。不同于一般的建筑系统,JoJo结合了远程缓存、远程执行和依赖计算。JoJo在本地构建时,她实现了一个类似Xcode的增量构建方案——构建所需的所有文件都是通过。C或Swift源代码最后一次构造后编译器生成的d文件,以便进行依赖计算。的。这里的d文件是一个依赖描述文件。编译器完成一个构造后,会生成一个. d文件来描述这个构造过程中涉及到的所有文件。
在JoJo中,技术人员基于clone和Swift的编译器,实现了一个C系列和Swift系列代码的快速依赖计算工具。2000+C系列文件的扫描可以在几秒钟内完成,Swift系列代码也可以达到类似的性能。所以JoJo几乎可以在保证正确性的前提下带来开销,实现正确快速的缓存重用体验。
另外,在JoJo构建系统中,使用了分布式缓存和构建集群来加速构建。对于每个构造好的子任务,JoJo会根据其依赖关系计算出一个key,然后用这个key查询远程缓存服务器中已有的产品。如果匹配成功,将下载产品和文件,并完成子任务。如果没有命中,JoJo其实会调用相关工具构建一次,本地或者远程执行。为了避免在本地上传相关资源文件到远程集群,JoJo会通过内部高速网络从缓存服务器下载需要的文件,只需要在本地传输一个列表到集群。远程集群本身可以扩展,可以是Mac机,也可以是Linux机,大大提高了集群的可扩展性。最终形成一个完整的分布式架构。
具体到 engineer 的建设场景,由于网速和本地性能的差异,整体任务调度的需求也充满了变数。所以JoJo实现了一个智能排班系统 。与Xcode对并发任务数量有固定限制不同,JoJo可以通过网络、CPU、集群资源的差异动态调整调度策略。此外,JoJo还会实时测量速度,根据本地CPU的性能决定是否熔断远程机制。这些都进一步保证了分布式架构的稳定性和性能。
高可扩展性JoJo以bazel为核心引擎,同时重写和构建大量规则,以摆脱对bazel的完全依赖。在实践中,JoJo绕开了单元测试、静态分析、库的动态懒加载、索引构建等过程,使得相关任务也可以由构建系统自动管理和缓存。
Bazel自带的查询命令和方面机制赋予了JoJo灵活的数据查询能力,使工程师可以自由获取包括构造参数和依赖信息在内的任何编译信息,这些信息也可以在构造过程中被另一个规则消耗,从而实现动态构造能力。
目前常见的仓库管理机制有Monolith、Multirepo和Monorepo。JoJo被设计成以可扩展的方式支持任何架构。目前JoJo支持直接构建标准的cocoapods项目,无需任何业务转换。 Tik Tok 在这种模式下运行。 Monorepo用于业务管理,第三方库和基础库继续使用cocoapods管理的混合构建模式。同时,JoJo也在尝试制定内部Monorepo开发标准范式,一站式解决学习成本和迁移成本。
对于不同的架构,JoJo通过扩展一个新的规则来支持不同的架构描述。对于一个特定的架构,相关的规则会负责具体的处理,统一转化为一个中间层 进行表示。这个中间表示将抽象地描述静态和动态库的构造、依赖关系等等。最后,JoJo通过中间层构建最终产品。从而实现了对多架构和混合模式的支持。
IDE 融合JoJo本身支持多种ide。舒彪老师以Xcode为例,介绍了如何在Xcode下用JoJo构建。为了尽可能让商科学生在转用JoJo后变得不敏感,技术团队经过研究自行研究了一些逻辑,通过一定手段完全接管了Xcode的索引、调试、日志、进度条等功能。所以在JoJo的系统下,Xcode项目完全变成了一个“前端”的角色,只是浏览项目文件和目录结构,所有底层任务都由JoJo完成,业务体验基本接近原生体验。
改造后,Xcode直接与JoJo的构建服务进行通信,JoJo构建服务会调用JoJo进行构建,同时将构建进度、日志、编译、参数等数据提供给Xcode进行消费。其他不相关的请求将继续转发给XCB构建服务进行处理。再者,JoJo还挂接了SK Agent 的索引构建流程,让技术人员可以使用JoJo构建索引任务,从而通过JoJo实现全流程接管,保证各个功能的独立性。
此外,技术团队还从索引缓存、二进制调试源索引、引入智能分析系统优化引导错误提示等方面对JoJo进行了进一步优化,从而更好地帮助各项业务的开展。
韩建磊《抖音 iOS 体验优化:流畅性优化探索》目前在负责iOS客户端基础体验的韩老师,从具体的感性案例中梳理出了与流畅度相关的常见问题和优化策略,并结合实践经验提供了一些针对指数恶化问题的故障排除思路和解决方案。
流畅性简介什么是流畅度?如果区别于场景,包括页面刷新、动画、过渡、弹出、拖拽滑动等一系列操作。都属于流畅的范畴。从用户体验的角度来看,对流畅度的理解可以包括视觉体验、触觉体验和听觉体验三个指标。一般来说,流畅度可以用来衡量用户在各种场景下的交互体验。根据技术团队在Tik Tok的实践经验,流畅度优化至少可以带来3%的观看时长收入和6.6%的视频播放量收入,流畅度优化与人均播放时长、页面渗透率、用户留存、广告收入等业务指标密切相关。
目前,丢帧和FPS是衡量Tik Tok流畅度的核心指标。
韩老师带领我们想象这样一个场景:有一天,在线核心指标FPS突然大幅恶化,该如何排查问题?
基于以上问题,技术团队开发了一套函数耗时监控系统。通过对比线上市场耗时,很容易定位哪个功能已经退化,退化程度如何,有助于技术人员快速定位新增的退化功能,同时无需考虑Debug能否重现。
此外,技术人员还整理了滑动和首刷场景中关键函数的调用,然后以汇编钩子的形式截取函数。在主函数调用期间,记录了子函数的执行时间,不仅收集了每个子函数的时间,还收集了内部调用栈。同时,为了使功能耗时监控系统能够应用于各种场景,上层支持动态配置和分配,还支持导出完整的调用链接,使得在达到监控目标的同时,可以将整体性能损失控制在最小。
优化实践在回顾了常用的优化策略后,韩先生从帧率和卡顿 细节优化入手,结合具体案例阐述了处理问题的方法论。
这里有三种帧速率优化情况。
此外,韩老师还以Tik Tok三个真实卡顿案例为例,介绍了技术团队在实战中处理卡顿问题的解决方案和优化路径。
在有效应对卡顿问题的基础上,如何拦截类似掉帧问题的小劣化?反复出现的问题如何防止进一步恶化?带着这些问题,团队通过问卷调查发现,流畅性问题的恶化并没有被高度重视,RD对修复存量问题的热情也远不如对新问题的热情。在此背景下,技术人员开发了一套精细化监控系统,在用户相对敏感的时间或场景下,挂钩记录一些常见的卡顿、耗时等不良情况,并应用于防降级平台。随着卡顿和帧率问题优化数的增加,坏例条目数增加,精细监控质量提高,粒度越来越细,形成一组良性循环。
整体流程如上图所示,客户端通过动态库注入将监控代码植入主机App,然后执行自动化测试任务。当每个场景被命中时,将进行数据和堆栈记录。任务后,统一符号化;然后上报给防降级后台,最后生成数据报告,触发报警或进行智能诊断。
此外,Tik Tok的技术团队在慢功能、动画、耗时任务打散、低端机退化等方面投入更多,以更好地满足用户的流畅体验。未来,团队将继续在UI/动画、架构、线程控制等方向探索,在流畅度和用户体验上交出一份满意的答卷。
朱峰《抖音 iOS 稳定性优化与探索》Tik Tok基础技术iOS客户端工程师朱峰先生一直参与Tik Tok iOS应用的稳定性优化和保障体系建设。他从稳定性的基本概念出发,详细讲解了稳定性框架和核心指标,并畅想了稳定性优化的未来。
基础概念从狭义上讲,崩溃是指在代码层面遇到的语言机制错误、CPU访问异常、主动退出等问题。广义上的崩溃包括内存过多被系统杀死(OOM)、主线程块被系统杀死(watchdog)、CPU过多被系统杀死等问题。,这些都属于稳定性关注的范畴。
说到稳定性框架,不得不提的一个问题是启动任务。在APM的SDK初始化时序问题上,我们需要让大部分代码在监控SDK之后执行,这包括崩溃监控、看门狗监控和OOM监控,直接关系到稳定性框架。
在premain code的治理中,朱峰老师介绍了延迟自定义段模式的方法。这种方式可以替代传统的+load方式,但同时提醒大家,节数不能无限扩大,否则可能会超过系统dyld限制,启动崩溃。
Log 对于排除稳定性问题至关重要。问题往往是堆栈不清造成的。这时候通过日志搜索来分析崩溃上下文的信息就非常重要了。其中,日志记录必须基于mmap,以保证日志不会丢失。此外,Tik Tok技术团队开发的日志分析工具也可以帮助开发者显著提高分析效率。
针对目标C异常、多线程崩溃、杀死进程时崩溃、全系统调用栈、编译优化级别导致崩溃等常见问题。,朱峰先生阐述了问题的形成机制和应对策略。
以处理整个系统调用栈崩溃为例。一般的应对流程是在查看日志分析上下文的基础上逆向系统库代码,通过swizzle/fishhook绕过有问题的代码,使用CoreDump分析。如果问题可以在本地重现,可以使用Xcode Malloc日志来查找地址分配调用堆栈。
在处理死机问题时,除了疑难问题的排查,还有线上线下的长效应对机制。有asan自动测试,灰色阶段猴子自动测试,集成阶段启动崩溃自动测试。通过安全气垫、安全模式、堆芯转储等进行在线响应。
WatchDog常见原因有文件IO、网络IO、CPU密集型、主线程和子线程共享锁等。相应的解决方案通常包括放置子线程、使回调形式适应业务逻辑、优化锁粒度等。
OOM是Tik Tok技术团队在稳定性优化方面面临的最严峻的挑战之一对于Tik Tok来说,OOM问题的数量是Crash的两倍多。用户使用时间的增加,导致内存使用的硬归属,优化/恶化,低端电脑的大量存在,这些都使得OOM的处理变得困难。
对于线上OOM,技术团队主要采用MemoryGraph机制(自学)、矩阵内存Stat、大图监控来应对;离线部分通过MLeaksFinder,Xcode Leaks自动测试,missing AutoreleasePool自动测试等方式规避。
朱峰老师对每个解决思路和工具都做了针对性的讲解。
未来将从框架、流程、静态和动态分析等方面进行更多的探索和努力,优化Tik Tok iOS应用的稳定性。,为超大型app建设保驾护航。最后,朱峰老师鼓励大家永远保持对底层技术的兴趣和不断探索的热情,不要给自己的成长设限。
每位讲师的分享结束后,线上观众通过评论区和弹幕与讲师互动。五位老师都根据自己的专业方向和实践经验,耐心细致地做出了针对性的回答。
至此,第三届字节跳动技术沙龙已经圆满结束。
如何获取 PPT 和回放视频?关注微信官方账号“
字节跳动技术团队”,后台回复关键词“沙龙点评”,即可获得五位老师PPT的下载链接和回放视频。字节跳动技术沙龙是由字节跳动技术社区ByteTech发起的技术交流活动,面向全行业开发者。通过搭建一个包容、开放、免费的交流平台,推动前沿技术的普及和落地,帮助技术团队和开发者快速成长。字节跳动技术沙龙的技术分享来自在字节跳动工作的技术专家和一线互联网厂商。针对热门技术方向和实践总结,为技术团队和开发者呈现一场技术盛宴,以供参考。你希望在未来的沙龙
中听到哪些话题?你期待看到哪位技术专家分享他的实战经验吗?欢迎在文章底部留言表达心声~第四届字节跳动技术沙龙预计在3月[/S2/]举办。春暖花开的时候我们一起见面吧!