字节跳动亿级DAU客户端发布实践

2022年05月14日 阅读数:3
这篇文章主要向大家介绍字节跳动亿级DAU客户端发布实践,主要内容包括基础应用、实用技巧、原理机制等方面,希望对大家有所帮助。

本文是字节跳动发布工程团队的高磊讲师在2021 GOPS 全球运维大会中「字节跳动亿级DAU客户端发布最佳实践」的分享全文。web

首先作一下自我介绍:我是字节跳动发布工程团队的工程师高磊。从事软件开发工做有10多年的时间,在传统软件公司还有一些创业公司都作过,最近大概6,7年时间基本专一在DevOps方向,也积累了一些本身的理解和经验。
file
今天我分享的主题是【字节跳动亿级DAU客户端发布最佳实践】,经过今天的分享,但愿你们能够了解字节在客户端发布方面作的一些实践。本次我将从四个方面来进行分享,分别是:1.移动端发布的特色难点,2.字节移动发布体系的介绍,3.移动发布的实践总结,4.将来的展望。算法

1. 移动发布特色&难点

咱们先从移动发布特色难点开始。
发布这个概念应该属于CD(持续部署)的范畴,也就是Devops的一部分。平时咱们接触的比较多的是服务端Devops,今天的分享主题看似会偏客户端一些,但大部分的内容和理念应该是相通的;原本我以前想的是,若是能到场的话,我会作一个现场的调研,看下到场的作客户端的同窗比例;不过既然如今没有这个机会,我先简单介绍服务端和客户端的发布流程的区别:
file
其实这里的内容并不复杂,但做为咱们后续内容的一个背景铺垫仍是有必要讲的。
从构建打包到包出来的这个阶段,二者应该区别不大,无非底层依赖的打包工具略有差别,最本质的区别在于出包后的流程;服务端的更新流程,是把打出来的二进制包发到咱们本身的服务器上,因此他的整个过程是可控的,一方面你能够随意更新新版本;另外一方面呢,万一上线的版本有问题,也能作到一键回滚;但客户端是不行的,咱们的包打出来之后,通常咱们会把新版的包放到服务器上,若是对于正式包,咱们会上传到商店来托管,但用户何时过来更新,咱们是不知道的;若是这个版本有问题,那你也没有办法很快会退到上一个版本,你还得规规矩矩的再走一遍这个发版的流程,这个止损的成本是比较高的。
这就是二者最大的区别:客户端升级依赖终端,不彻底取决于平台,这个特性也决定了二者在版本发布全周期其余方面的不一样。
file
具体来讲,首先是部署介质,这个上面提到了,一个是可控的服务器环境;另一个是复杂变化的终端设备,操做系统有Android/iOS, Android有不少不一样的厂商,好比小米,华为, vivo等等;
第二,服务端的版本概念比较弱,通常来讲,咱们不用版本号去定位某次服务端的发布,但客户端不一样,咱们的交流语言就是某某版本,版本号是客户端发布里面很是重要的一个信息;
第三个差别点是发版周期,服务端的发版通常没有明确约定,有新功能的话能够天天都更新,一天发屡次都是常态;这个也符合Devops持续交付的理念; 移动端,通常准备周期比较长,目前主流的节奏多是1到2周一个大版本,也有一些不常更新的应用甚至能够一个月才发一次版;
第四个差别点是参与人群,服务端通常状况下只要测试阶段经过,到了发布阶段基本上就是RD来主导,但客户端由于版本比较珍惜,一个是一个,因此在发版阶段设计了很长的链路,每一个阶段都会配不一样的角色去完成某项工做,如今字节很多团队还有QABM这个角色,就是QA里面专门负责发版管理的同窗;总体分工能够说愈来愈精细和复杂了;
第五点是止损效率,这个以前已经提到过了,不能很快的回滚止损这个“硬伤”能够说是形成客户端和服务端发版差别主要的缘由;
最后一点是多版本并行,服务端显然常态下只会保留一个最新的版本,在上线或者灰度阶段会短暂的多版本并行一段时间,可是客户端历史上累积的这些版本会永久的保留下来,再也不变动;
那么说了这么多,相信你们对二者差别应该有了一个更清晰的认识,你们可能都会想,“客户端发版”真麻烦,这个是对的,并且由于麻烦,一旦发出去之后,就要承担一些可能的风险。
file
下面我给你们看几个典型线上事故的例子,你们能够看下这张PPT,这是咱们线上曾经出现过的真实事故,有由于错误下发64位机型安装包到32位机型致使升级失败的,有为安装包配置错误下载连接致使安装失败的,还有使用不恰当物料致使应用商店拒绝上架的…真是什么事故都有。不难看出,移动场景下发布面临的风险不少,有安全的问题,有数据的问题,有测试的问题,稍有遗漏就会给公司形成很大的损失,或者是财务损失,或者是用户流失,这些都是咱们在设计发布系统时要解决的问题。
file
那么看了以上这些事故,再结合客户端发版的特色,就会引出几个问题:小程序

  1. 如何打造一个高效的发布流水线?
  2. 如何保证流程的安全性?
  3. 如何达到更好更快的放量效果?
  4. 如何保证发布数据的可靠性?

2. 字节跳动移动发布体系

这些问题在字节是怎么解决的?接下来我将为你们介绍字节的移动发布体系,并尝试回答以上四个问题。
file
首先先介绍下字节的移动发布中台发展史,大体能够分为几个阶段:
第一阶段是2017年之前,由于业务发展比较快,公司级的中台发展相对滞后,更多的是业务从自身发版的需求出发,简单搭建了一些小的jenkins集群,用来串联各类打包和测试任务;那这个状态持续了一段时间后,问题就出现了,大量分散的jenkins集群维护起来很麻烦,业务须要本身去维护这样一个平台,投入太大,不少任务编排都重复建设,没有很好的共享资源,随着业务愈来愈多,发版问题愈来愈突出,因此一个中台的出现就变得迫在眉睫了;
因而咱们进入了第二阶段,从2017开始,第一代发布平台1.0就出现了,咱们内部叫“Rocket”,字面意思是火箭,显然它的寓意是快,这个阶段相以前有了一些进步,最大的改变是经过jenkins提供了平台级的流水线,不一样的团队能够本身定制,同时也有了专门的编译团队来解决打包的环境和部署问题,状况比以前要好了不少,jenkins出了问题有人维护,有了流水线,也能够重复执行。
这个过程大概持续到2019,一些隐患又暴露出来了,首先是jenkins打包集群,受限于jenkins自己的单master架构问题,海量的jenkins任务对于构建团队而言一样苦不堪言,多的时候一天发生10屡次重启机器也不罕见,另外呢,这一期的流水线也有一些问题,过分追求灵活的配置,那会的原子能力其实不能真正算原子能力,更像是一些脚本的零散组合,缺少系统的协议约定,带来的问题就是用户的配置成本很高,由于须要关心的细节太多了,平台和平台之间的能力联动不透明,致使各工具之间比较割裂,用户配置流水线成本很高;同时在安全等方面的流程设计不合理,致使一些卡点形同虚设;因此从2019年开始,咱们开始推动第二代发布系统的建设,这一期咱们作了这样几个事情:安全

  • 首先在构建层面,咱们抛弃了基于jenkins的二次开发模式,彻底采用自研的分布式调度集群,实现多主多活,自动恢复,支持任务优先级调度等方案,整个可用性也有了大幅提高;
  • 在流水线设计方面,咱们放弃了以前彻底脚本化的方式,提炼出了不少通用的系统原子能力,大幅下降了用户的使用成本,交互体验有了大幅改善;
  • 除此以外,咱们在安全方面作了一些建设,总体从需求开始就有渗透,目前来看基本覆盖了CI/CD全流程;
  • 在数据这块,咱们肯定了以制品库做为发布的数据基座,从以前关注版本的宏观视角落到关注产物的微观视角,整个平台的架构更加清晰;
  • 最后,咱们围绕灰度放量这个环节进行了多种方式的探索,目标是提升咱们的问题反馈率,尽量把一些潜在的严重问题前置暴露;
    file
    你们能够看看这个图,这是咱们当前版本的一个主要架构体系;
    首先平台目前较好支持了头条,抖音,西瓜,小说,飞书等业务的发版需求,支持的终端场景也从Android, iOS 应用扩展到,Mac,Windows等更多场景;在此过程当中,咱们也沉淀出了不少的平台和能力,从需求规范到研发打包,测试,发布,以及上线后的监控和反馈;咱们的最终目标就是打造一个一站式的通用移动研发平台;
    file
    那回过头来,咱们再看下以前提到的几个问题,我会分4个小节,分别从流水线,安全,测评,制品库这几个方向介绍平台的一些特色,一块儿来看下字节对这些痛点给出了怎样的解决方案。
    file
    首先,针对如何构造一个高效流水线这个问题,咱们搭建了字节发布流水线。流水线对于Devops来讲基本算是一个既定的事实标准了,咱们也不例外,在字节的场景下,他主要解决了两个问题:
    第一:多场景自定义任务编排;
    曾经咱们尝试想从一个最佳实践出发知足全部业务的场景,后来发现这条路是行不通的,由于字节不一样业务的发展阶段不一样,成熟的业务好比头条,抖音,他的团队分工和成熟度和一些新兴业务确定不一样,在权限控制,测试流程,准入准出规范上差异很大,举个例子,一些小业务在上线之初,可能都没有灰度阶段,你若是非得拿一套发布的全家桶模板往给他套上,逼着他必须走一个复杂的灰度流程,对于业务方来讲实际上是一个拖累,而不是提效;
    第二:解构平台的复杂度,便于度量;
    整个移动devops的流程很长,若是不依赖流水线,那你须要本身单独管理这十几个甚至几十个原子能力的相互关系;流水线的设计可让这些原子能力用一个编排的方式管理起来;对于平台来讲,咱们也更容易去度量整个平台的质量瓶颈,是出在哪个具体的能力上,好比某个业务的发版速度一直很慢,咱们经过分析流水线上每一个原子的执行时间,就很容易的定位到是具体哪一个阶段有问题,是自动化测试效率低,仍是灰度阶段放量慢,均可以用自动化的方式来完成,甚至能够作成报表,给出一些定量的分析;
    从咱们本身的实践来看呢,我以为其中的关键点在于:原子能力的粒度;
  • 粒度过大,那内部结构就过于复杂,不利于直接深刻到本质,这说明还须要往下拆解;
  • 粒度太小,没有太多度量的价值,那他就能够合并到其余原子能力里面;
    这里总结了咱们的两个原则,你们能够参考下:
  1. 有独立的功能定位:
  • 这里面独立指的是执行独立,权限独立,数据独立这三个维度;
  • 执行独立指的是原子能力在给定了基本的依赖数据后就能够独立运行,能够实现特定的功能;
  • 权限独立指的是原子能力须要具有独立的权限,不受其余原子能力的直接控制;
  • 数据独立指的是原子能力应该享有独立的数据通路,能够直接和流水线框架作一些数据的沟通;
  1. 可独立度量改进:整个发版流水线的度量最终会落到单个原子能力上,若是你的原子能力自己没法被某个指标度量,那么说明这是个无效的原子能力,他不具有独立存在的条件,须要经过兼并或者拆解来达到度量的要求;
    file
    流水线问题讲完了,咱们再来看看如何保证发布安全。前几年你们会把安全问题当作一个不得已而为之的事情,也就是安全问题是完全暴露了才想去解决的事情,如今呢,业界逐步造成了一些共识,就是安全问题不该该做为一个救火队员,或者做为兜底手段存在,而应该做为一个devops必需的参与者,渗透到devops的全流程;那在字节的场景下,咱们从前两年开始也逐步把安全的理念贯彻到总体移动发布的全流程,从需求阶段开始,咱们就开始作相关的安全合规评估,在CI和CD阶段,咱们也会分别作静态以及动态扫描,在最终release到商店前,咱们还会基于咱们累计的一些案例库作一个审核,避免触碰一些安全方面的红线。
    平台能力刚上线的时候,咱们确实能发现不少的安全漏洞,有网络方面的问题,有隐私合规的问题,看上去效果不错,可是发现漏洞仅仅是起点,更重要的是咱们要去消费漏洞,去修复问题;从平台的角度看,一旦发生了高危漏洞,应该禁止业务方发版; 但从业务方的角度呢,版本的按时上线才是他们最关心的,最后的结果就是平台临时给开绿灯(多是hardcode),而后双方拉老大开群讨论,最后定一个限期整改的方案出来。
    这种事情多了之后,所谓“安全很重要”就变成了一句口号,因此咱们须要一个机制去解决这个问题。这个机制呢,不是技术层面的,更重要的是在公司内部造成自上而下的共识。
    通常来讲,这里面有三方参与的,安全团队,平台团队和业务团队;咱们须要明确每一个团队在安全问题当中的定位:
  • 首先安全团队的职责是负责对安全问题定级,提供安全问题的整改方案,而且辅助落地;好比在咱们如今的平台上,安全团队就提供了黑盒和白盒的扫描能力,以及相应的规则库;
  • 其次是平台团队,平台团队对系统的流程负责,平台不能无论,也不能管的太死,简单粗暴的规则“一刀切”确定是不行的,更合理的作法是提供灵活的卡点能力和配置能力,业务能够根据本身的实际状况配置
  • 卡口级别;在具体的问题上,咱们采起的仍是“增量问题动态修复,存量问题限期整改”这样的原则;
  • 最后是业务团队,须要提升对安全问题的重视和反馈,积极配合整改意见的实施,分阶段按优先级来推进安全问题的整改落实;
    file
    接下来咱们想解决的痛点是:如何提升放量的效果?
    在一开始咱们介绍服务端和客户端差别的时候提到了,放量这个阶段的差别是移动端和服务端最显著的区别,咱们但愿能经过正式发版前的灰度环节发现更多的问题;显然咱们安装的新版人越多,反馈的问题越多,那么咱们的灰度效果也越好;因而咱们尝试了两个思路:
    第一个思路是对内:
    咱们考虑到公司内部有好几万人,里面有RD,PM,QA,他们的专业和对故障的敏感程度是远超过普通用户的,若是能够很好的利用这部分资源,咱们至关于有一个几万人的后备资源池,这个是很是厉害的;因此咱们在18年开始在公司内部作了这样的尝试,上线了一款小程序,叫“字节内测”,咱们本身的运营团队会按期和业务方作一些合做,吸引他们在咱们的平台设置一些活动,引导你们去下载他们的新版,同时反馈试用过程当中的问题,而且给予必定的激励;那从目前来看呢,咱们的ROI仍是很正向的;每周大概参与到活动的人数在7000人以上,平均反馈的问题数量都在几十个上下,其中P0到P2的问题能占到四分之一以上,若是严格去计算的话,咱们为此付出的成本,主要是运营人力和激励,仍是明显少于这些问题外泄到线上后带来的损失;因此呢,内测活动仍是很划得来的;但话说回来,这个对咱们内部运营的要求是比较高的,咱们须要持续进行一些运营的引导,下降用户参与的门槛,保证活动-反馈这个通路的畅通。
    file
    咱们尝试的第二个思路是对外:
    公司用户虽然很多,但相对于外部的几亿用户而言,仍是很小的一部分,因此咱们主要精力仍是要这些数以亿级的普通用户上,他们才是咱们要挖掘的重点;问题就变成了咱们怎样在这几亿用户里经过算法精准的去找到这样一些目标人群。
    file
    要使用模型算法,那前提得准备数据;这里面能利用的数据维度仍是很是多的:
    首先是用户app信息:用户使用app的习惯,浏览内容偏好,活跃时间段,老用户仍是新用户等等;
    其次是用户基础信息:性别,年龄,城市等等这些也能够辅助咱们作一些判断;
    除了用户相关的这些信息外,咱们也能够结合版本自己的一些属性,好比我此次上线的是一个直播相关的功能,那我应该优先去覆盖平时玩直播比较活跃的这部分用户;这样的话,能够实现一个版本信息和用户的深度双向匹配;提升咱们算法的准确性;
    file
    那么在实际落地阶段,咱们还会根据不一样业务的状况来对模型作针对性的优化;好比对于头条,抖音这种亿级APP而言,咱们能够拿到足够的数据来训练个性化的模型;但对于一些小业务而言,由于数据规模达不到能够单独训练的量级,因此咱们会提供一套通用的模型。
    总而言之,目标仍是很是明确的,就是提供CTR和CVR这两个数据的转化率。
    这些就是咱们在放量这个事情上作的一些尝试工做,目前咱们也取得了必定成绩,经过咱们的算法模型比手动盲选平均有10个点左右的提高,但这个事情的天花板很高,咱们后面的提高空间依然很大,须要继续努力;
    file
    再讲最后一个痛点:如何保证发布数据的有效性?
    你们应该还记得咱们分享开始时提到的由于连接配置出错致使的线上事故,根本缘由在于咱们的升级体系没有一个可信的数据源。
    为何咱们不能直接用连接呢,由于连接仅仅表明了这个产物的获取方式,并非惟一表明这个升级包,若是这个连接被篡改或者覆盖,那么意味着你的发布就会出错,而制品库的存在就能够避免这一点,他保证给到下游使用的数据是可信的,是通过完整测试的。
    因此在我看来,制品库他是做为整个devops的核心数据基座存在;若是说CI(持续集成)是对代码负责;那么CD(持续发布)就是对制品负责。
    发布过程当中全部在出包后的数据,基本上能够认为都在针对制品来作的,无论是安全检测,仍是功能测试,或者是用户故事,都表明这个制品存在的某些特性;若是咱们发现某个制品有问题,咱们能够把他放到黑名单里面,这样就不会影响后续的放量。
    有一个案例能够分享下:咱们内部有一个直播中台团队,由于他们是跨业务部门,头条/抖音/西瓜等多个业务都要用到他们的直播插件;以前在制品库出现以前,他们的作法是用飞书在线文档来存储这个包,而后还会很是详细标记这个包的状态,谁,什么时间,什么缘由,备注信息是什么,里面有什么功能?这个过程是很是繁琐和低效的,那在制品库出现以后,咱们能够把整个出包前的配置信息和以后经历的事件动做所有集中在一处,这样用户就能够很方便的根据各类标签条件去找到他须要的包,同时咱们还支持订阅模式,好比我只关注正式类型的包,那我能够订阅下正式包这个标签,当出现此类包的时候,就会主动通知到你;固然前提是你得有这个产品的访问权限。
    那么如今,咱们能够回答这个问题了,发布数据的有效性是经过咱们对制品库的质量品控来保证的,他做为咱们平台的一个数据基座,须要作到和流程解耦,保持必定的独立性,这样才能适配各类复杂的场景。

3. 字节跳动移动发布的实践总结

那第三块咱们总体介绍一下字节在发布体系里面的一些实践和总结。
file
先看这组数据:咱们如今大概每周会有 10 万次的构建,每周超过 700 次的灰度,每周超过千万量级的灰度实际的人群。
file
我也总结出了几点关于迭代的经验,你们能够参考一下:
首先是最佳实践的问题,咱们整个平台的迭代史都是以一个典型业务做为的一个模板进行持续优化的,不追求一步到位,持续迭代是最好的状态;
第二是珍惜事故,事故都是很宝贵的经验,因此咱们对于每次事故就尽可能要作到极致,咱们要作很是完善的这个 case study,也就是“5W” 原则;这个地方须要提一下,做为平台方千万不要去甩锅,业务方没有遵照规范,那能够问下本身是否是给了业务方犯错的空间了?我是否是给到足够的引导跟支持了?我能不能让他没有犯错的空间,我能不能杜绝一切犯错的可能性?
第三个是需求,由于需求是作不完的,那怎么办呢?我以为做为平台方,心态要开放一些,咱们能够作通用的需求,平台能够尽可能作到闭环;可是对一些个性化的需求,不要去强求,不把全部东西都揽下;咱们能够制定规则,给其余人参与的机会,一块儿合做共建,把生态作大。
最后一点是平台价值是须要被度量的,仍是老生常谈的那句话,不能度量的不能被改进;你若是想改进,就必须能够被度量。
file
其次分享一下移动发布版的发展趋势,这个趋势是咱们内部这几年作平台感知到的一些变化。
首先是版本发布逐步出现高频化的趋势;从以前的单月到双周,而如今主流的业务多是一个单周的节奏在迭代,未来可能用不了多久,可能会呈现半周/天级别的演进,这个趋势仍是比较明显的;
第二是安全愈来愈受到重视;这应该是一个常态了,上面其实讲的比较多了,这里再也不赘述;
第三是精准测试场景;传统的都是基于已经写好的用例,这些用例最大的问题在于后期没有人维护;当UI只要有一点变化,测试用例就基本上不可用,必须持续的对这个用例进行更新,这样后期的维护成本是很高的。如今基于 AI 技术的精准测试,后面可能成为一种主流,咱们不须要去维护大规模的case ,它会自动根据我当前的这种场景去实时生成测试场景,咱们内部也在作这方面的一些尝试。
最后一点是持续灰度的理念;随着版本的日益高频这个是必然的,也就是灰度版本和正式版本的界限会愈来愈模糊;你不知道哪天是在灰度,明天就正式了,过两天的又进入下一个灰度。持续灰度这个理念也是我目前感知到的一个点。
file
从平台视角来看,还有几个点能够稍微提一下;速度、效率、安全、成本。具体的每一点你们能够参考一下,我就再也不细讲。
我稍微提一降低本这一点:为何咱们有降本呢?由于咱们要存储大量的包,因此对存储是有必定的要求的。
带宽这一块多是应用场景下比较明显的一个特色,由于若是你是一款拥有亿级用户APP的话,随着迭代周期的缩短,包的更新频率愈来愈高,那由此产生的带宽成本的费用也是比较高。每一年的花在 CD 成本上的这个钱估计可能会上亿。钱其实仍是挺贵的,咱们仍是想办法降一下成本。具体怎么降呢?其实有不少方法的,可是不是今天的主题,因此先不一一展开了。
file
最后作一下总结:今天咱们讲了不少的点,有流水线、安全能力还有放量。仔细去看这些点,它们其实都在追求 balance :好比说流水线,在原子能力上太大或过小都不行,要追求它的 balance;安全和业务的 ROI 的中间的取舍,咱们也要作 balance;放量这一块,咱们要在速度、效果、用户体验之间追求balance。
因此总结起来,整个发布平台的迭代过程,咱们都在不断追求 balance 。在特定的时间段内,想要追求平台的最大业务收益,就必须在某一方面进行取舍,不能什么都想要。
file
在这里分享一下咱们平台的将来的发展方向:
第一,咱们会对发布概念作一些延展。从目前的小发布体系,逐步的把它向大发布体系去引进。那何谓大发布体系呢?除了如今正常的升级包、热修包之外,咱们可能还会把配置资源或者静态资源给也归入整个的发布体系里面来,造成面向业务统一的一个大致系。
第二,咱们会持续优化放量,对放量作一些算法模型化的优化,也尝试引入更多的一些数据维度增长它的丰富性。
第三,咱们会更加精细的度量,把它造成消费的闭环,而不只仅是去搭一个数据看板,数据很好看但并没什么用;最终仍是要去消费、去改进。服务器

今天个人分享内容就所有结束了,期待未来与你们能有更多的交流,谢谢你们。网络