LiveVideoStack · 2022年08月22日 · 北京市

七牛云QRTC自研传输协议(QRTP)对音画质量的提升

编者按: 自疫情开始席卷全球,人们对音视频的需求急剧上升。在需求上升的过程中,人们对网络延迟、音画质量的要求也在不断提高。LiveVideoStackCon 2022 音视频技术大会上海站有幸邀请到了七牛云资深开发工程师——于佳老师为我们讲述QRTN的网络架构是如何提升用户体验度的,以及分析其中的QRTP协议是如何对音画质量进行提升的。

文/于佳

整理/LiveVideoStack

图片

大家好,我是于佳,来自七牛云开发团队,我今天给大家分享的主题是七牛云QRTC自研传输协议对音画质量的提升。今天的分享大概分成三个环节。首先我会以一个工程师的视角去给大家介绍和解析一下七牛云QRTC的实时转发网络 QRTN 的整体架构,然后进而带出今天的主题,也就是QRTN内部的媒体转发协议 QRTP 是如何对整个音画质量进行提升的。第三个环节会去结合实践经验和落地的场景,分享一些QoE提升的经验。

01、QRTC 实时媒体转发服务架构

图片

1.1 网络传输对QoE的影响

图片

整个流媒体从生产到消费,我大概简化为七个环节。其中的三个环节:发送、转发和接收,会与网络相关。大家都知道网络环境是一个很复杂的环境,相比于采集、编码、解码和渲染,它的环境更加复杂,更加的不可控。

由于网络环境造成QoE的下降,是我们日常生活中经常接触到的。比如我们经常感觉到在消费流媒体的时候,有卡顿、延迟和马赛克的现象。其实去溯源的话,多数都是因为网络的拥塞、丢包、乱序和抖动,从而导致了QoE的下降。所以接入到一个好的实时转发网络,是提升终端用户QoE体验的一个必要的环节。那一个好的RTC转发网络它应该具备哪些特点?我大概归纳了四个点。

1.2 面向QoE的RTC转发网络应具备的条件

图片

以上这四个点是我总结出来的,可能不全,但是每一个都很有代表性。首先,节点覆盖会考虑成本还有用户分布等因素,但是在理想情况下肯定是越多越好。当然,节点覆盖的增多也会增加系统复杂度,加大了管理的难度。但是一个好的RTC的转发网络一定是节点覆盖很全面的,包括主要的省市、主要的网络供应商,还有海外的主流国家都是必须要有覆盖的。

第二个点是延迟。实时媒体转发网络相对于传统的CDN分发,有一个特点就是低延迟。它对延迟是非常敏感的。延迟大概分成两个层面,一个是接入延迟,一个是转发延迟。第二部分将分享的QRTP协议,就是去提升转发延迟的。

第三点高可靠是作为服务必须要具备的能力,体现在容灾能力、快速扩容能力,以及对故障的隔离能力。

最后一个是数据量化。数据量化是在把整个框架搭建好之后,才会去考虑的一个事情,但是它相对来说非常重要。为什么重要呢?因为数据在整个系统中,有三个层面的作用。第一个层面是数据可以为用户通话质量调查,还有日常的排障提供一个有力的依据。然后第二个层面,网络中产生的大量数据,可以帮助我们去提前发现转发节点、接入节点的一些故障和一些不利因素,从而进行预判并规避风险。数据使用的第三个层面,就是当拥有大量的数据之后,这个数据可以通过训练模型和一些合理化的清洗以及处理之后,去反馈给系统,对整个网络形成一个强反馈的机制,然后让系统更加稳定。

针对以上四个方面,整个QRTN网络也在不断地迭代,不断地优化。

1.3 QRTN转发网络演进

图片

这里我大概将 QRTN 的演进简化为三个阶段,包括:单点转发、分布式转发和智能分发。

单点转发比较简单,现在很多开源社区,在实现了整个WebRTC协议栈之后,一般都会去做这种单点转发的 SFU 来作为用户体验的一个接入点。单点转发的缺点也是比较明显的,比如单点转发去作为一个对外服务的话,它的容灾能力、承载能力,还有地域覆盖能力都会存在问题。但是由于它部署简单,所以作为功能验证的方式还是非常好的。

我们在内测阶段使用的是单点转发的方式,而在公测阶段,就进化到分布式转发的方式了。分布式转发就是让媒体在内部构建的实时分发的网络下去传输,这样可以降低整个端到端的延迟,并且也可以多点协同,有很强的容灾能力。但是分布式转发发展到一定的阶段之后,系统会变得非常复杂。首先是内部的分发路径,我们之前是基于经验去调整的,所以在管理上难度会有所提升。在结合分布式转发这些局限之后,我们又进一步迭代到智能分发阶段。下面我会结合某些点去讲我们是如何去做智能分发的。

1.4 QRTN转发服务架构

图片

我把QRTN整个网络抽象成四种类型的节点。这个是抽象的,因为可能具体的服务或者节点不是这样。抽象出的四种节点包括:接入节点、转发节点、调度节点和控制节点。这四种类型的节点分别有不同的作用,然后有机地构成了整个QRTN的转发网络。

首先接入节点是地域全覆盖的用户接入节点。转发节点负责将所有的接入节点进行连接,在转发节点内部进行跨ISP的、跨地域的、跨国家的连接。调度节点负责用户接入的时候应该分配到哪个节点,以及怎么去做容灾和成本的一些优化。最后控制节点去做动态的路由规划,转发节点内部的动态的路由规划是通过控制节点来去完成的。

这里讲一下调度节点在智能分发阶段我们做了哪些优化。早期在用户接入过程中做节点选择时,我们采用了基于地理信息的选择策略,比如某一个地域的用户,他应该就近接入到这个地区的接入节点里。但是经过大量的实践之后,我们发现这种模式是存在一定误差的。因为如果只从单维度去考虑地理信息的话,有些用户接入的QoE体验并不是特别的好。最后我们引入了大量的数据参考,结合历史数据做一个加权,再综合它的地理信息去做节点调度。这个是作为智能分发阶段的一个迭代优化点。

1.5 QRTN智能分发网络

图片

前面环节里面没有体现我们对于数据是如何整理使用的,我们针对整个网络产生的数据构建了鹰眼数据平台和QoE评估系统。鹰眼数据平台主要是帮助用户完成通话质量的调查。在实现排障和质量分析的前提下,鹰眼数据平台同时为系统提供了很多的参考信息,比如说动态的路由规划,还有最常用的场景自适应,即根据特定的场景需求在参数方面进行优化。

1.6 QRTN转发网络QoE数据

图片

以上是我以一个工程师的视角对 QRTN 网络做了一些介绍。七牛云整个QRTN的网络,对外的QoS大概有三个指标。登录时间小于5秒、卡顿达标率不低于99.5%、端到端的延迟是小于400毫秒。这个卡顿是指单位统计时间音频200毫秒没有渲染记为一次卡顿,视频是600毫秒没有渲染记为一次卡顿。

大家可以先记一下QRTN网络的指标数据。这里面体现了两个关键字:卡顿和延迟。卡顿和延迟是在整个实践中追求的一个重点,接下来我也会围绕卡顿和延迟这两个点来分享QRTP协议针对这两个指标做了哪些优化和提升。

02、传输层媒体转发协议QRTP

图片

前面我大概分享了一下QRTN网络的结构。那么QRTN网络内部的流媒体转发该用什么样的协议呢?大家可以思考一下你所接触到的传输层的协议,比如说TCP或者UDP。如果让你去设计一个QRTN网络中内部的流媒体转发协议,应该怎样去设计?

我给大家提示一下,有一条主线是:我们整个内部流媒体的转发要解决一个问题——即在保证实时传输的前提下,尽可能大的提高带宽利用率。基于这一设计需求,想一想我们有哪些协议符合这个需求呢?

2.1 常规传输层协议的局限

图片

以上是我整理的几个比较典型的传输协议。基于上面的需求我们来看一下TCP,我有一个比较深刻的实践经验,有一次对一条跨国的高质量线路通过 iperf 基于 TCP 协议去做测试,1G的带宽,用iperf去跑TCP测试大概只有300到400兆的带宽,为什么呢?是因为这种长肥网络,它的延迟相对较高,轻微的抖动就会导致丢包和拥塞。TCP的带宽利用率并不高,因为它为了保证传输的质量牺牲了延迟和带宽利用率。其次 TCP不能多路复用,这是一个很重要的概念。因为整个的连接里面会包含很多stream,它们互相之间是不能干扰的。

第二个是KCP以它为代表性的协议还有很多。这类协议的思路就是通过增加冗余的方式去提高整个传输的质量。KCP会增加40%左右的带宽占用,这也是不符合我们的要求的,因为我们要尽可能高地提高带宽利用率。

最后一个比较典型的传输协议是QUIC,经过调研之后,它是最接近于我们需求的协议。因为它的设计思路非常符合流媒体的转发,可以去自定义拥塞控制策略,我们可以在上面做很多优化,而且它还支持优先级的管理。但是QUIC也有一些的局限性,例如 QUIC 的抗弱网能力较弱,同时 QUIC 协议相对与 TCP 协议需要消耗更多的 CPU资源和内存资源。所以它不太适合在服务节点之间进行转发,或者说我们可能会基于QUIC做一些改进和优化。当然我们不想去重新造轮子,因为我们看到了很多传输层协议的不足和局限后,才去决定自研QRTP协议。

2.2 QRT的设计思想

图片

用于QRTN网络内部的传输协议,它的设计思想要满足哪些要求呢?我大概列了一下,首先要业务解耦,它是传输层的,不能跟RTP/RTCP协议绑定。传输策略是可调整的,因为我们为了提高QoE,在不同的场景下会有不同的传输策略。快连接用于提升服务间建联速度,因为这个服务间建联的速度直接影响了转发延迟。

2.3 QRT的设计思想

图片

上图所示是一个传输层协议的三角关系。分布式系统中有一个非常著名的CAP理论,就是一个分布式系统,它不可能同时较好的满足一致性、可用性和分割容错性这三个能力,只能较好地同时满足两个。在传输协议里面也存这样一个三角关系:低成本、低延迟和高质量,在一个传输层的协议中,只能较好地同时满足两个。

举个例子,右下角高质量这个点就是TCP,它为了实现高质量,延迟会很高,成本也很高。然后再看三角左边这条线就是UDP,是一个datagram传输,它没有针对网络中的丢包、拥塞、乱序、抖动做任何对抗机制。所以它的成本非常低,延时非常低,但是质量是没有保证的,是不可控的。基于这个三角,QRTP的设计思想是如上图所示这条绿色的线,我们保证低延迟和高质量。同时又能根据场景去调整参数,在低延迟和高质量之间去做一个权衡。

2.4 QRT协议堆栈

图片

QRTP的协议栈是基于UDP之上的,它既考虑了安全性,又可以在应用层做一些调整。

2.5 QRT解决的两个核心问题

图片

在前面我提到了一条主线:QRTP要解决的一个核心问题,就是要在满足实时传输的前提下,尽可能高地提高带宽利用率。那么我给大家推导一下,把这句话拆成两个部分,就是首先要保证实时传输。那我们考虑一下,在传输层导致实时性变差的原因有哪些呢?

大概有两个点,一个就是拥塞,它会导致时延增大。其次是丢包,它会导致重传,从而导致时延的增大。先抛开丢包不提,那拥塞是什么呢?拥塞其实就是网络超发,也就是说发的内容inflight的 size 大于了整个网络的承载带宽就会产生拥塞,所以拥塞也就是带宽的超发。

然后我们再考虑刚才的下半句:要尽可能地提高带宽利用率。该如何提高带宽率呢?就是要尽量地多发。前半句说我不能超发,后半句又说要尽可能地多发,这是一个既要又要的问题。

所以再往下推导,为了满足设计需求,QRTP协议要实现什么呢?就是要实现带宽的精准预测,也就是一定要能实时地预测一个连接的实际带宽是多少,必须要精准地预测带宽之后,才能去决定该如何去分配传输的流量,也就能够满足实时传输和提高带宽利用率这个需求。

那如何去做带宽预测呢?有研究过拥塞控制的同学应该知道,拥塞控制其实就是去做带宽控制的。我们推导之后,会发现整个QRTP协议想要去提升质量、满足需求,其实我们只要做好拥塞控制这一件事就好了。因为这个协议比较复杂,整个QRTP协议就不在这里赘述了。我着重讲一下它主要解决的问题。然后以这个问题为主线,去分析一下我们是如何去满足这个需求的。刚才推导到要去设计一个好的拥塞控制算法,当然我们还是不想去重新造轮子,所以要参考市面上已有的拥塞控制算法,看一下哪些是适合我们的,哪些不适合。大概的思路就是找到最适合我们的那个,然后在上面做一些调整,去适配我们的业务场景。

2.6 QRT拥塞控制算法演进

图片

可能大家在学习TCP协议的时候,里面大量篇幅都在讲拥塞控制。以TCP为例,TCP里面最经典的就是CUBIC拥塞控制。它的算法是基于丢包的,当它发现网络丢包了,那就是发生了拥塞,然后就要乘性减窗去降低congestion window,来降低发送速率。当降到不丢包之后,再去加性增窗,增到下一次丢包。那就又拥塞了,然后再去降,这样的一个机制,就会导致如上图所示的这条红线。这样的发送速率就会是一个锯齿状的,在一次临界值到下一次临界之间不断地跳。这种方式对于小流量的传输是没有太大问题的,但是对于服务间大流量的并且有实时性要求的媒体转发是不适用的。也就是说TCP这种基于丢包的拥塞控制肯定是要避开的。那比较流行的方式就是基于延迟的,当网络在达到临界饱和的时候,RTT一定会上升的,基于这个理论去选择拥塞控制算法。很幸运看到了 google 发布的BBR拥塞控制算法,我们也实践了一下,确实比较符合媒体之间的转发。同时我们在实践中也发现了BBR算法的一些缺点,或者说一些不足。在用于适配场景的过程中,我们做了一些调优。

2.7 QRT拥塞控制算法演进BBR原理

图片

BBR拥塞控制算法提出了BDP概念,就是可以把网络想象成一个圆柱形的管道。只要用底面积乘以高,大概就是这个管道的容量。所以BDP就是这个容量,它使用最小的RTT乘以最大的带宽去推算出一个BDP值,然后通过BDP去加权控制发送的速率,基本能够精准地预测应该发送多少量。但有一点要记住,它这两个参数:最小RTT 和最大带宽,是不可能同时测量的。因为在带宽没有满的情况下才能测出来最小RTT,然后只有在RTT开始上升的阶段才能测出来最大的带宽。

2.8 QRT拥塞控制算法演进BBR状态

图片

也是由于这个限制,BBR有四个状态,它在开始阶段(Startup)会不断地去增加发送量,然后发送到一个临界值之后,进入到一个最排空的状态。排空状态(Drain)之后,这个时候一般就能测出来最小RTT了,然后进入到对带宽的探测。而对带宽的探测是一个不断的过程。上面这三个过程,如果任何一个阶段RTT超过10秒没有探测到,就会进入到ProbeRTT状态。这个状态是比较麻烦的,因为它认为这个网络可能发生了拥塞,它会进入一个排空的状态,那么我们后面也针对它进行了一些改进。

2.9 QRT拥塞控制算法演进BBR整体流程

图片

我把BBR的工作流程进行了超级简化,可以看到BBR其实在主动地做两件事情。前面讲到TCP的AIMD解决拥塞控制,它是一个非常被动的方法,丢包了我就减,然后没丢包我就增,这种方式会导致什么呢?很多丢包是发生在拥塞之后的,这时再去调整已经晚了。BBR吸取了这个教训,它是非常主动的、非常实时的根据发送的、在inflight状态的、还有ACK回来的事件,主动地探测最大带宽和最小RTT,然后通过这个去结合pacing gain的加权周期不断地去调整它的发送速率,然后达到一个精准的拥塞控制。

2.10 QRT拥塞控制算法演进BBR存在的问题

图片

在BBR整个的实现过程中,它的拥塞控制,可能在场景上比较适合突发流量的发送。但是对于大流量的媒体发送和服务间高带宽的这种场景,可能还是不太适用。

它的不足有两个点,一个是对于高丢包的情况下,比如很多跨国网络,丢包是比较严重的,对于这种高丢包的弱网环境下,它的表现性能是比较差的,带宽利用率很不高。可能百兆的带宽在25%丢包的时候就已经没有可用的带宽利用率了。这个也是因为它设计的场景导致的,后面会讲到。

然后另一个点是前面提到它状态机里面有一个ProbeRTT状态。这个状态是非常保守的,它会让inflight的 size 只有四个packet,整个传输会处于一个拥塞的状态。

2.11 QRT拥塞控制算法优化

图片

针对这两个方面的不足,我们做了一些优化。

把ProbeRTT这个状态进行优化,让它变得更加激进,它的超时时间缩短。然后排空的方式更加的激进,以一个递减的方式去排空。至于这个排空过程的调参,过程比较复杂,但思路大概就是这样的。

另一个优化的点是改进它的弱网对抗性。弱网就是我前面提到的丢包,通常这种丢包是噪声丢包,有一个特点就是在发生噪声丢包的时候,网络的RTT值在统计上是基本不变的。根据这个结论,可以对在噪声丢包的时候给pacing gain做一个动态的补偿,也就是基于对噪声丢包的预判去做一个动态化的pacing gain补偿,这个也是改进BBR的一个很好的思路。我们也是在这上面做了很多的工作,虽然BBR理论相对简单,但改造的过程比较枯燥,同时改造的结果是非常明显的。

2.12 QRT拥塞控制测试数据

图片

上面是我们在百兆网络下做的一组测试, QUIC使用默认的BBR V1拥塞控制,我们自研协议使用改进后的BBR拥塞控制,它们在20毫秒延迟和200毫秒延迟下分别对带宽利用率的使用情况对比。可以看到,淡颜色的QUIC在20%丢包的时候,已经没有带宽率可言了。而我们自研的拥塞控制算法在丢包达到50%的时候,还有30%左右的带宽利用率。这个已经基本符合设计目标了,再优化的话可能复杂度会比较高。

2.13 QRT传输延迟优化

图片

再回到前面提到的QRTP的设计思想,就是在保证实时传输的情况下,尽可能大地提高带宽利用率。那么现在带宽的利用率提上来了之后,就要去考虑实时性。其实只要拥塞控制方法做得好,保证传输正常,能够在一个正常的网络层的RTT里面去传输就已经没问题了。所以只要拥塞控制算法做好之后,时延问题已经解决了一半。另一半问题还是丢包,因为丢包就是会导致时延。

对于一些高带宽高延迟的网络,由于延迟导致的丢包我们要去做一些优化。这时增加冗余时一种非常有效的手段。FEC就是一种增加冗余的方式,有很多协议都是通过FEC去提高带宽传输质量的。

但是FEC有它的缺点,就是开启了FEC之后,带宽占用立马就上来了,实际传输效率就不高了。我们结合实践之后,采取了动态FEC方法,根据丢包和延迟去做一个预判,从而配置 FEC的权重。降低连接建立的耗时也可以降低传输时延,服务之间的建联借鉴了QUIC 中 0-RTT的方式,通过连接预热的方式能够让服务端之间的连接能够在0-RTT的情况下去传输,也就是第一帧数据里面就包含了安全验证和业务数据。

2.14 QRT对卡顿率和端到端延迟的提升

图片

上图所示是对时延优化后的结果。我们用720P@25fps@1500kbps的视频做了延迟优化的验证。可以看到这个数据里面,结合七牛云自研的拥塞控制算法和抗丢包机制后,在50%的丢包情况下,相比与 QUIC 协议900多毫秒的延迟较低到300多毫秒。已经基本符合我们对整个媒体转发的需求了。

2.15 QRT展望

图片

以上主要是围绕我们在设计QRTP协议过程中去解决的一些主要问题,以及如何去做技术决策的。当然,因为QRTP协议是基于提高QoE而产生的。基于QoE提升的技术演进与生俱来就会有一个特点,就是一定要不断地演进。因为QoE的定义就是终端用户对于应用或服务整体的主观可接受程度。这里面有个关键词是主观可接受程度,它是无止境、无上限的,所以我们QRTP的协议也是在不断地演进,大概演进的思路有两个点。

第一个方向是把QRTP协议尝试在接入层去做适配。大家如果调试过WebRTC协议多了的话,会发现这个协议还是有很多的槽点,比如它的带宽预测在弱网环境下非常的不可控。FEC机制比较的臃肿等等。我们想去尝试让QRTP在接入层能够做一些改进,但是这个过程会很复杂。因为之前所有拥塞控制的调窗之类的,都是针对服务端的网络场景去做的。如果针对客户端的接入,在弱网、低带宽的情况,可能还要做更大的一些改进或者一些更高的抽象。

第二个方向就是想把我们在整个QRTP演进过程中独立出来一些模块适配到公有协议上。一个典型的思路就是QUIC的拥塞控制算法是可以自定义的。我们想把优化过的拥塞控制算法移植到QUIC上,在内网中或者在业务上需要使用QUIC的时候,加载我们自己的拥塞控制算法,可以更好地提升传输质量。

03、基于QoE的优化实践

图片

第三个环节结合我们在网络传输层面的一些实践经验,就 QoE优化的来做一个分享。

3.1 不同场景的QoE需求

图片

QoE本身其实是一个主观性的概念,它的主观性可能体现在不同的场景。因为它是综合了服务层面、用户层面以及环境层面的考量。所以用户在不同的使用场景下,对服务提出的要求也是不一样的。也就是说,当脱离了场景,脱离了用户去谈QoE其实都是空谈。所以我们也去充分地调研了在不同场景下,用户对QoE需求的一些侧重点。

举一个比较简单的例子。在跨国的实时通话的时候,用户会对什么比较感兴趣呢?首先是时延,而且音频的时延体验是大于视频的。对于这个问题,我只要保证两个用户之间有一个清晰流畅的实时音频,即使视频出现一些轻微的卡顿、丢帧,其实用户的体验度也不会降低的特别多。所以我们在做网络传输的时候,会优先考虑实时性,以及优先考虑音频应该如何去优化。

3.2 基于场景的QoE优化策略

图片

还有一个是直播场景,前面我们提到了QRTN网络中的一个指标是端到端延迟会小于400毫秒。对于直播场景下小于400毫秒的端到端延迟,观众是不会有太大感知的。即时发布端到订阅端的延时达到整个QRTN网络的最大值,用户也是几乎感觉不到的。也就是说在直播场景下,用户对端到端的延时并不是特别的敏感。其实直播场景,终端用户对播放是否流畅、画面是否清晰的要求是非常高的,所以在直播场景下我们需要做的是去优化流畅度。虽然我们在网络层没有办法去控制基于ROI的编码,但是可以在传输层去尽量地保证传输的流畅度。

3.3 实时会议场景优化实践

图片

这里结合两个场景去看一下如何去做QoE的优化,即在接入策略和分发策略上,是如何去提升用户的QoE体验的。

首先在实时会议场景中,因为会议它是一个虚拟的房间,会分布在整个QRTN网络当中,所以我们要尽量地将同一区域的客户调度到同一个节点。这样会减少这个房间在整个网络中的分布程度,从而降低成本,同时还会提升用户的体验。然后尽量让接入端去开启大、小流。这样如果在订阅端不具备很好的网络情况下可以选择小流,或者在缩略图的情况下使用小流,这样用户体验感会有提升。分发策略方面尽量的短路径,要让路径尽量的短。因为发布者的订阅量是很少的,我们只需要去做一些边缘化的分发和转发就好了。

3.4 互动直播场景优化实践

图片

与此相对的一个比较典型的场景就是互动直播。互动直播这个场景就是两个主播之间去进行互动,然后他们的流会被大量的用户订阅。对于这个场景从QoE体验来看,观众就是他们最终的终端用户,那么观众对于视频的流畅度以及整个的体验的要求很高。那么如何去提升呢?其实就是在发布端去增加冗余。

可以在发布端去做更激进的带宽预测的补偿。因为一般发布者会在比较专业的工作室,网络环境不会太差。然后再去增加 RED 和 FEC 等冗余编码机制。在分发的时候,因为主播整个的流会被大量的用户订阅,所以要首先完成主干节点的汇聚,让这个流尽量地去走主干的节点。这样对于分发的速度和用户的体验也是非常好的。然后在传输策略上尽量去保证传输质量,实时性可能就会被放到后面。

总结一下,首先,介绍了QRTN整个的网络架构。然后又分析了一下这个架构里面的QRTP协议是如何对音画质量进行提升的,最后分享了一些经验。其实所有的话题都是在围绕如何去提升用户的体验度,如何去提升QoE的质量。这个过程是没有上限的,我们也一直在路上,一直在探索。

谢谢大家,以上就是我本次分享的全部内容。


图片


图片

推荐阅读
关注数
4162
内容数
363
分享音视频相关技术干货、产品研究与行业趋势
目录
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
安谋科技学堂公众号
关注安谋科技学堂
实时获取安谋科技及 Arm 教学资源
安谋科技招聘公众号
关注安谋科技招聘
实时获取安谋科技中国职位信息