导读:2021年10月21日,「QCon 全球软件开发大会」在上海举行,网易智企技能 VP 陈功作为出品人建议了「AI 时代下的交融通讯技能」专场,邀请到网易云信、网易音视频实验室、网易云音乐的技能专家与大家一同共享交融通讯技能趋势和演进方向、视频通讯要害技能探索及实践、音频 AI 算法在 RTC 中的实践、网易云音乐网络库跨渠道化实践等论题。
咱们会针对四个讲演专题逐个进行介绍与共享,本期是咱们的第四期,网易云音乐网络库跨渠道化实践。
嘉宾介绍: 陈松茂,2020年底参加网易云音乐,一站式网络处理计划技能负责人,目前从事跨渠道网络处理计划相关研究,旨在下降多端网络工作的研制本钱,以及多应用间的接入本钱,用较低的本钱取得持续可观的功能及能效提升。曾就职于阿里,长时刻从事于 Chromium 相关技能研究和应用,具有丰厚的浏览器开发和内核晋级经历。
前语
在做网络优化的过程中,因为体系网络库的差异,你不得不把同一类型的优化,在各端进行适配,你感觉工作量在成倍增长。
正因为多种适配版别的存在,一致性无法彻底保证, 别的因为体系网络库供给的数据收集才干不同,你很难收集到彻底对齐的数据,这意味着服务端需求做一些兼容。
跟着移动互联网的崛起,PC 在变得小众化,但这不代表 PC 不需求对应的网络优化或监控服务,但你的确无暇顾及。大厂能够不惜代价,筹建庞大的团队深化协议栈进行从头开发优化,但你期望只投入有限的资源,就能够换来可观的网络功能提升。
不知道这些场景是否有戳中你的痛点,或许你曾经也被困扰过?假如我告知你,接下来的共享能帮你处理上述一切的问题,你是否有兴趣了解下?假如我告知你,你或许什么都不需求做,就能轻松让网络的呼应时刻缩短 30%~40%,你是否更有兴趣了?
本次讲演主题为:网易云音乐网络库跨渠道化实践。 本文聚焦跨渠道化,首要涉及工程化相关思路,分四个部分,别离是布景介绍、计划规划、落地实践及后续规划。
布景介绍
下图是当时云音乐网络库在各端的架构,能够看到上层的网络战略和监控服务等等在各端都有独立的完结,这会带来如下问题:
-
重复造轮子: 一切的网络战略、质量监控,每个端都有完结。当你需求加一个新的战略的时分,每个端都得完结一遍,这是严重的人员浪费。
-
缺乏一致性: 网络库及人的差异,导致轮子的标准和完结度不一致。
-
资源不对等: 移动端研制比较多,但 PC 端研制就很少,这导致 PC 端许多网络战略和质量监控都是残损的。
-
深度优化难: 对网络库来说,要深层次的优化,需求对网络模块有充分的理解。可是这当下,咱们能够在 Android 上进入深度的挖掘,可是不或许四个端里边都有做网络的同学来做专门的优化。这导致每个端只做一些浅层次的优化,不会做深层次的挖掘,因为没有人。
经过前面的分析,大家能够清楚的看到,其实每个端都完结一套,是不靠谱的。结合当下面临的一些痛点,自然而然产生了一个共同的诉求:让一切的端都共享一套网络处理计划。 再进一步,是不是一切的 App 都能共享一套网络处理计划。
处理上述问题最首要的做法是全体计划跨渠道化, 但也面临着不少应战
-
首先是跨渠道性。 功用层面上是不是只有战略需求下沉,战略下沉今后,三方 SDK 是否能下沉?别的跨渠道计划有许多,能够仅仅是移动端的跨渠道化,也能够是移动端加桌面端都跨渠道化。
-
其次是才干复用。 运用 C++ 重写的网络战略能不能在不同场景下复用,除了重构事务,是不是能够提炼一些结构?这些结构是不是能复用?别的后续新的需求出来了,是不是能在现有的根底上很容易的扩展上去?
-
最终是后期推行。 一开始树立这个项目的时分就明确后期需求进行推行,不仅仅供给给网易云音乐运用。所以,其它 App 在接入网络库时本钱怎么样?是不是能很简略的接入?这决议着后期能否顺畅推行。别的,每个 App 都有各自的特色,比方网易云音乐有免流功用,但其它 App 或许不需求免流,换句话说,不同的 App 能够依据实际情况进行定制,这也是咱们面临的应战。
针对上述应战进行的计划规划,是整个共享的中心。
计划规划
跨渠道规划思路
一开始规划思路很简略,下图中右侧绿色部分是用 C++ 重写的包含中心逻辑的 SDK,在这个根底上,由 Android、iOS 别离接入这个 SDK,底下的网络库不变。这个改造本钱很低,但接入本钱较高, 移动端接入 SDK 的时分,需求对咱们供给的 SDK 进行二次包装。于是咱们就在想,能不能接入的时分不要搞五六个 SDK,兼并成一个 SDK?
接下来就有别的一个计划,咱们想把上层的绿色部分悉数兼并到一个 SDK,这需求在现有的网络库之上抽象出网络署理层,依据网络署理,上面做各种战略和事务逻辑封装,这样才干把一切逻辑兼并到一个 SDK 里边,这个做完了今后全体接入本钱就会大大下降。但网络署理层很厚,跟着时刻的搬迁,底下的网络库会变,上面的网络署理层需求不断适配,这样适配工作就会没完没了。
更进一步考虑,能不能让网络库一致掉?咱们把上面的网络署理层抽掉,选用一个通用的跨渠道网络库进行代替, 在这根底之上,封装咱们的战略和服务,这样全体链路就跨渠道化了,这是一个思路。
最终小结一下,跨渠道的办法有许多,在网易云音乐,咱们挑选了最彻底的一种,即整个网络处理计划包含网络库、上层战略以及一些服务悉数跨渠道化。
跨渠道网络库规划
上面讲了跨渠道最要害的点便是挑选一个适宜的跨渠道网络库,咱们挑选了 Cronet,它跨五端,彻底能支撑云音乐的场景;协议层面支撑传统的 HTTP、HTTP/2,QUIC;别的普及程度上,Google 系悉数用了 Cronet,国内百度、微博、网易传媒,现已接入了官方的 Cronet,他们在官方 Cronet 根底上,各端做了自己的战略包含一些监控服务。头条系、蘑菇街改造比较彻底,在 Cronet 根底上进行二次定制开发,形成了自己的网络库;自从 Chromium 开源今后,国内一切浏览器都是依据这个项目做的,并在不断的演进中,十分活跃;最终一点是开源协议,Chromium 首要运用的是 BSD 协议,也便是说咱们依据 Cronet 做的修正,不需求强制开源,这对商业公司来说,很要害,也是咱们挑选 Cronet 的重要考量。
下图是整个跨渠道网络库的全体架构。
最底下别离是 OS、Base 和 Net;咱们在Net 的根底上封装了一层 Common API,作为胶水层阻隔 Net,并扩展一些自己的根底才干,包含 BI、FunctionBridge、插拔服务等;在通用才干根底上又做了一层组件,包含网络战略、APM 监控、HTTPDNS 服务等等;最终接口层,咱们对外露出了组件 API,便利 App 调用。
咱们能够经过 Cronet API 进行网络收发,并在这个根底上新增了部分扩展 API(比方原先的 Cronet API 不支撑超时[包含建连和包间超时]设置;关于成功和失利的恳求,也不支撑返回详细的 IP;别的,关于 HTTPDNS 支撑也不是很便利)。
关于 App 来说,除了看到 Cronet,还能看到一个组件体系。App 经过一致装备,把内部的组件按需启用(比方这儿默许会启用 HTTPDNS 和 APM,可是关于网络战略就不一定需求);理论上组件之间是彻底阻隔的, 可是有一些特别场景,比方网络战略需求跟 HTTPDNS 组件做一些通讯,咱们内部封装了一些可插拔的服务,HTTPDNS 组件将才干露出到插拔服务中,网络战略凭借插拔服务对 HTTPDNS 组件进行调用;App 经过调用桥接(类似于 JSBridge)直接与组件进行通讯,这样后续组件接入和扩展起来本钱就很低了。
组件不直接和网络内核通讯, 咱们在网络内核根底上封装了根底才干,包含一些必要的恳求拦截,恳求转发及网络监控才干。
咱们期望经过这次网络库跨渠道化实践,沉淀出一个可复用的网络结构:这部分网络结构能够在网易内部复用,不包含事务逻辑,仅仅是一个结构,里边会定期更新 Cronet 内核,包含一些安全补丁(咱们也接过 Cronet 官方版别,运转一段时刻后发现,线上有一些 Crash,这个需求咱们经过打补丁的办法修正);咱们在 Cronet 的根底上供给一些根底的组件管理****和根底才干封装,旨在下降 C++ 等级定制本钱。
另一方面,依据可复用网络结构,咱们扩展了一部分才干集:一切事务都放在才干集里边,变成三方库,以组件的形式进行复用; 接入方能够依据自身需求,灵活组合;才干集能够供给通用的才干(比方 APM 监控、HTTPDNS 服务),也能够供给个性化的才干(比方免流服务),旨在满足接入方多变的事务场景和定制述求。
最终,简略总结一下网络库规划,咱们直接依据开源的 Cronet 计划,构建了云音乐自己的一致网络库计划,并采用了“可复用网络结构+可扩展才干集”的模式进行事务下沉。
Cronet 晋级
咱们在选这个计划时分经过了许多的网上调研,咱们发现大部分公司在计划选型时,挑选了直接运用 Cronet,而不是依据 Cronet 进行二次开发定制。他们都提到了一个共同点,假如对 Cronet 进行了定制,后续内核晋级把控起来难度有点大或许本钱会很高, 这是他们不选这个计划的最首要理由。
那么面临晋级咱们该怎么办呢?首先讲一下为什么要晋级,晋级原因很简略,一个是要修正问题(比方出现一个安全漏洞,期望经过晋级或许修补丁的办法修正这个问题);别的一个是取得特性(比方现在的 QUIC 在快速演进中,国内主流用的都是 gQUIC,可是 iQUIC 标准正在慢慢的一致,Google 也在逐渐向 iQUIC 靠拢,咱们期望经过晋级直接支撑 iQUIC);最终,Google 对 Cronet 也在持续进行优化,咱们期望经过晋级,直接享受到对应的优化效果。
那晋级详细有哪些痛点呢?简略点讲,能够把晋级类比成一次代码提交: 假如你提交足够及时,修正一部分就立刻提交,你简直不会遇到抵触,很顺畅;有些同学习气欠好,写了两三天的代码,才一次性提交,这时分就比较容易遇到代码抵触,或许需求花点时刻才干处理;假如持续怠慢代码提交的节奏,像咱们对 Cronet 的二次开发,或许半年或一年乃至更久,也不会与官方的最新 Cronet 进行兼并,比及需求进行 Cronet 晋级时,你会发现新版 Cronet 结构或许都变了,这个时分兼并代码就十分痛苦了。
以前,咱们做浏览器,每次进行内核晋级,就有几千上万个文件抵触,光兼并代码这部分要花半个月的时刻。别的代码兼并的时分,你其实不知道怎么兼并它,改变太多了,兼并很麻烦。最终一个,即便侥幸编译链接经过了,你会发现许多功用阑珊。
依据此,咱们想了一些对应的处理思路,比方关于代码抵触来说,咱们依据源码二次定制时尽量削减修正,尽量做好阻隔让修正的当地能够很容易的辨识出来。 这样兼并者能够很清楚的知道这个当地要合,这个当地不要合。对功用阑珊最有用的办法便是做单测, Chromium 项目自身单测掩盖率很广,你只需在新增的代码上做一些单测掩盖就够了。
下面重点讲下,怎么削减侵入并做好阻隔,这两点其实是很简略的技巧,没有什么难度,大家能够很容易的参考并实践。
削减侵入咱们是这样考虑的,首要是三个词:一个是提接口,第二个是依据接口搭结构,最终依据结构扩组件。
对 Cronet 的侵入,咱们更多以接口的办法进行,而不是直接魔改。 提接口包含新增一些署理、观察者或许拦截器(运用了部分规划模式的思路),把一切的修正都会聚到几个小的点上,整个实践下来,提接口这部分,咱们改造了快一年了,接口部分只占修正里边的 5% 乃至更少;依据新增的接口,咱们搭了一个网络结构,网络结构首要做一些才干封装,包含组件机制和通道封装,再包含一些插拔服务等等;最终,咱们会把各种战略、监控、事务都往组件上堆, 整个下来,对源码的侵入程度操控得还是能够的。
下图代码是咱们对 Cronet 源码进行修正的一处示例。左边是源文件关于 Socket 复用的代码,右边做了一些改造,咱们做了一个回调,由事务侧决议是否能够进行 Socket 复用。乍一眼看,无法发觉两者的差异,这给内核晋级带来一个很严重的应战。咱们代码彻底没加任何阻隔办法,一兼并彻底不知道自己做了哪些修正,彻底无法兼并。
怎么办呢?有同学或许会想到加注释这一类的。以前,刚开始做浏览器的时分,咱们团队也是用加注释这种办法,这种办法简略“高效”,但总感觉有一点不舒服,尽管进行了阻隔,可是有时分定位一个问题,你觉得这个 bug 不该该是 Cronet 的,应该是咱们修正出来的,这时分,你或许需求编译原始代码进行验证,可是加注释的办法导致你无法快速编译出一个源版别。
关于 C++ 来说其实很简略,便是加一个宏开关,经过宏开关你能够很清楚的看到哪些当地改动了,一目了然,而且能够快速进行源切换,这是以前我地点的团队长时刻实践下来的经历。
大家看到一切修正都把源代码放在前面,把咱们的修正放在后面,为什么要这样做?有一个很大的优点是,上面的代码因为都不是你修正的,兼并的过程中不太会有抵触,后续假如有问题,你能够经过兼并东西快速的识别差异。
关于 C++ 以外的代码,咱们也做了与宏开关类似的开关进行代码阻隔,如下图所示。
最终咱们还做了文件等级的阻隔。 红框部分是新增的文件目录,咱们把修正悉数放在 wow 下面,把一切修正都阻隔在自己的文件里边。举一个比如,net 目录下有一个文件,咱们对它进行了修正,咱们会把新建的文件放在 wow 下的 net 目录中,并对新增的文件加上 wow 前缀。
Cronet 晋级无法防止, 也没有银弹,咱们在这儿采用低本钱、可推行的“技巧”,让整个晋级变得相对简略一点。
避坑攻略
处理了晋级的顾忌,你是不是现已摩拳擦掌了?别急,你还需求最终一步,先让 Cronet 代码跑起来。
下图是 Cronet 官方的文档,对源代码的 check out、build and run 给出了翔实的描述,你只需求对着文档一步步操作就行了。因为 Cronet 未独自开源,Cronet 与 Chromium 的代码是混在一同的,共用同一个代码库房和构建体系, 所以代码拉取和编译环境预备与 Chromium 一致,关于 Cronet 的编译,Google 给出了独自的文档描述,而且为 Android 和 iOS 供给了独自的编译脚本,简略点说便是一条命令行的事情。
年初咱们对 Cronet 进行了调研,那时 Chromium 的内核版别是 M88,整个拉代码编译调试都很顺畅,当然咱们只测试了 Windows 端。咱们接入 Cronet 的初衷仅仅为跨渠道化, 但跟着调研的深化,咱们看到了各大互联网公司关于 QUIC 方面的实践,他们给出了不同版别的功能提升数据,因为 Cronet 天然支撑 QUIC,咱们就想,等完结网络库跨渠道化改造后,咱们也敞开 QUIC,看下作用,假如真有提升,那就更好了。
但当咱们对 QUIC 进行一番调研后,咱们发现国内云厂商首要支撑的 QUIC 版别是 gQUIC 43, 而且 Chromium M88 版别现已不默许支撑 gQUIC43,也便是说咱们不得不回退到某个默许支撑 gQUIC 43 的低版别 Chromium,为了更好的做数据对比并下降 QUIC 接入的危险, 咱们选取了与传媒一致的版别 M72。
因为 M72 与 M88 隔了近2年的时刻,当咱们将 Chromium 代码切回 M72 时,咱们发现无论是 Windows、Ubuntu、Mac 下,都编译不过,有各种古怪的问题。捣腾了很久,后来才猛然意识的,或许是文档的问题,毕竟2年过去了,怎么找到2年前 M72 对应的官方文档呢?
Chromium 的官方文档和代码是一致管理的, 你只需在 src 目录下找到对应的文档即可,或许线上直接依据 tags 找到对应的文档即可,有了匹配的文档,各种编译链接问题就少多了。
下图是依据官方文档和咱们的运用习气整理的 Cronet 在各端下的开发东西、编译环境和构建体系。仅有需求着重的是,在编译 iOS 版别时,需求将 XCode 中的 Command line tools 指向低版别、Win10 下记住装置对应的 SDK。别的,整个 SDK 的构建,运用了 GN+Ninja 的办法,或许刚接触的同学会有一点不适应,其实了解几天就能够上手了。
别的一个是调试。做开发的都知道,学一个东西很简略,便是把代码拉下来编译,然后 Debug。出乎咱们意料的是,在 Android 下原生不支撑调试 Cronet SDK, 官方引荐一个是 VLOG,第二个是 NetLog。因为咱们三端都有对应的开发同学,比方我习气 Windows,直接依据 Cronet 建一个 Demo 进行调试,大部分场景都能掩盖。假如掩盖不了就用 VLOG 调试一下,这个问题是一个痛点,暂时还没有找到很好的处理办法。
最终是App 接入。运用 Cronet 建议恳求,Google 供给两种完结,一种是异步的 UrlRequest,另一种是符合移动端协议标准的, 在 UrlRequest 根底上封装了流操作的 HttpURLConnection 和 NSURLProtocol 完结。
因为咱们对网络恳求进行了一些接口扩展,左侧的计划只需修正 URLRequest,右侧的计划既需求修正 UrlRequest,又需求修正上层的协议封装,出于削减对 Cronet 侵入的考虑,咱们更倾向于一切的端都运用同一套网络接口, 即 UrlRequest,事实上在主站 API 恳求接入的过程中,咱们的确是这样操作的。可是当接入 CDN 恳求时,面临流操作,UrlRequest 运用起来并不太便利,事务侧需求更多的适配和修正才干接入,最终出于让 App 更低本钱接入方面的考虑,咱们还是全体切换到了运用 HttpURLConnection 和 NSURLProtocol 的办法。
这儿边有一些试错本钱,共享给大家,大家能够少走点弯路。避坑攻略首要是依据 Cronet 进行二次开发相关,怎么让代码跑起来仅仅一个小坑,跳过了今后便是康庄大道。
落地实践
咱们一开始对 Cronet 不太了解,先接入了官方的 Cronet SDK,进行了实验;再依据 Cronet 做一些网络结构的搭建,然后将事务组件逐个下沉到网络库(用 C++ 重写);下沉完今后在 Android 端进行了落地(放量中);然后逐渐把 QUIC 敞开,代码里边只需一行代码敞开就行了;最终,iOS 端也在接入过程中。
线上数据方面,Cronet 在未敞开 QUIC 的情况下,呼应时刻较 OK 提升 16%~20%,敞开 QUIC 后,呼应时刻进一步提升到 37%~41%。这个 40% 的功能提升十分可观,你或许优化一年也赶不上这个作用。咱们为了把上层事务跨渠道化,最终挑选将底层网络库也一同跨渠道化, 因为计划选型的原因,咱们直接享受了 Cronet 带来的网络功能的优化效果。
后续规划
整个跨渠道网络库,现已在网易云音乐的主 App 侧部分落地了, 接下来会把 Windows 和 Mac 掩盖掉;网络库,在云音乐主 App 彻底落地后,咱们会在云音乐产品矩阵中逐个落地;未来,咱们会在网易内部进行推行。
Cronet 接入了,后面的调优之路才刚刚开始,包含预衔接、参数调优、“竞速”优化、衔接复用率、衔接搬迁、QUIC 集群独立布置等。
今年 QUIC 的标准化版别现已出来了。未来,等时机成熟,咱们会经过晋级 Cronet 内核版别直接支撑 iQUIC。
咱们实践下来网络库是最值得和最应该进行跨渠道化改造的; 引荐 Cronet 作为跨渠道网络库的首选,略微有一点点门槛,可是这个门槛不高;咱们线上数据 Cronet 在 HTTP/2 的根底上现已有不错的功能优势,大概 20% 左右,敞开 QUIC 后优势进一步扩大;关于接入 Cronet,一开始咱们也是张望的,你能够跟百度、微博、网易传媒相同,先尝试一下用官方的 Cronet 进行接入,再决议是否依据Cronet进行二次开发。