每天有数百万次视频通话,或“给妈妈打电话!”

从用户的角度来看,呼叫服务看起来非常简单:您转到另一个用户的页面,您打电话,他接听电话,与他通话。 外面似乎一切都很简单,但是很少有人知道如何提供这样的服务。 但是Alexander Tobol( alatobol )不仅知道,而且乐于分享他的经验。



进一步了解HighLoad ++ Siberia上的报告的文本版本,您将从中学习:

  • 视频通话服务如何在后台运行?
  • 突破NAT有多美-对于需要点对点连接的游戏专家来说,这将很有趣;
  • WebRTC的工作原理,包括哪些协议;
  • 如何通过BigData调整WebRTC。


关于演讲者: Alexander Tobol在ok.ru上负责视频和磁带平台的开发。

视讯通话记录


第一个视频通话设备出现在1960年,它被称为picherphone,它使用专用网络,而且非常昂贵。 2006年,Skype将视频通话添加到其应用程序中。 在2010年,Flash支持RTMFP协议,我们在Odnoklassniki发起了Flash视频通话。 Chrome在2016年停止了对Flash的支持,而在2017年8月,我们重新启动了使用这项新技术的通话,今天我将讨论这一新技术。 完成服务后,再过六个月,我们成功完成的呼叫数量大幅度增加。 最近,我们在通话中也有屏蔽。


建筑与传统知识


由于我们在社交网络中工作,因此我们没有技术任务,也不知道传统知识是什么。 通常,整个想法只适合一页,看起来像这样。


用户想使用Web或iOS / Android应用程序呼叫其他用户。 另一个用户可能有多个设备。 呼叫到达所有设备,用户在其中一个设备上接听电话,然后通话。 一切都很简单。

技术指标


为了提供高质量的呼叫服务,我们需要了解要跟踪的特征。 我们决定从寻找最让用户烦恼的方式开始。

如果用户拿起电话并被迫等待直到建立连接,肯定会感到烦恼。


如果通话质量不佳,用户会感到烦恼-某些事物被打断,视频散落,声音冒泡。


但是大多数用户对通话的延迟感到恼火。 延迟是通话的重要特征之一。 对话的等待时间约为5秒,因此绝对不可能进行对话。


我们为自己确定了可接受的特征:

  • 开始 -我们认为最好在一秒钟内开始通话。 即 用户应答后进行连接,连接时间不应超过1秒。
  • 质量是一个非常主观的指标。 例如,您可以测量信噪比(SNR),但是仍然缺少帧和其他伪像。 我们比较主观地评估质量,然后评估用户的满意度。
  • 延迟应小于0.5秒。 如果延迟超过0.5秒,则您已经听到延迟并开始互相打扰。



Polycom是我们办公室中安装的会议系统。 我们的平均Polycom延迟约为1.3秒。 有了这样的延迟,您并不总是彼此了解。 如果延迟增加到2秒,则无法进行对话。


由于我们已经启动了该平台,因此我们大致预期每天将有100万个呼叫。 这是一千个并行的呼叫。 如果所有呼叫都是通过服务器启动的,则每个呼叫将有1000兆比特的呼叫。 只需1吉比特/秒,一台铁服务器就足够了。

互联网与TTX


有什么可以阻止您实现如此出色的功能? 上网!


在Internet上,存在无法克服的问题,例如往返时间(RTT),可变带宽,NAT。

以前,我们测量用户网络中的传输速度。


我们按连接类型将其细分,查看了平均RTT,数据包丢失,速度,并决定对每个网络的平均值测试呼叫。


互联网上还有其他麻烦:

  • 数据包丢失 -我们测量了0.6%的随机数据包丢失(我们没有考虑过多数据包的拥塞数据包丢失)。
  • 重新排序 -您以相同的顺序发送数据包,然后网络将它们重新排序。
  • 抖动 -以一定的间隔发送视频或音频流,例如,由于网络设备上的缓冲,数据包在客户端以捆绑的形式汇聚在一起。
  • NAT-事实证明,超过97%的用户使用NAT。 我们将讨论原因,内容和方式。



考虑一个简单的示例,上面列出的网络设置。

我从我的办公室访问了新西伯利亚国立大学的网站,并收到了一个奇怪的通知。


在此示例中,平均抖动为30 ms,即相邻ping时间之间的平均间隔约为30 ms,平均ping为105 ms。

通话中重要的是什么,我们为什么要争取p2p?


显然,如果我们设法在试图在圣彼得堡彼此通信的用户之间建立p2p连接,而不是通过位于新西伯利亚的服务器进行通信,则将为该服务节省大约100毫秒的往返路程和流量。

因此,本文的大部分内容都专门介绍如何制作好的p2p。

历史或遗产


正如我所说,自2010年以来我们一直提供电话服务,现在我们重新启动了该服务。


在2006年Skype成立之初,Flash收购了Amicima,后者制造了RTMFP。 Flash已经具有RTMP,原则上可以用于呼叫,并且通常用于流式传输。 Flash随后打开了RTMP规范。 我想知道为什么他们需要RTMFP? 在2010年,我们使用了RTMFP。

比较呼叫协议和实际流协议的要求,看看边界在哪里。


RTMP更像是一种视频流协议。 它使用TCP,具有累积延迟。 如果您的互联网连接良好,则可以拨打RTMP。

尽管只有一个字母不同,但RTMFP协议是UDP协议。 它没有缓冲问题-TCP上的问题; 它被剥夺了行头阻塞的功能-这是您丢失一个数据包的时候,TCP直到需要再次发送丢失的数据包时才返回以下数据包。 RTMFP能够处理NAT,并且正在更改客户端IP地址。 因此,我们于2010年在RTMFP上启动了网络。


直到2011年,WebRTC初稿才出现,但尚未完全投入使用。 2012年,我们开始支持iOS / Android上的通话,然后又发生了其他事情,2016年,Chrome不再支持Flash。 我们必须做点什么。


我们研究了所有VoIP协议:一如既往,为了做某事,我们首先关注竞争对手。

竞争对手或从哪里开始


我们选择了最受欢迎的竞争对手:Skype,WhatsApp,Google Duo(类似于环聊)和ICQ。

首先,我们测量了延迟。


这很容易做到。 上图是其中的照片:

  • 秒表(请参阅左上角的电话),其中显示了时间(03:08)。
  • 附近的电话拨打电话并将第一个电话作为视频。 从图片进入手机相机的那一刻起,您就看到了它,大约花了100毫秒。
  • 呼叫另一部电话(白色),再通话一次。 Google Duo的延迟约为310毫秒。

我不会透露所有卡,但是我们确保这些设备无法建立p2p连接。 当然,测量是在不同的网络中进行的,这只是一个例子。


Skype仍然会中断一点。 事实证明,对于Skype,如果无法连接p2p,则延迟为1.1 s。

我们的测试环境很复杂。 我们在不同的条件(EDGE,3G,LTE,WiFi)下进行了测试,考虑到信道是不对称的,我给出了所有测量值的平均值。


为了估算电池消耗,处理器负载以及其他所有因素,我们决定只用高温计测量手机温度,并假设这是手机GPU上每个处理器和电池的平均负载。 原则上,将热手机带入耳中甚至握在手中是非常不愉快的。 在用户看来,现在该应用程序将耗尽其整个电池。


结果是:

  • 延迟最慢是ICQ和Skype,最快的是Telegram。 这不是一个完全正确的比较,因为Telegram没有视频通话,但是它们的音频延迟最小。 WhatsApp(大约200毫秒)和环聊-390毫秒效果很好。
  • 按温度来看 Telegram在没有视频的情况下吃得最少,而在Skype上则最多。
  • 响应时间而言,Telegram建立连接时间最长,而最快的是WhatsApp和Google Duo。

太好了,我们有一些指标!


我们在不同的网络,不同的分支和其他所有条件下测试了视频和语音的质量。 结果,我们得出的结论是, 最高质量的视频在Google Duo上,语音在Skype上 ,但这是在已经存在失真的“不良”网络中。 一般来说,每个人的工作水平一般。 WhatsApp的图片最模糊。

让我们看看它全部实现了。


Skype具有自己的专有协议,其他所有人都使用WebRTC的修改,或者通常直接使用WebRTC。 环聊,Google Duo,WhatsApp,Facebook Messenger可以与网络一起使用,并且都具有WebRTC。 它们是如此不同,具有不同的特征,并且都具有一个WebRTC! 因此,您需要能够正确烹饪。 另外还有Telegram,ICRT,由WebRTC的某些部分负责音频部分,还有ICQ,它使WebRTC了很长时间,并且继续发展自己的方式。

WebRTC 建筑学




WebRTC意味着存在一个信令服务器,这是客户端之间的中介,用于在客户端之间建立p2p连接期间交换消息。 建立直接连接后,客户端开始彼此交换媒体数据。

WebRTC 演示版


让我们从一个简单的演示开始。 建立WebRTC连接仅需5个简单步骤。

详细的示例代码
1. // Step #1: Getting local video stream and initializing a peer connection with it (both caller and callee) 2. 3. var localStream = null; 4. var localVideo = document.getElementById('localVideo'); 5. 6. navigator 7. .mediaDevices 8. .getUserMedia({ audio: true, video: true }) 9. .then(stream => { 10. localVideo.srcObject = stream; 11. localStream = stream; 12. }); 13. 14. var pc = new RTCPeerConnection({ iceServers: [...] }); 15. 16. localStream 17. .getTracks() 18. .forEach(track => pc.addTrack(track, localStream)); 19. 20. // Step #2: Creating SDP offer (caller) 21. 22. pc.createOffer({ offerToReceiveAudio: true, offerToReceiveVideo: true }) 23. .then(offer => signaling.send('offer', offer)); 24. 25. // Step #3: Handling SDP offer and sending SDP answer (callee) 26. 27. signaling.on('offer', offer => { 28. pc.setRemoteDescription(offer) 29. .then(() => pc.createAnswer()) 30. .then(answer => signaling.send('answer', answer)) 31. }); 32. 33. // Step #4: Handling SDP answer (calleer) 34. 35. signaling.on('answer', answer => pc.setRemoteDescription(answer)); 36. 37. // Step #5: Exchanging ICE candidates 38. 39. pc.onicecandidate = event => signaling.send('candidate', event.candidate); 40. 41. signaling.on('candidate', candidate => pc.addIceCandidate(candidate)); 42. 43. // Step #6: Getting remote video stream (both caller and callee) 44. 45. var remoteVideo = document.getElementById('remoteVideo'); 46. 47. pc.onaddstream = event => remoteVideo.srcObject = event.streams[0]; 


它说如下:

  1. 拍摄视频并建立对等连接,传输某种iceServer(尚不清楚它是什么)。
  2. 创建一个SDP提议并将其发送给信令,并且信令WebRTC不会以任何方式为您实现。
  3. 然后,您需要为来自信号传递的那个包装一个包装,这也不是WebRTC的一部分。
  4. 进一步交换一些候选人。
  5. 最终获得远程视频流。

让我们弄清楚那里正在发生什么以及实现自我所需的东西。


我们从下往上看图片。 浏览器中已经内置了一个WebRTC库,Chrome,Firefox等支持该库。您可以在Android / iOS下构建它,并通过描述会话本身的API和SDP(会话描述协议)与之通信。 下面我将告诉您其中包含的内容。 要在您的应用程序中使用此库,必须通过信令在订户之间建立连接。 信令也是您必须自己编写的服务,WebRTC不提供。

在本文的进一步内容中,我们将依次讨论网络,然后是视频/音频,最后我们将编写信号。

WebRTC网络或p2p(实际上是c2s2c)


建立p2p连接似乎很简单。


我们有爱丽丝和鲍勃想要建立p2p连接。 他们使用自己的IP地址,拥有一个信令服务器,它们都连接到该服务器,并且可以通过它们交换这些地址。 他们交换地址,哦! 他们有相同的地址,出了点问题!


实际上,这两个用户最有可能坐在Wi-Fi路由器后面,这是他们的本地灰色IP地址。 路由器为他们提供了诸如网络地址转换(NAT)之类的功能。 她如何工作?


您有一个灰色的子网和一个外部IP地址。 您从灰色地址将数据包发送到Internet,NAT将灰色地址替换为白色,并记住映射:它从哪个端口发送,到哪个用户以及与哪个端口匹配。 当返回数据包到达时,它将通过此​​映射进行解析并将其发送给发送方。 一切都很简单。

下图显示了它在我的位置的外观。


这是我的内部IP地址和路由器的地址(顺便说一下,也是灰色的)。 如果您跟踪并查看路由,我们将看到我的Wi-Fi路由器:一个灰色提供商地址包和一个外部白色IP。 因此,实际上,我将有两个NAT:一个是我在Wi-Fi上,另一个是从提供商那里,除非我当然为自己购买了专用的外部IP地址。

NAT之所以流行是因为:

  • 许多IPv4仍然丢失,并且地址不足;
  • NAT似乎可以保护网络。
  • 这是路由器的标准功能:连接到Wi-Fi,那里有NAT,它可以工作。

因此,只有3%的用户使用外部IP,其余所有用户都通过NAT。

NAT使您可以安全地访问任何白色地址。 但是,如果您没有去任何地方,那么没人能来找您。


建立p2p连接是一个问题。 实际上,如果Alice和Bob都在NAT后面,则它们无法相互发送数据包。

WebRTC具有STUN协议来解决此问题。 建议部署一个STUN服务器。 然后,爱丽丝连接到STUN服务器,获取她的IP地址,并通过信令将其发送给鲍勃。 鲍勃还获得了他的IP地址,并将其发送给爱丽丝。 它们相互发送数据包,从而突破了NAT。


问题 :Alice有一个特定的端口处于打开状态,此端口已经突破了NAT /防火墙,而Bob处于打开状态。 他们知道彼此的地址。 爱丽丝尝试将数据包发送给鲍勃;他将数据包发送给爱丽丝。 您认为他们会说话还是不会?

实际上,无论如何您都是正确的,结果取决于用户拥有的NAT对的类型。


网络地址转换


NAT有4种类型:

  1. 全锥NAT;
  2. 受限锥NAT;
  3. 端口受限锥NAT;
  4. 对称NAT

在基本版本中,爱丽丝向STUN服务器发送一个数据包,她打开了一些端口。 鲍勃以某种方式发现了她的端口并发送了返回包。 如果这是全锥NAT (最简单的NAT ,它只是将外部端口映射到内部端口),那么Bob将能够立即向Alice发送一个数据包,建立连接,然后他们才能通话。


下面是交互方案:Alice从某个端口向STUN端口发送一个数据包,STUN用她的外部地址应答她。 STUN可以从任何地址进行响应,如果它是全锥NAT,它仍然会穿透NAT,而Bob可以响应相同的地址。


对于受限锥NAT,情况要复杂一些。 它不仅记住您需要映射到内部地址的端口,而且还记住您访问的外部地址。 也就是说,如果您仅建立了与IP STUN服务器的连接,则网络上没有其他人可以回答您,那么Bob的数据包将无法到达。


这个问题如何解决? 在一个简单的方案中(如下图所示):Alice向STUN发送一个数据包,他用IP应答她。 只要是受限锥体NAT,STUN都可以从任何端口响应它。 鲍勃无法回答爱丽丝,因为他有一个不同的地址。 爱丽丝知道鲍勃的IP地址,然后用一个数据包进行响应。 她向Bob打开NAT,Bob回答了她。 他们好了。


稍微复杂一点的选项是“ Port受限锥NAT” 。 完全一样,只有STUN应该完全从访问它的端口进行响应。 一切也将工作。

最有害的是对称NAT


最初,一切都以完全相同的方式工作-爱丽丝将数据包发送到STUN服务器,它从相同的端口进行响应。 鲍勃无法回答爱丽丝,但她将数据包发送给了鲍勃。 在这里,尽管事实是Alice向端口4444发送了一个数据包,但映射为她分配了一个新端口。 对称NAT的不同之处在于,在建立每个新连接时,每次在路由器上发布新端口时。 因此,鲍勃在爱丽丝前往STUN的端口中跳动,无法连接。

相反,如果Bob拥有开放的IP地址,则Alice可能会来找他,他们将建立连接。

所有选项都收集在下表中。


它表明,几乎所有的事情都是可能的,除非我们尝试通过对称NAT与另一端的端口受限锥形NAT或对称NAT建立连接。


正如我们所发现的,就延迟而言,p2p对我们而言是无价的,但是如果无法安装,则WebRTC会为我们提供TURN服务器。 当我们意识到无法安装p2p时,我们可以连接到TURN,它将代理所有流量。 但是,与此同时,您需要为流量付费,并且用户可能会有一些额外的延迟。

练习


Google有免费的STUN服务器。 您可以将它们放在库中,它将起作用。

TURN服务器具有凭据(登录名和密码)。 很可能,您将不得不自己筹集资金,很难找到自由。

Google提供的免费STUN服务器示例:

  • stun:stun.l.google.com:19302
  • stun:stun1.l.google.com:19302
  • stun:stun2.l.google.com:19302
  • stun:stun3.l.google.com:19302

还有一个免费的TURN服务器,其密码为:url:'turn:192.158.29.39:3478?Transport = udp',凭据:'JZEOEt2V3Qb0y27GRntt2u2PAYA =',用户名:'28224511:1379330808'。

我们使用coturn


结果,34%的流量通过p2p连接传递,其他所有内容都通过TURN服务器代理。

STUN协议中还有什么有趣的东西?


STUN允许您确定NAT的类型。


滑动 链接

发送数据包时,可以指示要从同一端口接收响应,或者要求STUN从其他端口,其他IP甚至是其他IP和端口来响应。 因此, 对于对STUN服务器的4个查询,您可以确定NAT的类型


我们计算了NAT的类型,发现几乎所有用户都具有对称NAT或端口​​受限锥形NAT。 因此,事实证明只有三分之一的用户可以建立p2p连接。

您可能会问,如果您能直接从Google那里获得STUN并将其放入WebRTC,那么为什么我要告诉您所有这些信息,看来一切都会正常进行。

因为您实际上可以自己确定NAT的类型。


这是一个指向 Java应用程序的链接 ,该链接没有任何棘手的问题:它仅ping通不同的端口和不同的STUN服务器,并查看最终看到的端口。 如果您具有开放式全锥NAT,则STUN服务器将具有相同的端口。 使用受限锥体NAT,每个STUN请求将具有不同的端口。


使用对称NAT,事实证明在我的办公室中是这样。 有完全不同的端口。

但是有时会有一个有趣的模式,对于每个连接,端口号都会增加一个。


即,许多NAT配置为使它们以恒定的速率增加或减少端口。 可以找到此常数,从而突破对称NAT。


因此,我们突破了NAT-我们转到一台STUN服务器,再转到另一台STUN服务器,查看差异,进行比较,然后再次尝试以递增或递减的方式提供端口。 就是说,爱丽丝(Alice)试图向鲍勃(Bob)提供已经调整为常数的端口,并知道下一次就是这样。


因此,我们设法焊接了另外12%的点对点

实际上,有时具有相同IP的外部路由器的行为相同。 因此,如果您收集统计信息,并且如果对称NAT是提供商的功能而不是用户的Wi-Fi路由器的功能,则可以预测增量,并立即将其发送给用户,以便他使用它并且无需花费太多时间确定它。

CDN中继或如果无法建立P2P连接该怎么办


如果我们仍然使用TURN服务器并且不是在p2p中工作,而是在实模式下通过服务器传输所有流量,那么我们仍然可以添加CDN。 除非您当然有游乐场。 我们有自己的CDN网站,因此对我们来说非常简单。 但是有必要确定将人发送到哪里更好:将其发送到CDN站点,或者发送到莫斯科的频道。 这不是一项非常琐碎的任务,因此我们这样做:

  1. 意外地发布给莫斯科站点的一些用户,一些-远程。
  2. 我们收集了有关用户IP,服务器和网络特性的统计信息。
  3. 通过maxMind,我们对子网进行了分组,查看了统计信息,并能够通过IP了解哪个用户具有最接近的TURN服务器进行连接。



新西伯利亚有CDN。 如果通过莫斯科为您提供一切服务,那么RTT的99%就是1.3秒。 通过CDN,一切工作都快得多(0.4秒)。

使用p2p连接而不使用服务器总是更好吗? 一个有趣的示例是两个克拉斯诺亚尔斯克(Krasnoyarsk)提供程序Optibyte和Mobra(名称可能已更改)。 由于某种原因,它们之间在p2p上的连接比通过MSK差得多。 他们可能不是彼此的朋友。


我们分析了所有这些情况,将用户随机发送到p2p或通过MSK,收集了统计数据并建立了预测。 我们知道统计信息需要更新,因此对于某些用户,我们特别建立了不同的连接来检查网络中是否发生了更改。

我们测量了诸如往返时间,数据包丢失,带宽之类的简单特征-仍然需要学习如何正确比较它们。


如何理解哪个更好:2 Mbit / s的Internet,400 ms的RTT和5%的丢包率或100 Kbit / s,100 ms的延迟和很少的丢包率?

没有确切的答案,视频通话质量的评估是非常主观的。 因此,通话结束后,我们要求用户评估星号的质量,并根据结果设置常数。 事实证明,例如,RTT小于300毫秒-不再重要,比特率更为重要。

在Android和iOS上具有更高的用户评分。 可以看出,iOS用户更倾向于放置一个单位,并且更经常放置五个单位。 我不知道为什么可能是平台的细节。 但是,我们沿着这些常数拉动了常数,因此,在我们看来,它具有良好的性能。

回到本文的大纲,我们仍在讨论网络。

连接设置是什么样的?


我们将STUN和TURN服务器发送到PeerConnection(),建立连接。 爱丽丝找出她的IP,发送给信令; 鲍勃了解爱丽丝的IP。 爱丽丝获得鲍勃的IP。 他们交换数据包,可能会突破NAT,可能会设置TURN并进行通信。


在前面讨论的建立连接的5个步骤中,我们确定了服务器,弄清楚了从何处获得它们,而ICE候选者是我们通过信令交换的外部IP地址。 如果客户端的内部IP地址在一个Wi-Fi范围内,也可以尝试突破。

让我们继续看视频部分。

视音频


WebRTC支持一组特定的视频和音频编解码器,但是您可以在其中添加自己的编解码器。 基本上受H.264和VP8视频支持 。 VP8是一种软件编解码器,因此会消耗大量电池。 H.264并非在所有设备上都可用(它通常是本机),因此默认优先级在VP8上。

在SDP(会话描述协议)内部,存在编解码器协商:当一个客户端发送其编解码器列表时,另一客户端优先发送其自己的编解码器列表,并且他们同意将使用哪些编解码器进行通信。 如果需要,您可以更改VP8和H.264编解码器的优先级,因此,您可以在某些本地264设备上节省电池。 这是如何完成此操作的示例 。 我们这样做了,在我们看来,用户并没有抱怨质量,但是与此同时,电池电量的消耗却少得多。

对于音频,WebRTC具有OPUS或G711 ,通常所有OPUS都可以正常工作,而无需执行任何操作。

以下是使用10分钟后的温度测量值。


显然,我们测试了不同的设备。 这是一个iPhone的示例,在该应用程序上,OK应用程序使用的电池最少,因为设备的温度最低。

如果使用WebRTC,则可以启用的第二件事是, 当连接非常差时自动关闭视频


如果您的速率低于40 Kbps,则视频将关闭。 您只需在创建连接时选中该复选框,即可通过界面配置阈值。 您还可以设置最小和最大启动电流比特率。


这是非常有用的事情。 如果在建立连接时事先知道要使用什么比特率,则可以转移该比特率,呼叫将从该比特率开始,并且您无需调整比特率。 另外,如果您知道自己的频道经常出现丢包或带宽减少的情况,那么最大值也可能会受到限制。

WhatsApp可以处理非常肥皂的视频,但延迟很小,因为它可以从上方积极压缩比特率。

我们使用MaxMind收集统计数据并将其映射。


这是我们在俄罗斯不同地区拨打电话所用的近似起始质量。

发信号


如果要打电话,很可能必须编写此部分。 有各种各样的陷阱。 回想一下它的外观。


有一个带有信令的应用程序可以与SDP连接和交换,下面的SDP是WebRTC的接口。

这是简单的信令看起来像的样子:


爱丽丝打电话给鲍勃。 它例如通过Web套接字连接进行连接。 鲍勃在他的手机或浏览器上按了一个推,或者通过某种开放式连接,通过网络套接字进行连接,然后电话开始在他的口袋里响了。 鲍勃拿起电话,爱丽丝向他发送了自己的编解码器和她支持的其他WebRTC功能。 鲍勃也回答了她,然后他们交换了所见的候选人。 哇,打个电话!

这一切看起来都很长。 首先,在建立网络套接字连接之前,直到推入按钮生效为止,Bob的电话不会在他的口袋里响。 爱丽丝会一直等着,想想鲍勃在哪里,为什么他不接电话。 确认后,这需要花费几秒钟,即使连接良好也可能需要3-5秒,而连接不良则需要10秒。

我们必须为此做点什么! 您会告诉我,一切都可以非常简单地完成。



如果您的应用程序已经打开了连接,则可以立即发送推送以建立连接,连接到所需的信令服务器并立即开始进行呼叫。

然后再进行优化。 即使电话仍在您的口袋中响起并且您还没有拿起电话,您实际上也可以交换有关受支持的编解码器,外部IP地址的信息,开始发送空的视频数据包,并且通常所有内容都会被预热。 拿起电话后,一切都会很好。

我们这样做了,似乎一切都很酷。 但是没有


第一个问题是用户经常取消呼叫。 他们单击“呼叫”并立即取消。 因此,推送进入呼叫,并且用户消失(他失去了互联网或其他东西)。 同时,某人的电话铃响了,他拿起电话,并且不希望他在那里。 因此,为了尽快开始调用而进行的原始优化实际上是行不通的。


快速取消通话会产生第二种有害的情况。 如果您在服务器上生成会话的ID,则需要等待响应。 也就是说,您创建一个呼叫,获取一个ID,然后您才能做您想做的任何事情:发送数据包,交换,包括取消呼叫。 这是一个非常糟糕的故事,因为事实证明,在响应到达之前,您实际上无法从客户端取消任何操作。 因此,最好在客户端上生成某种类型的ID,例如GUID,并说您已开始呼叫。 人们经常这样做:他们打电话,取消并立即再次打电话。 为了防止这种情况弄乱,请执行GUID并提交。


似乎什么都没有,但是还有另一个问题。 如果鲍勃有两部手机,或者浏览器保持打开状态,那么如果他突然从另一个设备接听电话,我们整个魔术计划就无法交换数据包,建立连接。

怎么办 让我们回到基本的简单慢速信令方案并对其进行优化,并稍早发送推送。 用户将开始更快地连接,但这将节省一些费用。


他拿起电话并开始交换后,最长的时间该怎么办?


您可以执行以下操作。 很明显,爱丽丝已经知道她所有的编解码器,并且可以将它们发送到鲍勃的两部电话中。 她可以解析所有IP地址并将其发送给信令,这将使它们保持在队列中,但不会发送给任何客户端,以便他们可以提前开始连接到她。

鲍勃能做什么?收到报价后,他可以查看其中有哪些编解码器,生成自己的编解码器,编写自己的内容并发送。但是Bob有两部电话,并且它们具有不同的编解码器协商,因此发信号将自己保留所有内容,并且会排队等待,直到他发现他们将在哪部设备上接听电话。候选人还将生成两个设备并将其发送给信令。

因此,在不同设备上,信令具有来自Alice的一个消息队列和来自Bob的多个消息队列。他将所有这些存储起来,一旦他们在其中一个设备上拿起电话,他就简单地扔掉已经准备好的整套程序包。

它的工作速度非常快。我们使用这种算法进行管理,以达到类似于Google Duo和WhatsApp的特征。


您可能会想出更好的东西。例如,保留几个队列,而不是用于发送信号,而是将其发送给客户端,然后说出哪个数量,但最有可能的收益很小。我们决定停在那里。

还有什么其他问题在等着您呢?


有一个回叫之类的东西:一个回叫,另一个回铃。如果他们不尝试竞争,那就太好了-在信令级别添加一条命令,说如果有人第二名,您只需简单地接听电话并立即拿起电话就需要切换到模式。


碰巧网络消失了,消息丢失了,所以一切都需要通过队列来完成。也就是说,您必须在客户端上具有调度队列。仅当服务器确认已处理完从客户端发送的消息后,才应从队列中删除它们。服务器还具有发送队列和确认队列。

因此,在考虑到我们拥有24/7全天候服务的情况下,所有这一切都在我们内部实现,我们希望能够丢失数据中心,转移和更新软件版本。


链接 到幻灯片上的视频和参考文本版本

客户端通过Web套接字连接到某个负载均衡器,然后将其发送到不同数据中心中的信令服务器,不同的客户端可以到达不同的服务器。在Zookeeper中,我们进行了领导者选举,该领导者定义了现在管理该对话的信令服务器。如果服务器不是此对话的负责人,他只是将所有消息扔给另一个。

接下来,我们使用一些分布式存储,在Cassandra之上NewSQL使用什么真的无关紧要。您可以保存任何位置上正在发送信号的所有队列的状态,以便如果发送信号的服务器消失,电源中断或发生其他情况,Leader Election在Zookeeper上运行,另一台成为领导者的服务器启动,从数据库中恢复所有队列消息并开始发送。

该算法如下所示:

  • 客户端发送一些消息,比如说它的外部IP到信令
  • 信令接受,写入数据库。
  • 在他知道一切都已到来之后,他回复说他收到了此消息。
  • 客户端从其队列中删除此消息。

所有包装均提供唯一编号,以免混淆。

从数据库的角度来看,我们在Cassandra上使用了一个插件,该插件使您可以在数据库上进行交易(视频就是这样)。

因此,您了解到:

  • 什么是iceServer以及如何传输它们;
  • 什么是会话描述协议;
  • 必须生成并发送给另一端;
  • 必须从信令中获取并转移到另一侧的WebRTC,并与外部IP地址进行交换;
  • 并开始发送视频!



我们已经收到:

  • 延迟低于市场平均水平的看涨期权;
  • 我们没有给手机加热太多;
  • 顶级应用程序中的响应时间。

哇!


安全性 WebRTC的中间攻击者


我们来谈谈WebRTC的中间攻击中的人。实际上,WebRTC是一个非常困难的协议,因为它基于RTP(至今仍是1996年),而SDP则来自SIP于1998年。


在底部,一个巨大的清单是构成RTP WebRTC的一堆RFC和其他RTP扩展。

列表中的前两个有趣的RFC-其中一个将音频级别添加到数据包中,另一个则表示以包形式公开传输音频级别并对其进行加密是不安全的。因此,在交换SDP时,重要的是要知道客户端支持哪些扩展集。甚至有几种拥塞算法,几种用于恢复丢失的数据包的算法,几乎所有内容。

WebRTC的历史很复杂。最初的草案发布于2011年,2013年Firefox支持此协议,然后于2014年开始在iOS / Android上构建Opera。总的来说,它已经发展了很多年,但仍然不能解决一个有趣的问题。


当爱丽丝(Alice)和鲍勃(Bob)连接到信令时,他们将使用此通道,建立DTLS握手和安全连接。一切都很好,但是如果事实证明不是我们的信号,那么原则上,中间人有机会与爱丽丝和鲍勃一起“赚钱”,以阻止所有流量并窃听那里发生的事情。


如果您拥有高度信任的服务,那么,当然,您肯定需要使用HTTPS,WSS等。还有另一个有趣的解决方案-ZRTP,例如,Telegram就使用了它。

建立连接后,许多人都在Telegram上看到了表情符号,但很少有人使用它。实际上,如果您告诉朋友您拥有什么表情符号,他会验证他的表情符号完全相同,那么您绝对可以保证安全的p2p连接。

如何运作?


在所有这些协议中,最初都使用常规的Diffie-Hellman算法。爱丽丝会生成一些数字,然后将所有数字发送给鲍勃。 Bob还会生成一个随机数,并将其发送给Alice。通过这种交换,爱丽丝和鲍勃得到了一定的大数K,中间那个听了他们的整个频道的男人对此一无所知,根本无法猜测。

当戴夫(Dave)出现在爱丽丝(Alice)和鲍勃(Bob)之间时,他们与他交换相同的密钥分别获得K 1和K 2。无法追踪中间人的身影。然后应用这样的技巧。这些键是K 1和K 2Dave肯定会有所不同,因为Alice和Bob随机生成密钥。我们只是从K 1和K 2中获取一些哈希值,然后将其显示在表情符号中:在苹果,梨子中-在任何东西中,人们都简单地用声音呼叫看到的图片。由于您可以通过语音识别彼此,并且如果这些图片不同,则您之间可能有某人,也许他在听您说话。

结果


  • 我们“挖掘”了NAT类型并突破了对称NAT。
  • 经过统计评估,更好:p2p或中继,质量,CDN;并从用户角度提高了星星的质量。
  • 更改了编解码器的优先级,节省了一些电量。
  • 信令延迟最小。



该图显示,首先是对RTMFP的旧呼叫,然后当我们切换到WebRTC时,出现了轻微故障,然后峰值上升。并非一切都马上解决!结果,现在保持的呼叫数量增加了4倍。

简单指示


如果您不需要所有这些,则有一个非常简单的说明:


一切都会响起,而且响起还不错。

报告后聆听问题的答案


HighLoad++ 4-.

, . , 19 (10 9 -) , - . , , .

Source: https://habr.com/ru/post/zh-CN428217/


All Articles