技术实践 | 聊聊网易云信的信令网络库实践
導讀:信令作為實時音視頻技術架構中的重要一環,是對建立實時音視頻通信起到關鍵橋梁性的作用。
文|丁永鋒
網易云信資深客戶端開發工程師
本文將從信令的概念著手,分享在網易云信新一代音視頻技術架構下,信令的基本交互流程設計以及信令網絡庫的模塊設計和重連優化等。
什么是信令
我們都知道,WebRTC 是通過 RTCPeerConnection 來做到端與端之間的實時音視頻通信的,那他們是怎么知道對方網絡位置(網絡數據)?支持何種編解碼器(媒體元數據)?何時打開或關閉通信(會話控制)的呢?
這就需要建立一條通道來交換這些信息,而這協商的信息就是信令,這條通道也就是信令通道。我們這里所說的信令網絡庫的作用就是為端和信令服務器交換信令提供網絡傳輸的通道。那信令的作用到底是什么?
在實時通信中,信令的主要作用體現在以下四個方面:
媒體功能的協商和設置。
標識和驗證會話參與者的身份(交換 SDP 對象中的信息:媒體類型、編解碼器、帶寬等元數據)。
控制媒體會話、指示進度、更改會話和終止會話。
當會話雙方同時嘗試建立或更改會話時,實施雙占用分解。
總之,信令就是協調音視頻實時通信的過程,一旦信令服務建立好了,兩個客戶端之間建立了連接,理論上它們就可以進行點對點通訊了。而值得注意的是,WebRTC 標準本身沒有規定信令交換的通訊方式,信令服務根據自身的情況實現。這也為我們自定義信令服務器提供了可能。
單 PeerConnection 方案
2020年,在疫情的沖擊下,音視頻通信市場得到了爆發式的增長,在視頻會議、在線教育、線上金融、云游戲等各個領域都得到了長足的發展。同時,客戶也對各種應用場景下的音視頻的高性能、低延時等方面提出了更高的要求。
在2020年11月,網易云信發布了新一代音視頻技術架構(簡稱 NERTC),詳細內容可查看文末介紹,為了提升產品性能,我們從高可用、高并發、高性能、高擴展等方向進行了全流程的技術升級,包括新一代音視頻融合通信服務端系統、新一代音視頻 SDK 以及新一代音視頻引擎,其中就包括單 PeerConnection 的重構方案。
單 PeerConnection 方案涉及了信令服務器的重構。其基本設計原則是主要是:
iOS/Android/windows/Mac/Web 多端協議一致,均采用 Websocket 交互,節省服務器資源,簡化服務器代碼邏輯。
端側只創建 2 個 Peerconnection,一個只負責發送(sendonly),一個只負責接收(recvonly)。
采用自定義信令協議進行交互。
簡化協商流程,減少首屏時間。
單 PeerConnection 方案基本的信令交互流程如下:
WebSocket 通信簡介
前文可知,為了達到多端(Web)信令協議交互一致性,所以采用了 WebSocket 作為信令傳輸。那 ?WebSocket 有什么特點?
說到 WebSocket,就離不開 HTTP,簡單來說,WebSocket 是基于 HTTP 協議的,而區別于 HTTP 的最大特點在于服務器可以主動向客戶端推送信息,客戶端也可以主動向服務器發送信息,是真正的雙向平等對話;而 HTTP 只能從端側發起請求。從下圖可以清晰看出 HTTP 與 WebSocket 之前的區別。
(圖片來自網絡)
?握手(Handshake)?
WebSocket 是建立在 TCP 長連接基礎之上的,為了實現 WebSocket 的通信,借用 HTTP 協議完成了一次握手過程。具體的握手過程是這樣的:
客戶端發起握手請求
服務器返回應答
這樣表示握手成功。握手成功之后,客戶端和服務器就可以進行數據傳輸了。
?連接保持?
常規做法大家都知道,那就是心跳機制,通過判斷心跳是否有響應來判斷鏈接是否可用。WebSocket 也不例外,其協議規定了 ping/pong 機制來保持連接。我們可以看下 ping/pong 在 RFC6455 具體是怎么規定的。
5.5.2.?Ping
The Ping frame contains an opcode of 0x9.
A Ping frame MAY include "Application data".
Upon receipt of a Ping frame, an endpoint MUST send a Pong frame in response, unless it already received a Close frame. ?It SHOULD respond with Pong frame as soon as is practical. ?Pong frames are discussed in Section?5.5.3.
An endpoint MAY send a Ping frame any time after the connection is established and before the connection is closed.
NOTE: A Ping frame may serve either as a keepalive or as a means to verify that the remote endpoint is still responsive.
5.5.3.?Pong
The Pong frame contains an opcode of 0xA.
Section 5.5.2 details requirements that apply to both Ping and Pong frames.
A Pong frame sent in response to a Ping frame must have identical "Application data" as found in the message body of the Ping frame being replied to.
If an endpoint receives a Ping frame and has not yet sent Pong frame(s) in response to previous Ping frame(s), the endpoint MAY elect to send a Pong frame for only the most recently processed Ping frame.
A Pong frame MAY be sent unsolicited. This serves as a unidirectional heartbeat.
A response to an unsolicited Pong frame is not expected.
由上可知,一端通過發送 ping 幀,對端收到 ping 幀后,響應一個 pong 幀,這樣就完成了一次連接的檢測,并且它是單向的。
?關閉連接?
當關閉 WebSocket 通信的時候,發起端需要發送一個關閉幀,對方收到關閉幀,如果不曾發送過關閉幀,則需要發送一個關閉幀作為響應。關閉幀可以攜帶應用數據,用來說明關閉的原因。最后等到底層 TCP 連接關閉后,整個 WebSocket 通信就完全關閉了。
在 NERTC 中的應用
網易云信在新一代音視頻技術架構中,是如何使用這些技術來實現信令的傳輸通道呢?下面我們先從模塊設計方面和重連方面的設計做一些介紹。
一個基本原則:應用層不需要關心消息丟失、亂序、重發等問題。眾所周知,TCP 提供可靠的傳輸服務,通過 TCP 連接傳送的數據無差錯、不丟失、不重復且按序到達。TCP 通過校驗、重傳控制、序號標識、滑動窗口、確認應答來實現可靠傳輸,如丟包時的重發控制,還可以對次序亂掉的分包進行順序控制。這樣,我們只需要解決的就是重連和重發問題。
?網絡庫架構設計?
下圖是 NERTC 的網絡庫架構圖設計:
我們簡單介紹其中的幾個模塊:
API 部分定義的是網絡庫模塊的對外接口,由應用層調用。
Transport 模塊主要抽象了消息收發和連接管理的功能,ws/wss 以及未來的 quic 協議擴展等都基于其虛接口實現。
Message 模塊管理 WebSocket 子協議的組包和解包。
SendBuffer 管理 Message 的緩存和重發。
Peer 作為核心模塊,實現對 Transport、Message 等所有模塊的控制。
接下去我們看下快連接快重試和重連設計優化。
?快速連接和重連設計?
下面我們按不同的場景來介紹下網絡庫是如何運作以及做了哪些工作,部分場景可以結合下圖來理解。
場景一:首次連接時的退避策略。當應用層(簡稱 SDK)首次嘗試連接時,如果 WebSocket 連接成功,則返回 SDK,SDK 發起信令協商;如果連接失敗,使用每隔 200/400/600ms 的快速重試多次連接的策略。如果最終都失敗的話,則回調給應用層 onFail 事件。
場景二:連接成功后的斷開重連策略。如果已經連接成功,因為網絡原因或者服務器等原因導致連接斷開,則觸發此策略。觸發方式分為兩種,一種方式是,WebSocket 通知了 onClose 事件;另外一種是主動探測的方式,通過 ping/pong 機制來觸發重連。后者通過發送 ping 幀三次,每次間隔 3s,超時1.5s,如果三次均無法得到 pong 幀,則認為網絡或者服務器異常,觸發此場景的重連策略。具體的策略是,每隔 2/4/6s 觸發一次連接嘗試,如果最終還是失敗的話,回調給應用層 onDisconnected 事件。
場景三:應用層收到 onDisconnected 事件,會切換新的 server 地址,重新通過網絡庫嘗試連接,直到 server 用盡,退出當次通話。
場景四:當網絡切換或者恢復可用時,應用層會主動觸發重連。
場景五:服務器主動關閉連接時,網絡庫清空消息緩存,并且不再嘗試重連。
重連場景如下圖所示:
?消息緩存和重發?
其實上面的時序圖已經包含了消息發送和重發的時機。消息分為兩種:
Request 類型消息,需要等待服務器的 Response,需要緩存。
Notification 類型消息,不進入消息緩存,當然也有可能是服務器發送過來的通知。
我們這里只講端側的消息發送。消息的發送和重發都只在連接成功后觸發。
每一條消息都會先進入發送緩存隊列(即 SendBuffer),如果當前連接正常,則直接發送,如果連接斷開則會暫停發送,等待連接或重連成功之后才會恢復發送。因為依賴于 TCP 的可靠傳輸,所以消息的重發均只發生在重連成功之后。當連接被服務器 kick off 或者應用層主動關閉時,peer 對象會清空所有緩存消息,不再做發送或重發的嘗試。
?弱網下的表現?
在弱網下,我們的測試數據發現,最多能抗50%的丟包率。在實測場景中,高丟包率情況下,媒體流 的 QoS 激進策略下會發送大量的冗余包和重傳包,從而導致帶寬資源幾近耗盡。這會導致什么呢?
WebSocket 連接可能會失敗,消息可能無法收發。我們都知道 TCP 是通過滑動窗口和擁塞窗口來做的流控。當已發字節數等于對方的接收窗口字節數時,就會導致發送窗口滿(TCP Window FULL)了,從而無法再發送數據。有興趣的同學可以了解 TCP 相關的概念。這種情況下基本只能通過觸發斷開重連的機制,關閉老的連接,新建連接進行消息的重發。
未來規劃&總結
為了增強弱網情況下的抗性,我們會考慮 UDP 作為優化的方向,比如說 QUIC(Quick UDP Internet Connection)協議等,目前也基本已經接近產品化階段,這里就不再贅述,敬請期待 QUIC 版本的表現。
本文從信令的基本概念以及作用入手,簡要地講述了網易云信新一代音視頻技術架構中信令網絡庫基本交互流程、模塊化設計思路以及網絡庫基本運作方式。另外,也對連接重試和重連的設計和優化做了一些論述。同時,也非常歡迎跟我們交流更多關于信令網絡庫的實現。
?作者介紹?
丁永鋒,網易云信資深客戶端開發工程師,一直致力于客戶端跨平臺開發,目前負責音視頻客戶端跨平臺 SDK 開發,曾負責 Unity&Cocos2dx SDK 以及網易云信 IM SDK 的跨平臺開發工作。
?延伸閱讀?
網易云信流媒體首席架構師:新一代音視頻技術架構如何構建?
聊聊WebRTC網關服務器2:如何選擇PeerConnection方案?
http://yunxin.163.com/blog/webrtc-2/
?暖春成長記,一起來成為網易云信核心開發者!?
為了感謝各位開發者一直以來對云信的支持,也為了更好的支撐開發者們對 IM 及 RTC 技術的學習和應用,網易云信2021年推出了核心開發者計劃(NE Core Developer),并為核心開發者設計了豐富的權益體系,以期幫助開發者們更高效的學習成長、更好的溝通交流。點擊“閱讀原文”,了解更多詳情~
與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的技术实践 | 聊聊网易云信的信令网络库实践的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 语音社交产品,安全合规“防坑指南”!
- 下一篇: 沟通无国界,云信助力译牛构建远程会议同传