言
在現代的移動應用程序中,長連接是一種不可或缺的能力,包括但不限于推送、實時通信、信令控制等常見場景。在貓耳FM的直播業務中,我們同樣使用了 WebSocket 長連接作為我們實時通信的基礎。
在我們推進用戶體驗優化的工作中,其中用戶成功進入直播間的時間是我們優化的一個重點指標,其包含了房間信息接口的調用、長連接的建立、播放器拉流的首幀等。本文主要介紹我們在 WebSocket 長連接跨端統一和體驗優化的思路和方案。
這里我們先簡單介紹下 WebSocket,以及為什么我們選擇了 WebSocket 而不是其他的協議作為我們持續迭代的方向。
WebSocket 是一種在 Web 應用程序和服務器之間建立持久、雙向通信連接的通信協議。它允許客戶端和服務器之間進行實時數據傳輸,而無需客戶端不斷地發起 HTTP 請求,為開發者提供了豐富的實時應用開發可能性。從最早貓耳 2016 年開始調研和迭代直播的業務,WebSocket 已經是一種相當成熟的方案,可以同時在 Web 和移動應用程序中使用。早在 2011 年 12 月 WebSocket 的協議標準被定稿 [RFC 6455](https://datatracker.ietf.org/doc/html/rfc6455),從 2012 年開始 WebSocket 逐漸被各大瀏覽器支持,包括當時的 Internet Explorer、Safari、Mozilla Firefox 和 Google Chrome 等。
同時作為更早期誕生的 Socket.IO 為了兼容更早期的瀏覽器,在我們的場景下很多做法于這個時間點上就顯得相當臃腫和沒必要了。當時使用 WebSocket 的一個重點考慮我們還是可以同時在 Web 上直接使用,如果我們在客戶端上引入其他的協議,在迭代過程中,我們就不得不考慮同時兼容和支持多個實時通信的通道,為了降低最初直播方案的復雜性,我們選擇使用了 WebSocket 協議作為我們直播業務實時通信、信令傳遞的基礎協議。
時間來到 2023 年前后,隨著互聯網技術的發展,我們當前又有了更多的選擇作為實時消息傳遞的基礎消息通道,類似 MQTT、gRPC 等上層協議其實都可以作為一個可靠的傳遞消息的方式,并且被大量的用戶所驗證。同時,在 Web 技術上也有類似 SSE、WebRTC、WebTransport 等方案可以作為我們上層消息傳輸的機制。作為一個普遍的考慮,這里我們的選擇一定是一種“高級”協議,如果直接使用 TCP、UDP 等傳輸層協議,不可避免的我們要考慮更復雜的消息拆分、可靠性保證和安全等問題,這里我們秉持著多端統一、提高研發效率、減少維護成本的考慮,我們最后的選擇盡可能還是一種相對成熟和可靠的方案,在這樣的前提下,MQTT、gRPC 由于在 Web 上支持不佳或是本身就通過 WebSocket 包裝的,我們就暫時不做深入討論。
同時,一些較新的 Web 方案,對比之下類似 SSE 是單向傳輸、WebRTC 更適合實時音視頻通信的場景且不太能被 CDN 加速支持、WebTransport 太過于新,Safari 到現在為止還不支持,同時在消息順序上需要外部進行額外保證,這樣看下來 WebSocket 仍是我們當前最好的選擇。
技術方案
在考慮優化之前,由于我們之前在 Android 和 iOS 客戶端上也是使用的是 WebSocket (wss://),首先需要明確的就是當前有什么問題。
根據我們的埋點的數據,在我們直連國內 BGP 線路服務器建連的情況下,完成 WebSocket 握手的時長(90 分位,下文同)為 500ms ~ 600ms,DNS + TCP + TLS + HTTP Upgrade,相比于我們一次正常的 https 請求取得響應的時間明顯慢了很多,這個也是我們優化的一個最終目標,由于 WebSocket 在 HTTP/1.1 上不可避免的需要重新建立 HTTP 連接并進行一次 Upgrade,目前可以做的優化相對有限,可能在 DNS 和 TLS 過程中可以有一些優化。其實我們早期還嘗試通過訂閱、取消訂閱指令來直接復用同一個連接,但后來為了方便做負載均衡以及高可用性等原因線上已經不再支持這塊邏輯。
要做好這次優化,我們這邊有幾點考慮:
在考慮多端統一并且成熟可靠的選擇不多,我們主要對比下我們使用過的一些可以跨端的方案,這里主要提使用過的原因是我們能大致理解其核心的邏輯并作出一定的修改:
由于 websocketpp 已經很久沒更新了,我們這里主要對比下我們目前 libwebsockets 和 cronet 實現的方案要考慮的一些問題:
主要代碼語言 | DNS | 系統 Wi-Fi http proxy 設置 | 接入成本 | 持續迭代 | |
libwebsockets | C | 目前僅支持簡單的策略,需要修改代碼進行完整的 DNS 邏輯控制 | 外部控制設置 | Android 上需要單獨實現 JNI 層,支持 Java/Kotlin 中調用。同時自定義 DNS 過程 | 都在持續迭代中,支持較新的標準 |
cronet | C++ / iOS Objective-C / Android Java JNI | 已修改,并在線上穩定運行 | 內部集成支持 | 需要實現 cronet 適配層代碼,代碼生成相關接入層代碼 |
通過簡單的對比,其實我們更傾向使用 cronet 作為持續后續迭代的方案,不僅更適合我們在移動端中集成,且有足夠的經驗來優化它。同時,在 Android 上我們將邏輯的代碼合入 native 層中,還能進一步優化網絡 IO、TLS 等關鍵性能。
這里特別要提到我們之前使用的 cronet 方案是來自B站移動端基礎架構優化過的修改版本,在一些特定的場景給予了我們業務更高的自由度,比如請求優先級等。常見的在 iOS 上原生支持自定義 DNS 過程其實都是一個比較取巧的方案,特別是在處理 https 請求的一些過程上,我們是用了 cronet 之后,才考慮 iOS 上也支持這塊。由于這里我們是使用的修改版 cronet 方案,這些問題已經都被優化的足夠好了,我們僅需要考慮如何啟用其中 WebSocket 的部分并提供給客戶端使用。
另外需要考慮的一點是 Android 上的 cronet 實際上它的 Java 層的初始化的配置和 native 層中使用的 Cronet C API 接口實際上不能直接兼容,這塊其實是在更早貓耳 Android 落地播放器使用 cronet 的作為 http 傳輸方案的時候已經得到了解決,并用于實驗不同協議的播放效果,參見 [貓耳 Android 播放框架開發實踐],而我們 iOS 和 PC 上直接使用的就是 Cronet C API 的包裝,這樣保證了多端全局的配置、埋點信息都是一致的且最大化了網絡的性能和端上可觀測的能力。
確定了方向,我們其實要做的事情也很簡單,因為在 Chromium 中 WebSocket 在某種程度上也是基于 http 已有過程的一種延伸,之前很多已有的優化方案可以直接對 WebSocket 生效,包括自定義 DNS 過程等。
這里我們僅將 `net/websockets` 中相關邏輯對客戶端進行了適配:
增加 cronet 適配層代碼,這里簡單貼下 native 接口 idl,Android 中 jni 的適配也是依樣畫葫蘆:
// Counterpart of UrlRequestCallback for websocket.
[Abstract]
interface WebSocketCallback {
/**
* The message type invoked by {@code OnMessage()}.
* 目前只能收到 text 或者 binary 兩種. continuation 已被合并處理.
*/
enum MESSAGE_TYPE {
CONTINUATION=0,
TEXT=1,
BINARY=2,
};
OnAddChannelResponse(WebSocket request, UrlResponseInfo info, string extensions);
OnMessage(WebSocket request, MESSAGE_TYPE type, Buffer buffer);
OnDropChannel(WebSocket request, bool was_clean, uint16 code, string reason);
OnFailed(WebSocket request, Error error);
OnCanceled(WebSocket request);
};
/**
* Controls an Websocket request.
* Initialized by InitWithParams().
* Note: All methods must be called on the Executor passed to InitWithParams().
*/
interface WebSocket {
// see https://www.iana.org/assignments/websocket/websocket.xhtml#opcode.
enum OPCODE {
CONTINUATION_FRAME=0,
TEXT_FRAME=1,
BINARY_FRAME=2,
CONNECTION_CLOSE_FRAME=8,
PING_FRAME=9,
PONG_FRAME=10,
};
[Sync]
InitWithParams(Engine engine,
string url,
WebSocketParams params,
WebSocketCallback callback,
Executor executor)=> (RESULT result);
[Sync]
Start()=> (RESULT result);
[Sync]
ReadFrames()=> (RESULT result);
[Sync]
SendFrame(bool fin, OPCODE op_code, Buffer buffer)=> (RESULT result);
[Sync]
Send(OPCODE op_code, Buffer buffer)=> (RESULT result);
[Sync]
Close(uint16 code, string reason)=> (RESULT result);
Cancel();
[Sync]
IsDone()=> (bool done);
};
// 請求參數.
struct WebSocketParams {
/**
* Array of HTTP headers for this request.
*/
array<HttpHeader> request_headers;
};
其中大部分的通用的參數都可以復用已有的 CronetURLRequest 的部分。
整體的架構和調用時機大致是這樣的,關系圖中有標星的位置是我們這次進行新加或調整的地方:
調用時機:
同時,我們對 WebSocket 的消息在內部進行了處理,由于協議支持消息是分片傳輸,為了簡化業務上消息處理的過程,將消息做了合并,最終一起回調給上層業務處理。
最后在端上再進行一次封裝,已有的重試、心跳等機制這里就不進行討論了,我們將端上業務中的和 native 代碼中 libwebsockets 的 WebSocket 都換成了 cronet 的實現,最終上線后收獲了非常可觀的收益:
在建連速度方面,Android 優化了 ~150ms,iOS 優化了 ~250ms,其中我們 Android 端上早在之前就已經落地通過 httpdns 的方式(包括 DNS 的緩存策略的優化等)優化 okhttp 建連的過程,iOS 之前的 WebSocket 實現 [SocketRocket](https://github.com/facebookincubator/SocketRocket) 依賴系統的 DNS,建連時長相比于 Android 會慢 50ms+,現在也和普通 HTTP 請求統一了 DNS 的策略,收益會更明顯點,符合我們的預期,最終也是補完了我們端上業務中最后一塊不支持自定義 DNS 過程的缺口。在失敗率方面,也和之前基本上一致,且上報上來的錯誤信息更具有可讀性,后續進行分析和監控都將更加清晰。下圖展示了不同版本間客戶端 WebSocket 連接失敗的錯誤信息,這里我們從 6.1.0 版本開始切換到 cronet 的實現,可以看到新版本的信息更加直觀和明確,極大地方便了研發人員定位具體問題。
隨著 WebSocket 的實現切換為 cronet,在我們客戶端本身的網絡診斷中也可以更加完整和準確反饋實際的 DNS 結果、錯誤信息和網絡質量等信息。
未來展望
前陣子 Node.js 22 的發布,其原生支持的 WebSocket 客戶端也旨在提供一個更加標準化的接口和使用的方式,說明了當前 WebSocket 仍能作為一種足夠優秀的方案被廣大開發者所認可。
值得一提的是,隨著互聯網技術的發展,WebSocket 也不是一成不變,WebSocket over HTTP/2 [RFC 8441](https://www.rfc-editor.org/rfc/rfc8441)和 WebSocket over HTTP/3 [RFC 9220](https://www.rfc-editor.org/rfc/rfc9220.html) 也被相繼定稿,其中 WebSocket over HTTP/2 也開始逐漸被各大瀏覽器、網關、開源庫支持,相對于 HTTP/1.1 中的 Upgrade 機制,在 HTTP/2 和 HTTP/3 中 WebSocket 的握手有了相當程度的簡化,換句話說就是可以更快。目前由于支持 WebSocket over HTTP/2 的服務端組件還不夠廣泛,暫時沒有在用戶側進行驗證,不過我們接入的 cronet 版本已經支持,僅需要先有一次 HTTP/2 的連接,確認服務端支持后就可以正常啟用,在我們的測試環境中也可以觀測到更好的效果。
除此之外,由于我們使用的修改后的 cronet 也支持配置下發域名通配符等方式強制使用 QUIC 通過 UDP 進行傳輸而無需與普通 TCP 的 HTTP 請求進行競速,目前僅用于在播放和下載場景中做一些實驗,后續也有望在 WebSocket over HTTP/3 的演進中得到更可觀收益。
作者:大前端 嗶哩嗶哩技術
來源-微信公眾號:
出處:https://mp.weixin.qq.com/s/JxJu7s01VLElfUcfEoISJA
直播成為風口開始,就在燒錢以及流量泡沫的質疑聲中成長。映客這家具有代表性的公司在資金和流量上都遭遇了困境。
資金缺口是賣身的重要原因。流量劇降已無力回天。
映客的核心數據:覆蓋率=安裝此應用的活躍設備量/監測活躍設備總量,活躍率=開啟次應用的活躍設備量/監測活躍設備總量。選擇宣亞,淪落的映客算是找到了出路。但是,直播行業的“風口”已到此為止。
2015年4月,映客獲得A8音樂500萬元的天使投資。映客正式上線。隨后,映客又完成了兩輪融資。
2015年11月,獲得賽富基金、金沙江創投、紫輝創投的1000萬元的A輪融資。
2016年1月,又獲得8000萬元的A+輪融資,其中昆侖萬維領投6800萬。此時,映客的估值僅為3.78億元。
借著直播“風口”的紅利,映客迎來快速增長,成為直播行業的明星公司。在光環之下,流量和資金上的問題從未遠去。
作為創業公司的映客并沒有大流量平臺的支撐,如何保持用戶增長是個問題。而且,一旦大流量平臺切入直播,映客的繁榮一戳就破。對用戶數據,映客更是選擇了自欺欺人的做法:數據造假——在直播房間中添加僵尸觀眾(機器人)。
2016年5月和9月,微博、陌陌相繼切入直播,映客早期積累的用戶優勢在大流量平臺面前逐漸減弱。
昆侖萬維在2016年9月出售映客3%的股權,套現2.1億,成為“風口”上映客的更大贏家。看來,估值增長17倍達到70億元的輝煌,成為了映客的絕唱。
鼎盛時期,國內的直播平臺超過200個。這些平臺大多和映客一樣,在三四季度開始降溫。頭部的YY、虎牙、斗魚滲透率均有不同程度的下滑,只不過映客下滑得更猛烈。
創業公司獨立IPO當然是更好的選擇。但無論從直播行業的走勢還是從映客的現狀來看:
一方面,沒有外部力量的幫助,映客從困境中翻身,并與微博、陌陌抗衡,幾乎不可能;另一方面,想講出一個讓投資人認可的新故事,也沒那么容易。
但宣亞+映客就不一樣了:傳統的營銷公司正在向新媒體營銷轉變,直播平臺提供了優質的傳播渠道。同時,有了宣亞的幫助,映客的收入結構更容易從C端用戶打賞分成,轉變為B端的廣告、營銷收入。
互聯網領域的并購案,無論滴滴收購優步、58同城收購趕集,都是在投資方的推動下進行的—一切都要以資本方的利益為前提。流量嚴重下滑的映客,恐怕連昆侖萬維套現時的70億元估值都難以維系,投資方如何套現獲利?放在A股里,可能就變成了一個完美方案。
當然,這樣一個各方都獲利的方案能不能實現還要看監管層能不能通過。
此前,趙薇旗下的龍薇傳媒試圖做一樁與宣亞類似的收購:以6000萬元加上15億元借款以及15億股權質押融資收購萬家文化,杠桿達到50倍。但這樁交易遭到證監會的否決。
映客能否“賣身”還不得而知,但它在降溫的直播行業已經夠幸運了。還有更多不幸的平臺正在倒閉的路上,或者已經倒閉。光圈直播因為A輪融資不利,官網停止服務,App從應用商店下架。據自媒體瑞萊觀點統計,愛鬧直播、網聚直播、美瓜直播、貓耳直播等10余家直播平臺。
投資界統計的一份116家直播平臺融資清單顯示,90%的直播還處于A輪及A輪之前,30%左右處于天使輪。這些平臺如果不轉型,恐怕很難活下去。
直播的泡沫隨時都會一戳就破,在如此危險的環境下,如何生存成為大難題!
本文來自生意我最行,創業家系授權發布,略經編輯修改,版權歸作者所有,內容僅代表作者獨立觀點。[ 關注創業家公眾號(ID:chuangyejia),讀懂中國7000種賺錢生意 ]
經記者 張虹蕾 每經編輯 張海妮
2016年,視頻直播進入紅海,出現近千家直播公司同時涌現的壯觀場面。2017年伊始,估值5億元的光圈直播倒閉,一時間,關于直播行業的死亡潮來臨之說甚囂塵上。
TMT領域知名研究人士布娜新告訴《每日經濟新聞》記者,直播平臺內容空洞、同質化嚴重,已引發觀眾的審美疲勞,在經歷狂熱過后,鑒于直播平臺的運維成本非常高,引流也會越來越困難。
不過,垂直類平臺則面臨著新機遇和挑戰,呱呱財經直播平臺負責人李磊表示,未來更加細分的垂直直播平臺可能會有更突出的表現。
多平臺“倒下”行業加速洗牌
光圈直播官網已無法正常訪問,在百度搜索“光圈直播”,相關搜索內容都是“撤資、欠薪”。這一局面的背后,則是其頗高的估值和資本曾經的青睞。據人民網報道,光圈直播2015年9月得到由合一資本、紫輝創投、協同創新3家投資的1250萬元天使輪融資。當時的光圈直播估值已超過5億元。
光圈直播的“倒下”,只是直播平臺現狀的一個側影,易觀互動娛樂分析師王傳珍告訴《每日經濟新聞》記者,2016年,直播從業廠商圍繞用戶流量展開了跑馬圈地的爭奪戰,在此階段,幾乎完成了以美女顏值、奇聞軼事、明星舔屏為推廣手段的用戶拉新。
不過,爭奪戰的背后則是內容的匱乏。艾媒咨詢顯示,77.1%的網民認為在線直播平臺存在低俗內容,90.2%的網民認為在線直播平臺的整體價值觀導向為一般或偏低。
據記者梳理,截至目前,趣直播、微播、網聚直播、貓耳直播、咖喱直播、美瓜直播等多家直播平臺已經下線或暫停服務。
齊聚科技CEO汪海濱認為,目前的網紅直播還處于混戰階段,最終獲得用戶的直播公司才能生存下去。2017年過后,大部分直播平臺將可能會因為定位模糊、盈利模式不清晰等原因而面臨倒閉或者被其他平臺收購,而一些人氣很高,具有良性生態模式的直播平臺將會獲得長久生存和發展。
多位業內人士認為,內容匱乏是行業加速洗牌的重要誘因,直播泡沫正在破裂,未來大而全的直播平臺少之又少,2017年垂直平臺將會迎來“升級”。
垂直類平臺“寒冬”突圍
毋庸置疑,行業加速洗牌和垂直類平臺的“新機”是2017年直播下半場的發展趨勢,而助推直播行業發展的資本也或許將發生“變革”。
據云投匯大數據顯示,截至2016年11月30日,全國共有31家網絡直播公司完成36起融資,涉及總金額達108.32億元。
艾媒分析師認為,在線直播行業除了人力成本外,還需要購買大量價格昂貴的專業設備和支付寬帶的費用,目前許多直播平臺都在虧損,或者是靠融資在做支撐。
在汪海濱看來,2017年將是資本回歸理性的過程,但是好的企業依然不會收縮自身的業務和資本;相對而言,不具有市場沉淀、之前盲目殺入市場拿到錢就開干的初創公司,可能會面臨巨頭的蠶食和資本的寒冬。
汪海濱預判2017年垂直類直播平臺將會獲得龐大的目標用戶,資本將會集中在幾大定位清晰、運營模式優質高效、人氣旺盛的直播平臺,也將會有資本看好財經、教育等垂直細分領域的直播公司。他提醒道,上述領域即便被資本投入也并不意味著能獲得巨額利潤。這需要一定的決心和勇氣,只求快速變現的互聯網產品是難以持續生存的。
(應被采訪對象要求,文中呱呱財經負責人李磊,主播栗子、寧寧、大白、李萌,直播公司聯合創始人王邁,某直播平臺負責人張曉均為化名)