1日あたり100万件のビデオ通話または「お母さんに電話してください!」

ユーザーの観点から見ると、コールサービスは非常にシンプルに見えます。別のユーザーのページに移動し、電話をかけ、電話を取り、話をします。 外ではすべてがシンプルに思えますが、そのようなサービスの作り方を知っている人はほとんどいません。 しかし、Alexander Tobol( alatobol )は知っているだけでなく、喜んで彼の経験を共有しています。



さらに、HighLoad ++ Siberiaのレポートのテキストバージョンについて学習します。



スピーカーについて: Alexander Tobolは、ok.ruでビデオおよびテーププラットフォームの開発をリードしています。

ビデオ通話履歴


ビデオコール用の最初のデバイスは1960年に登場し、ピッカーフォンと呼ばれ、専用ネットワークを使用し、非常に高価でした。 2006年、Skypeはアプリケーションにビデオ通話を追加しました。 2010年、FlashはRTMFPプロトコルをサポートし、OdnoklassnikiでFlashビデオコールを開始しました。 2016年、ChromeはFlashのサポートを停止し、2017年8月に新しいテクノロジーを使用して通話を再開しました。これについては、今日説明します。 サービスを終了すると、さらに6か月間、正常に完了した通話が大幅に増加しました。 最近、コールにもマスクがあります。


アーキテクチャとTK


私たちはソーシャルネットワークで働いているため、技術的なタスクはなく、TKが何であるかはわかりません。 通常、アイデア全体が1ページに収まり、次のようになります。


ユーザーは、WebまたはiOS / Androidアプリケーションを使用して他のユーザーに電話をかけたいと考えています。 別のユーザーが複数のデバイスを持っている可能性があります。 通話はすべてのデバイスに届き、ユーザーはデバイスの1つで電話を取り、話します。 すべてがシンプルです。

技術仕様


質の高いコールサービスを実現するには、追跡する特性を理解する必要があります。 私たちは、ユーザーが最も悩むものを探すことから始めることにしました。

ユーザーが電話を取り、接続が確立されるまで待たされると、ユーザーは間違いなくイライラします。


通話品質が悪い場合、ユーザーはいらいらします-何かが中断され、ビデオが散らばり、音が泡立っています。


しかし、ほとんどのユーザーは通話の遅延に悩まされています。 遅延は、呼び出しの重要な特性の1つです。 5秒程度の会話の待ち時間があるため、対話を行うことは絶対に不可能です。


許容可能な特性を以下のように決定しました。




Polycomは、オフィスにインストールされている会議システムです。 平均的なポリコムレイテンシは1.3秒程度です。 このような遅延があると、常にお互いを理解できるとは限りません。 遅延が2秒に増加すると、ダイアログは使用できなくなります。


すでにプラットフォームを立ち上げていたので、1日あたり100万件のコールがあるとおおよそ予想していました。 これは並行して1,000回の呼び出しです。 すべての呼び出しがサーバーを介して行われる場合、呼び出しごとに1,000メガビットの呼び出しがあります。 これはわずか1ギガビット/秒で、1台の鉄製サーバーで十分です。

インターネットとTTX


そのようなクールな機能を達成するのを妨げるものは何ですか? インターネット!


インターネットには、克服できないラウンドトリップ時間(RTT)などがあります。可変帯域幅があり、NATがあります。

以前は、ユーザーのネットワークの伝送速度を測定していました。


接続の種類ごとに分類し、平均RTT、パケット損失、速度を調べ、これらの各ネットワークの平均値で呼び出しをテストすることにしました。


インターネットには他にもトラブルがあります:




上記のネットワーク設定を簡単な例で検討してください。

ノボシビルスク州立大学のウェブサイトに私のオフィスからアクセスしましたが、そのような奇妙なpingを受け取りました。


この例の平均ジッタは30ミリ秒です。つまり、隣接するping時間の平均間隔は約30ミリ秒であり、平均pingは105ミリ秒です。

通話で重要なのはなぜですか?


サンクトペテルブルクでお互いに話をしようとしているユーザー間で、ノボシビルスクにあるサーバーを介さずにp2p接続を確立できた場合、ラウンドトリップとこのサービスへのトラフィックを約100ミリ秒節約できることは明らかです。

したがって、記事のほとんどは、優れたp2pの作成方法に当てられています。

歴史または遺産


前にも言ったように、2010年からコールサービスを提供してきましたが、今では再開しました。


2006年、Skypeの発売時に、FlashはAmicimaを買収し、RTMFPを作成しました。 FlashにはすでにRTMPがあり、これは原則として通話に使用でき、ストリーミングによく使用されます。 Flashは後にRTMP仕様を公開しました。 なぜRTMFPが必要なのでしょうか? 2010年には、RTMFPを使用しました。

通話プロトコルと実際のストリーミングプロトコルの要件を比較し、この境界がどこにあるかを確認します。


RTMPは、より多くのビデオストリーミングプロトコルです。 TCPを使用し、累積遅延があります。 インターネット接続が良好であれば、RTMPへの呼び出しは機能します。

RTMFPプロトコルは 、1文字だけの違いにもかかわらず、UDPプロトコルです。 バッファリングの問題はありません-TCP上にある問題。 これは行頭ブロッキングを奪われています-これは1つのパケットを失ったときであり、TCPは失われたパケットを再送する時まで次のパケットを返しません。 RTMFPはNATを処理でき、クライアントのIPアドレスが変更されていました。 そのため、2010年にRTMFPでウェブを開始しました。


その後、2011年に初めてWebRTCの最初のドラフトドラフトが表示されましたが、まだ完全には機能していませんでした。 2012年に、iOS / Androidでの通話のサポートを開始し、別のことが起こり、2016年にChromeはFlashのサポートを停止しました。 私たちは何かをしなければなりませんでした。


私たちはすべてのVoIPプロトコルに注目しました。いつものように、何かをするために、競合他社を調べることから始めます。

競合他社またはどこから始めるか


最も人気のある競合他社であるSkype、WhatsApp、Google Duo(ハングアウトに似ています)、ICQを選択しました。

まず、遅延を測定しました。


簡単です。 上の写真は次のとおりです。


すべてのカードをまだ公開しませんが、これらのデバイスがp2p接続を確立できないことを確認しました。 もちろん、測定は異なるネットワークで行われましたが、これは単なる例です。


Skypeはまだ少し中断します。 Skypeでは、p2pの接続に失敗した場合、遅延は1.1秒であることが判明しました。

テスト環境は複雑でした。 さまざまな条件(EDGE、3G、LTE、WiFi)でテストし、チャネルが非対称であることを考慮して、すべての測定値の平均値を示しました。


バッテリーの消費量、プロセッサーの負荷、その他すべてを推定するために、単純に高温計で電話の温度を測定し、これがプロセッサーのバッテリーのGPUの平均負荷であると想定することにしました。 原則として、熱い電話を耳に持って行ったり、手に持ったりすることは非常に不快です。 ユーザーには、アプリケーションがバッテリー全体を使い果たしてしまうようです。


結果は次のとおりです。


素晴らしい、いくつかのメトリックを入手しました!


さまざまなネットワークで、さまざまなドロップおよびその他すべてのビデオと音声の品質をテストしました。 その結果、 最高品質のビデオはGoogle Duoにあり、音声はSkypeにあるという結論に達しましたが、これはすでに歪みがある「悪い」ネットワークにあります。 一般的に、誰もがほぼ平凡に働いています。 WhatsAppの画像は最もぼやけています。

それがすべて実装されているものを見てみましょう。


Skypeには独自のプロトコルがありますが、他のユーザーはWebRTCの変更を使用するか、通常は直接WebRTCを使用します。 ハングアウト、Google Duo、WhatsApp、Facebook MessengerはWebで動作し、すべてWebRTCが内部にあります。 それらはすべて非常に異なり、異なる特性を持ち、すべて1つのWebRTCを持っています! だから、あなたはそれを正しく調理できる必要があります。 さらに、WebRTCの一部がオーディオ部分を担当するTelegramがあり、ICRTがあります。これは長い間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アドレスがあります。 グレーアドレスからパケットをインターネットに送信すると、NATはグレーアドレスを白に置き換え、送信元ポート、送信先ポート、一致するポートを記憶します。 返信パケットが到着すると、このマッピングによって解決され、送信者に送信されます。 すべてがシンプルです。

以下は私の場所でどのように見えるかのイラストです。


これは、私の内部IPアドレスとルーターのアドレスです(ところで、灰色)。 ルートをトレースして見ると、Wi-Fiルーターが表示されます。灰色のプロバイダーアドレスのパケットと外部の白いIPです。 したがって、実際には2つのNATがあります。1つはWi-Fi上にあり、もう1つはプロバイダーにあります。もちろん、専用の外部IPアドレスを購入した場合を除きます。

NATは次の理由で非常に人気があります。


したがって、外部IPを使用しているのは3%のユーザーのみで、残りはすべてNATを経由します。

NATを使用すると、ホワイトアドレスに安全にアクセスできます。 しかし、あなたがどこにも行かなかったなら、誰もあなたのところに来ることができません。


p2p接続を確立することは問題です。 実際、アリスとボブは、両方がNATの背後にある場合、互いにパケットを送信できません。

WebRTCにはこの問題を解決するためのSTUNプロトコルがあります 。 STUNサーバーの展開が提案されています。 次に、アリスはSTUNサーバーに接続し、IPアドレスを取得して、シグナリングを介してボブに送信します。 ボブもIPアドレスを取得して、アリスに送信します。 それらは互いにパケットを送信するため、NATを突破します。


質問 :アリスは特定のポートを開いており、NAT /ファイアウォールはすでにこのポートにブレークスルーされており、ボブは開いています。 彼らはお互いの住所を知っています。 アリスはパケットをボブに送信しようとしますが、アリスにパケットを送信します。 あなたは彼らが話すことができると思いますか?

実際、どのような場合でもあなたは正しいです、結果はユーザーが持っているNATペアのタイプに依存します。


ネットワークアドレス変換


NATには4つのタイプがあります。

  1. フルコーンNAT;
  2. 制限されたコーンNAT。
  3. ポート制限コーンNAT。
  4. 対称NAT

基本バージョンでは、アリスはパケットをSTUNサーバーに送信し、ポートを開きます。 ボブはどういうわけか自分のポートを見つけて、返信パケットを送信します。 これがFull cone NATである場合 -外部ポートを内部ポートにマップするだけの最も簡単なNATであれば、BobはすぐにAliceにパケットを送信し、接続を確立し、通話します。


以下は相互作用スキームです。あるポートからのアリスはパケットをSTUNポートに送信し、STUNは外部アドレスで彼女に応答します。 STUNは任意のアドレスから応答できます。フルコーンNATであれば、NATを介してパンチし、ボブは同じアドレスに応答できます。


制限コーンNATの場合、事態はもう少し複雑です。 内部アドレスにマップする必要があるポートだけでなく、移動先の外部アドレスも記憶します。 つまり、IP STUNサーバーへの接続のみを確立した場合、ネットワーク上の他の誰も応答できなくなり、ボブのパケットは届きません。


この問題はどのように解決されますか? このような単純なスキーム(次の図を参照)では、アリスはパケットをSTUNに送信し、IPで彼女に答えます。 STUNは、制限付きコーンNATである限り、どのポートからでも応答できます。 ボブは別のアドレスを持っているため、アリスに応答できません。 アリスは、ボブのIPアドレスを知っているパケットで応答します。 彼女はボブにNATを開き、ボブは彼女に答えます。 やった、彼らは話した。


もう少し複雑なオプションは、 ポート制限コーンNATです。 それでも、STUNのみがアクセス先のポートから正確に応答する必要があります。 すべてが同様に機能します。

最も有害なのはSymmetric NATです。


最初は、すべてがまったく同じように機能します。アリスはパケットをSTUNサーバーに送信し、同じポートから応答します。 ボブはアリスに応答できませんが、ボブにパケットを送信します。 そして、ここで、アリスがポート4444にパケットを送信するという事実にもかかわらず、マッピングは彼女に新しいポートを割り当てます。 対称NATは、新しい接続が確立されるたびに、ルーターで新しいポートを発行するたびに異なります。 したがって、ボブはアリスがSTUNに行ったポートで暴行しており、接続できません。

逆に、ボブがオープンIPアドレスを持っている場合、アリスは彼にちょうど来て、接続を確立します。

すべてのオプションは、以下の1つの表にまとめられています。


ポート制限コーンNATまたは反対側の対称NATを使用して対称NATを介して接続を確立しようとする場合を除き、ほとんどすべてが可能であることを示しています。


わかったように、p2pは待ち時間の点で私たちにとって貴重ですが、インストールできない場合、WebRTCはTURNサーバーを提供します。 p2pがインストールされないことに気付いたときは、TURNに接続するだけで、すべてのトラフィックがプロキシされます。 ただし、この場合、トラフィックに対して料金を支払うことになり、ユーザーにはさらに遅延が発生する可能性があります。

練習する


Googleには無料のSTUNサーバーがあります。 あなたはそれらをライブラリに置くことができます、それは動作します。

TURNサーバーには資格情報(ログインとパスワード)があります。 ほとんどの場合、あなたはあなた自身を上げる必要があります、それは自由を見つけるのはかなり困難です。

Googleの無料のSTUNサーバーの例:


パスワード付きの無料TURNサーバー:url: 'turn:192.158.29.39:3478?Transport = udp'、資格情報: 'JZEOEt2V3Qb0y27GRntt2u2PAYA ='、ユーザー名: '28224511:1379330808' '

私たちはコターンを使用します


その結果、トラフィックの34%がp2p接続を通過し、その他はすべてTURNサーバーを介してプロキシされます。

STUNプロトコルで興味深いものは何ですか?


STUNでは、NATのタイプを判別できます。


スライド リンク

パケットを送信するときに、同じポートから応答を受信することを示すか、別のポート、別のIP、または別のIPとポートからも応答するようにSTUNに要求できます。 したがって、 STUNサーバーへの4つの要求に対して、NATのタイプを判別できます


NATの種類を数えたところ、ほぼすべてのユーザーが対称NATまたはポート制限コーンNATを持っていることがわかりました。 ここから、ユーザーの3分の1だけがp2p接続を確立できることがわかります。

GoogleからSTUNを取得して、それをWebRTCに入れるだけで、すべてがうまくいくように思えるのなら、なぜ私はこれをすべて言っているのかと尋ねるかもしれません。

実際にNATのタイプを自分で決定できるからです。


これは、トリッキーなことは何もしないJavaアプリケーションへのリンクです。異なるポートと異なるSTUNサーバーにpingを実行し、最終的にどのポートを見るかを調べます。 フルコーンNATを開いている場合、STUNサーバーには同じポートがあります。 制限されたコーンNATでは、STUN要求ごとに異なるポートがあります。


Symmetric NATを使用すると、私のオフィスでは次のようになります。 完全に異なるポートがあります。

ただし、接続ごとにポート番号が1つずつ増加する興味深いパターンが存在する場合があります。


つまり、多くのNATは、ポートを定数で増減するように構成されています。 この定数を見つけることができるため、対称NATを突破できます。


したがって、NATを突破します。1つのSTUNサーバーに移動し、別のSTUNサーバーに移動して、違いを確認し、比較して、この増分または減分でポートを既に提供しようとします。 つまり、アリスはボブにポートを与えようとしていますが、すでに一定に調整されており、次回はそれだけになることを知っています。


そこで、私たちは別の12%ピアツーピアを溶接することができました。

実際、同じIPを持つ外部ルーターが同じように動作する場合があります。 したがって、統計を収集し、対称NATがプロバイダーの機能であり、ユーザーのWi-Fiルーターの機能ではない場合、デルタを予測し、すぐにユーザーに送信して、ユーザーがそれを使用し、判断に時間をかけすぎないようにすることができます。

CDNリレーまたはP2P接続を確立できなかった場合の対処方法


それでもTURNサーバーを使用し、p2pではなくリアルモードで作業し、すべてのトラフィックをサーバーに渡す場合、CDNを追加できます。 もちろん、遊び場がない限り。 独自のCDNサイトがあるため、私たちにとっては非常に簡単でした。 しかし、人をどこに送るべきかを決定する必要がありました:CDNサイトに、または、例えば、モスクワへのチャンネルに。 これはそれほど簡単な作業ではないため、次のようにしました。

  1. モスクワのサイトの一部のユーザーに誤って発行されたもの、一部-リモート。
  2. ユーザーのIP、サーバー、およびネットワークの特性に関する統計を収集しました。
  3. maxMindによって、サブネットをグループ化し、統計情報を見て、どのユーザーが接続に最も近いTURNサーバーを持っているかをIPで理解することができました。



ノボシビルスクにCDNがあります。 すべてがモスクワで機能する場合、RTTの99パーセンタイルは1.3秒です。 CDNにより、すべてがはるかに高速に動作します(0.4秒)。

サーバーを使用せずにp2p接続を使用する方が常に良いですか? 興味深い例は、クラスノヤルスクの2つのプロバイダーであるOptibyteとMobraです(名前は変更されている場合があります)。 何らかの理由で、p2pでのそれらの間の接続はMSKを介した接続よりもはるかに悪いです。 おそらく彼らはお互いの友達ではありません。


このようなすべてのケースを分析し、ユーザーをランダムにp2pまたはMSK経由で送信し、統計を収集して予測を構築しました。 統計を更新する必要があることはわかっているため、一部のユーザーについては、ネットワークで何かが変更されたかどうかを確認するために異なる接続を特別に確立します。

ラウンドタイム、パケット損失、帯域幅などの単純な特性を測定しました。それらを正しく比較する方法を学ぶことは残っています。


どちらが優れているかを理解する方法:2 Mbit / sインターネット、400 ms RTTおよび5%パケット損失、または100 Kbit / s、100 ms遅延とわずかなパケット損失

正確な答えはありません。ビデオ通話品質の評価は非常に主観的です。 そのため、通話終了後、ユーザーにアスタリスクで品質を評価し、結果に応じて定数を設定するように依頼しました。 たとえば、RTTは300ミリ秒未満であることが判明しました。これは問題ではなく、ビットレートがより重要です。

AndroidおよびiOSでのユーザー評価が高い。 iOSユーザーはユニットを配置する可能性が高く、多くの場合5ユニットを配置することがわかります。 おそらく、プラットフォームの詳細な理由はわかりません。 しかし、それらに対して定数を引いたので、私たちには良いように思えました。

記事の概要に戻って、ネットワークについて議論しています。

接続設定はどのように見えますか?


STUNおよびTURNサーバーをPeerConnection()に送信すると、接続が確立されます。 アリスは自分のIPを見つけて、それをシグナリングに送信します。 ボブはアリスのIPについて知ります。 アリスはボブのIPを取得します。 パケットを交換し、NATを突破し、TURNを設定して通信します。


前に説明した接続を確立する5つのステップで、サーバーを見つけ、それらをどこで取得するかを判断し、ICE候補はシグナリングを通じて交換する外部IPアドレスであることを確認しました。 クライアントが1つのWi-Fiの範囲内にある場合、クライアントの内部IPアドレスも突破することができます。

ビデオの一部に移りましょう。

ビデオとオーディオ


WebRTCは特定のビデオコーデックとオーディオコーデックのセットをサポートしますが、独自のコーデックをそこに追加できます。 ビデオ用にH.264およびVP8で基本的にサポートされています。 VP8はソフトウェアコーデックであるため、多くのバッテリーを消費します。 H.264はすべてのデバイス(通常はネイティブ)で利用できるわけではないため、デフォルトの優先順位はVP8です。

SDP(セッション記述プロトコル)内には、コーデックネゴシエーションがあります。一方のクライアントがコーデックのリストを送信すると、もう一方のクライアントは優先的に独自のコーデックを送信し、通信に使用するコーデックについて合意します。 必要に応じて、VP8およびH.264コーデックの優先度を変更できます。これにより、264がネイティブである一部のデバイスのバッテリーを節約できます。 これを行う方法の例を次に示します。 私たちはこれを行いましたが、ユーザーは品質について文句を言わなかったように思えましたが、同時にバッテリーの消費はずっと少なくなりました。

WebRTCのオーディオには、 OPUSまたはG711があり 、通常はすべてのOPUSが常に機能します。何もする必要はありません。

以下は、10分間使用した後の温度測定値です。


さまざまなデバイスをテストしたことは明らかです。 これはiPhoneの例であり、デバイスの温度が最も低いため、OKアプリケーションはバッテリーを最も使用しません。

WebRTCを使用する場合に有効にできる2番目のことは、接続が非常に悪いときにビデオ自動的にオフにすることです。


40 Kbps未満の場合、ビデオはオフになります。 接続を作成するときにチェックボックスをオンにするだけで、インターフェイスを介してしきい値を設定できます。 開始時の現在のビットレートの最小値と最大値を設定することもできます。


これは非常に便利です。 接続を確立するときに、予想しているビットレートが事前にわかっている場合は、転送することができ、通話はそこから開始され、ビットレートを調整する必要はありません。 さらに、チャネルで頻繁にパケット損失または帯域幅の低下があることがわかっている場合は、最大値も制限できます。

WhatsAppは非常にせっけんのビデオで動作しますが、上からビットレートを積極的に圧縮するため、わずかな遅延があります。

MaxMindを使用して統計を収集し、マッピングしました。


これは、ロシアのさまざまな地域での通話に使用するおおよその開始品質です。

シグナリング


呼び出しを行う場合は、ほとんどの場合、この部分を記述する必要があります。 あらゆる種類の落とし穴があります。 見た目を思い出してください。


SDPに接続して交換するシグナリングを備えたアプリケーションがあり、以下のSDPはWebRTCへのインターフェースです。

これは、単純なシグナリングがどのようなものかを示しています。


アリスはボブに電話します。 たとえば、Webソケット接続を介して接続します。 ボブは、携帯電話またはブラウザへのプッシュ、または何らかのオープン接続へのプッシュを受信し、Webソケットを介して接続し、その後、電話がポケットで鳴り始めます。 ボブは電話を取り、アリスは彼のコーデックと彼女がサポートする他のWebRTC機能を彼に送ります。 ボブは彼女に同じように答え、その後、彼らは見た候補者を交換します。 やれやれ!

これはすべてかなり長く見えます。 まず、Webソケット接続を確立するまで、プッシュが発生するまで、その他すべての操作を行うまで、Bobの電話はポケットで鳴りません。 アリスはいつも待って、ボブがどこにいるのか、なぜ彼が電話を受け取らないのかを考えます。 確認後、すべてに数秒かかります。接続が良好な場合でも3〜5秒、接続が不良な場合はすべて10です。

これで何かをしなければなりません! あなたはすべてが非常に簡単にできることを教えてくれます。



アプリケーションの接続が既に開いている場合は、すぐにプッシュを送信して接続を確立し、目的のシグナリングサーバーに接続して、すぐに呼び出しを開始できます。

その後、別の最適化。 電話がまだポケットに鳴っていて、電話を受け取っていない場合でも、サポートされているコーデック、外部IPアドレスに関する情報を実際に交換し、空のビデオパケットの送信を開始することができます。 電話を手にしたら、すべてが素晴らしいものになります。

私たちはそうしましたが、すべてがクールであるように見えました。 しかし、ありません。


最初の問題は、ユーザーが頻繁に通話をキャンセルすることです。 「通話」をクリックしてすぐにキャンセルします。 それに応じて、プッシュに電話がかかり、ユーザーは姿を消します(インターネットまたは他の何かを失いました)。 その間、誰かの電話が鳴り、彼は電話を取りますが、彼らはそこで彼を待っていません。 したがって、できるだけ早く呼び出しを開始するためのプリミティブな最適化は実際には機能しません。


クイックコールキャンセルでは、2番目の有害なことがあります。 サーバーで会話のIDを生成する場合、応答を待つ必要があります。 つまり、呼び出しを作成し、IDを取得し、その後でのみ、パケットの送信、呼び出しのキャンセルなどのやり取りを行うことができます。 これは非常に悪い話です。応答が到着するまで、クライアントから何も実際にキャンセルできないことが判明したためです。 したがって、GUIDなどの何らかのIDをクライアントで生成し、呼び出しを開始したと言うのが最善です。 人々はまだ頻繁にこれを行います:呼ばれ、キャンセルされ、すぐに再び呼び出されます。 これが混乱しないようにするには、GUIDを実行して送信します。


何もないように見えますが、別の問題があります。 ボブに2台の電話がある場合、またはブラウザが開いたままの場合、パケットを交換するためのマジックスキーム全体が、別のデバイスから突然応答した場合、接続を確立できません。

どうする? 基本的なシンプルな低速信号方式に戻って最適化して、少し前にプッシュを送信しましょう。 ユーザーはより高速に接続を開始しますが、これにより数セント節約できます。


彼が電話を取り、交換を始めた後、最も長い部分をどうするか?


次のことができます。 アリスがすでにすべてのコーデックを知っており、ボブの両方の電話に送信できることは明らかです。 彼女はすべてのIPアドレスを解決し、それらをキューに保持するシグナリングに送信することもできますが、クライアントとの接続を事前に開始できるように、クライアントには送信しません。

ボブは何ができますか?オファーを受け取った彼は、そこにあったコーデックを確認し、独自のコーデックを生成し、所有しているものを書き、送信することもできます。しかし、ボブには2台の電話があり、コーデックネゴシエーションが異なります。そのため、シグナリングはそれをすべて保持し、電話を受け取るデバイスを見つけるまで順番に待機します。彼らの候補者はまた、両方のデバイスを生成し、シグナリングに送信します。

したがって、シグナリングには、アリスからの1つのメッセージキューと、異なるデバイス上のボブからの複数のメッセージキューがあります。彼はそれをすべて保管し、これらのデバイスの1つが拾われるとすぐに、彼は既に準備されたパッケージのセット全体を単に投げます。

非常に高速に動作します。このようなアルゴリズムを使用して、Google DuoやWhatsAppに似た特性に到達しました。


おそらく、もっと良いものを思いつくことができます。たとえば、シグナリング用ではなく複数のキューを保持し、それらをクライアントに送信してから、その番号を発声しますが、ほとんどの場合、ゲインは非常に小さくなります。そこで停止することにしました。

他にどんな問題が待っていますか?


コールバックのようなものがあります:1つは別のものを呼び出し、他は鳴ります。彼らが競争しようとしなかったらいいと思います-信号レベルで、誰かが2番目に来た場合、ただ電話を受け入れてすぐに電話をかけるときにモードに切り替える必要があるというコマンドを追加します。


ネットワークが消え、メッセージが失われるため、すべてがキューを介して行われる必要があります。つまり、クライアントにディスパッチキューが必要です。クライアントから送信したメッセージは、サーバーがメッセージを処理したことを確認した後にのみキューから削除する必要があります。サーバーには、送信用のキューもあり、確認もあります。

したがって、これらはすべて24時間年中無休のサービスを考慮して社内で実装されており、データセンターを失い、ソフトウェアのバージョンを変更および更新できるようにしたいと考えています。


リンク スライド上のビデオへの言及にテキスト版

クライアントは、Webソケットを介してロードバランサーに接続し、異なるデータセンターのシグナリングサーバーに送信します。異なるクライアントは異なるサーバーにアクセスできます。 Zookeeperでは、この選挙区を管理するシグナリングサーバーを定義するリーダー選挙を行います。サーバーがこの会話のリーダーではない場合、サーバーはすべてのメッセージを別のユーザーに送信します。

次に、分散ストレージを使用します。Cassandraの上にNewSQLがあります。何を使用するかは問題ではありません。どこでも信号を送信しているすべてのキューの状態を保存して、信号サーバーが消えたり、電源が切れたり、他の何かが発生した場合、リーダー選挙がZookeeperで動作し、リーダーになる別のサーバーが起動して、データベースからすべてのキューを復元できますメッセージを送信します。

アルゴリズムは次のようになります。


混同しないように、すべてのパッケージには一意の番号が付けられています。

データベースの観点からは、Cassandraのアドオンを使用します。これにより、データベースでトランザクションを行うことができます(ビデオはまさにそれです)。

だから、あなたは学んだ:




私達は受け取った:


わあ!


セキュリティ WebRTCの中間者攻撃


WebRTCの中間者攻撃について話しましょう。実際、WebRTCは、1996年のRTPに基づいているという点で非常に難しいプロトコルであり、SDPは1998年にSIPから来ました。


一番下の巨大なリストは、RTP WebRTCを作成する多くのRFCおよびその他のRTP拡張機能です。

リストの最初の2つの興味深いRFC-1つはパケットに音声レベルを追加し、もう1つはパケットで音声レベルをオープンに送信することは安全ではないと述べ、暗号化します。したがって、SDPを交換するときは、クライアントがサポートする拡張機能のセットを知ることが重要です。いくつかの輻輳アルゴリズム、失われたパケットを回復するためのいくつかのアルゴリズム、その他すべてがあります。

WebRTCの歴史は複雑でした。最初のドラフトリリースは2011年にリリースされ、2013年にFirefoxはこのプロトコルをサポートし、その後2014 OperaでiOS / Androidでのビルドが開始されました。一般に、それは長年にわたって開発されましたが、それでも1つの興味深い問題を解決していません。


アリスとボブがシグナリングに接続すると、このチャネルを使用して、DTLSハンドシェイクを確立し、接続を保護します。すべてが素晴らしいですが、それが私たちの信号ではないことが判明した場合、原則として、真ん中の人はアリスとボブの両方で「お金を稼ぐ」機会があり、すべてのトラフィックをブロックし、そこで起こっていることを盗聴します。


信頼度の高いサービスがある場合は、もちろん、HTTPS、WSSなどを使用する必要があります。別の興味深いソリューションがあります-ZRTP、それは、たとえばTelegramによって使用されます。

接続が確立されたときにTelegramで絵文字を見た人は多くいますが、それを使用する人はほとんどいません。実際、友人にあなたが持っている絵文字を伝えると、彼は彼がまったく同じであることを確認し、あなたは絶対に安全なP2P接続を保証します。

どのように機能しますか?


これらすべてのプロトコルの内部では、通常のDiffie-Hellmanアルゴリズムが最初に使用されます。アリスはいくつかの番号を生成し、1つを除くすべてをボブに送信します。また、ボブは乱数を生成し、それをアリスに送信します。この交換の結果として、アリスとボブは特定の大きなKを取得します。これについては、チャネル全体を聞いた中間の人は何も知らず、まったく推測できません。

デイブがアリスとボブの間に現れると、彼らは彼と同じ鍵を交換しそれぞれK 1とK 2を取得します。中央にこの人物の存在を追跡する方法はありません。次に、このようなトリックが適用されます。これらのキーはK 1およびK 2ですアリスとボブは鍵をランダムに生成するため、デイブは間違いなく異なります。K 1とK 2からいくつかのハッシュを取得して、絵文字で表示します。リンゴ、ナシ、何でも、そして人々は自分が見た写真を自分の声で呼ぶだけです。音声でお互いを識別でき、これらの写真が異なる場合は、あなたとあなたの間に誰かがいて、彼があなたを聞いているかもしれません。

結果





このグラフは、最初にRTMFPの古い呼び出しがあり、WebRTCに切り替えたときに小さな障害が発生し、その後ピークが上昇することを示しています。すべてがすぐに機能したわけではありません!その結果、保留されるコールの数が4倍に増えました。

簡単な指示


これらすべてを必要としない場合、非常に簡単な指示があります。


すべてが鳴りますが、鳴りはかなり良いです。

報告後の質問への回答を聞く


HighLoad++ 4-.

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

Source: https://habr.com/ru/post/J428217/


All Articles