百度 iOS 端長連接組件建設及應用實踐

作者 | 百度消息中臺團隊

導讀

在過去的十年裏,移動端技術飛速發展,移動應用逐漸成爲主要的便捷訪問和使用互聯網的方式,承接了越來越多的業務和功能,這也意味着對移動端和服務器之間的通信效率和穩定性提出了更高的要求。爲了實現更高效的實時通信和數據同步,長連接逐漸成爲一種關鍵技術,通過維持客戶端和服務器之間的持久連接,實現了雙方實時數據交換,避免了頻繁的建連和斷連開銷,從而提高用戶體驗、服務穩定性、可靠性等方面的表現。

本文旨在探討長連接技術在移動端的實踐,針對百度 iOS 端在建設長連接過程中的技術選型和整體架構邏輯將做重點展開。同時結合 IM 即時通訊案例的介紹和分析,展示長連接是如何在移動應用領域爲類似業務場景提供解決方案的。

本文將分爲五個主要部分。首先,對長連接技術進行概述,包括定義、與短連接的對比以及在移動互聯網領域的常見應用。接下來,會簡單介紹百度長連接服務,包括搭建的背景以及建成後提供的服務核心主流程。然後,將重點討論百度 iOS 端長連接 SDK 搭建過程中的挑戰和解決方案,包含協議的選擇、DNS 解析優化、長連接保活機制的設計等。緊接着,以 IM 即時通訊場景中的長連接實踐爲例,展示了長連接 SDK 是如何爲業務實現請求數據轉發、接收服務器主動推送等功能的。最後,對本文的主要內容做了總結,以及對長連接在移動端應用中未來的發展趨勢和前景進行了展望。

01 長連接簡介

1.1 認識長連接

長連接,指在一個連接上可以連續發送多個數據包,在連接保持期間,如果沒有數據包發送,需要雙方發鏈路檢測包。

1.2 長連接與短連接對比

1.3 長連接在移動互聯網領域的應用

長連接在移動互聯網領域有廣泛的應用,特別是在實現實時通信和消息推送等功能方面發揮了關鍵作用。例如,常見的微信、QQ 這樣的即時通信軟件,就是通過維持客戶端和服務器的長連接,實現即時傳輸信息的需求。又如一些網絡遊戲、定位服務、新聞推送等,也會使用長連接,實時推送新的動態或者消息給用戶。這樣,無論用戶在何時何地,只要連接到互聯網,就能夠接收到最新的信息,極大地提升了使用者的體驗度並且使得移動互聯網更加便捷。

總的來說,對實時性、數據傳輸效率、頻繁通信等有強需求的應用,長連接都是一個好的選擇。

02 百度長連接服務簡介

2.1 搭建統一長連接的背景

此前,百度移動端都是由各業務自運維的長連接,往往搭建和維護成本都偏高,且可複用性不大,因此計劃實現一套高併發、低時延、高觸達的統一長連接組件,能夠更靈活高效地支持各業務接入,能夠對百度系的各 APP 獨立輸出長連接服務滿足各業務的訴求,從而提升服務質量,降低資源成本。

2.2 長連接服務主流程圖

百度長連接服務包含客戶端的長連接 SDK 和服務端的長連接接入層兩個部分,長連接接入層又包含訪問控制模塊和接入模塊,負責維護長連接管理及業務數據轉發。下圖描述了長連接建連及心跳保活過程,業務登錄和登錄後推送過程,以及最終長連接 SDK 觸發斷連的過程。後文將針對 iOS 端長連接 SDK 的具體實現解決方案,和長連接 SDK 在百度 APP 中的業務應用落地進行更爲詳細的探討。

03 百度 iOS 端搭建長連接 SDK 的解決方案

3.1 客戶端搭建長連接的挑戰點概述

客戶端從 0 到 1 搭建一套完整的長連接 SDK,這個過程涉及到多個技術點的考慮,包括但不限於:連接的創建和維護,網絡協議的選擇,使用加密傳輸、驗證數據來源等方式保證長連接的安全性,通過數據傳輸格式選擇、數據壓縮等方式減少數據量提高傳輸效率,錯誤異常處理機制等,需要開發者根據實際情況進行最優實現方案的選擇。在這之中,最核心的可以拆解爲以下兩個部分:

1、連接的創建:完整建連流程的設計,網絡協議的選擇,設計時需要考慮長連接建連的成功率、時延等核心指標;

2、連接的維護:保證建連成功是第一步,長連接還需要保持維護雙方連接纔可達成持續通信的目的,這包括:在長時間無數據交互的情況下,需要定期發送心跳包進行連接的保活,以及長連接連接斷開後需要及時進行斷線重連恢復連接在線狀態。

3.2 核心邏輯一:連接的創建

長連接建連即客戶端與服務器建立連接,是長連接 SDK 要做的第一件事,所有業務方數據的傳輸(上下行)都要基於長連接建連成功的這個前提。長連接建連並不是一個單一簡單的操作,而是一個分階段進行的過程。本小節將主要討論在設計開發長連接建連模塊之前,需要重點考慮確認的幾個技術點和實現方案,以及百度 iOS 端長連接 SDK 最終實現的長連接建連完整過程的架構。

3.2.1 挑戰①:協議的選擇
問題點:UDP 還是 TCP

對於網絡編程這個話題,使用哪種數據傳輸層協議來實現通信是一個非常基礎但一直爭論不休的問題。UDP 和 TCP 各有各的應用場景,TCP 能提供可靠的數據傳輸,UDP 則有更高的傳輸效率,此處不再贅述 TCP 與 UDP 的區別,最終選擇哪種協議實現,是一個見仁見智的問題,需結合整體應用場景、開發代價、部署和運營成本等方面綜合考慮。

解決方案:TCP 爲主,同時小流量探索 QUIC 的潛****力

百度 iOS 端長連接 SDK 中現有兩套數據傳輸方案:

方案一:在長連接 SDK 建設初期,根據業內成熟技術方案選型的調研結果,及開發成本、維護便捷性的考慮,第一個方案是參考 CocoaAsyncSocket 框架改寫的,基於 Socket 原生開發,使用 TCP 協議,支持 TLS/SSL 安全傳輸,並且是線程安全的,該方案較爲成熟,使用便捷,建連成功率較高。目前百度 APP iOS 端中 90% 的用戶流量都是走的該方案實現的長連接邏輯。

方案二:一般穩定網絡傳輸都是通過 TCP,但在網絡基建本身已經越來越完善的情況下,TCP 一些設計本身的問題便暴露了出來,加之 TCP 是在操作內核和中間固件中實現的,因此對 TCP 進行重大更改幾乎是很難的事情,類似建連過程握手耗時長、隊頭阻塞等問題沒有得到很好地解決,讓我們開始考慮一些新的可能性。長連接 SDK 後續引入了基於 QUIC 協議實現的第二套方案。QUIC 協議是建立在 UDP 之上,並且實現了可靠傳輸,相比 HTTP2+TCP+TLS 協議,QUIC 具有不少優點:減少了 TCP 三次握手及 TLS 握手時間,改進了擁塞控制,並且沒有隊頭阻塞的多路複用,支持連接遷移等。百度 iOS 長連接 SDK 目前通過 NWConnection 引入了 QUIC 協議的實現。QUIC 的協議雖然比較先進,但這也意味着在工程實現方面有更多可優化的空間,目前方案二還處於小流量實驗階段,仍有很多優化工作有待後續進一步去落地。就當前放量所得到的數據來看,在長連接建連成功率及時延指標上,QUIC 實現方案都有較好的表現。

3.2.2 挑戰②:DNS 解析優化
問題點:國內移動端網絡所面臨的 DNS 疑難雜症

國內各 ISP 運營商的 LocalDNS 由於域名緩存、解析轉發、LocalDNS 遞歸出口 NAT 的原因,容易引起 DNS 被劫持造成服務不可用、DNS 調度不準確導致性能退化等問題。DNS 解析的效率和準確性,直接影響長連接建連的質量,進而影響公司的業務。

解決方案:HTTPDNS

因此在百度 iOS 端長連接 SDK 中,採用當前業界比較主流的解決方案:HTTPDNS,來替代 LocalDNS 解析。HTTPDNS 是利用 HTTP 協議與 DNS 服務器進行交互,繞開了運營商的 LocalDNS 服務,有效防止了域名劫持,提高域名解析效率。

3.2.3 完整解決方案:百度 iOS 端長連接建連整體流程
建連時機

在百度 APP 中,統一維護了一系列系統事件和生命週期供各個組件監聽。iOS 長連接 SDK 根據百度 APP 的業務特性,選擇在環境搭建完成事件後觸發長連接建連,即等待 APP 啓動必要數據比如首頁資源等加載完成後,開始觸發長連接建連。

建連完整過程

下圖展示了長連接 SDK 建連的四個過程:

獲取 Token

DNS 域名解析:如前所述,長連接 SDK 中使用 HTTPDNS 替代 LocalDNS 來防止 DNS 劫持、提高解析效率。同時在 iOS Release 環境下,爲提高 DNS 解析效率,本地建立了緩存機制,HTTPDNS 解析結果返回後會更新本地緩存,下次建連過程優先取緩存,緩存不合法才走網絡請求。

建立 Socket 連接:Socket 建連過程涉及到傳輸協議的選擇,根據前面介紹,iOS 長連接 SDK 目前是通過小流量實驗的方式,10% 的用戶走 QUIC 建連,90% 的用戶走 TCP 建連。

長連接登錄請求:攜帶 Token 中獲取的 access-token 上行請求完成鑑權,長連接登錄請求返回成功意味着整個建連過程完成,業務層可開始正常使用長連接進行通訊,若登錄返回報錯,則會觸發重連。

順利完成這四個階段後,長連接會在該鏈路上持續發送心跳包進行連接保活,在異常斷連或壓後臺等觸發的主動斷連之前,一直保持連接在線狀態,爲各個業務的數據傳輸提供通路。

3.3 核心邏輯二:連接的維護

3.3.1 維護連接的意義

上個小節介紹了長連接連接建立的全過程,長連接建連成功後,實際已處於可用狀態,即各業務基於長連接的通信已經可以正常進行。但在此之後,保持長連接的可用性也是非常重要的。如果長連接無法很好地保持,在連接已經失效的情況下服務端繼續推送下行通知而端卻收不到,造成資源的浪費,同時無法及時重新建連,對業務造成損失。

3.3.2 維護長連接的解決方案

針對可能導致長連接斷開的幾種主要原因,長連接 SDK 建立了對應的機制來保證連接的穩定性,可總結爲兩點:心跳保活和斷線重連。

解決方案①:心跳保活

心跳保活的定義:實現長連接保活的方式通常是採用應用層心跳,通過心跳包的超時或報錯等來執行重連操作。心跳一般是指某端(通常是客戶端)每隔一定時間向另一端(通常是服務端)發送自定義指令,以判斷雙方是否存活,因其按照一定間隔發送,類似於心跳,故被稱爲心跳保活。

百度 iOS 端長連接 SDK 心跳保活機制:長連接登陸請求成功後,解析返回數據,若服務端下發了心跳包的間隔時間,則以服務端下發的時間間隔持續發送心跳包進行連接保活,若沒有下發心跳包間隔時間,客戶端會默認 60s 間隔時間來觸發心跳包的發送。具體心跳保活過程見下圖。

解決方案②:斷線重連

斷線重連原理:在長連接可能被斷開的場景(壓後臺重進 APP、網絡狀態變更等),檢測長連接的可用狀態,監測到連接不可用時,及時觸發重連機制。

百度 iOS 端長連接 SDK 斷線重連機制:具體觸發斷線重連的時機見下圖,iOS 長連接 SDK 內部維護有串行隊列和統一的長連接狀態監測記錄,不會導致重複建連的發生。

04 長連接在百度 APP 中的應用與實踐

4.1 長連接在百度 APP 中的業務落地

長連接是客戶端到服務端的一種全雙工連接,建連完成後,可以爲業務方提供請求轉發、服務端主動推送等服務。在百度 APP 中,包括在線健康診療、高考志願填報諮詢、情感心理輔導等一系列實時諮詢服務,發送直播彈幕、加入某大 V 粉絲羣聊天、私信好友等多種用戶實時溝通場景的落地,以及實現用戶在線情況下雲端可及時主動下發配置控制端的基礎能力建設,都離不開長連接的支持。長連接爲各個業務與自己服務端的數據交互提供了穩定便捷的方式和渠道。

下圖爲百度 APP 中長連接與落地業務的結構示意圖。完整的長連接模塊包括了客戶端的長連接 SDK 和服務端的長連接接入層兩個部分,作爲各個業務與自己服務端數據交流的中間渠道,處理了包括連接建立與保活、實現各業務客戶端與自己服務端的數據雙向互發等邏輯。下面將重點關注長連接在 IMSDK 實時聊天通訊場景中的實踐。

4.2 長連接在 IM 即時通訊場景中的實踐

4.2.1 背景介紹

IMSDK,即百度消息中臺爲百度 APP 及百度系其他產品打造的具備應用內即時通訊能力的客戶端 SDK,包括多種用戶溝通場景:私聊、羣聊、聊天室、直播彈幕等,並幫助業務推送消息通知觸達用戶,建立 B 端和 C 端的溝通渠道。目前主功能諸如拉取會話列表、拉取消息、發送消息、消息已讀等均爲長連接實現。本小節將通過介紹用戶發送消息、用戶收到新消息通知這兩個 IM 及時通訊中的常見場景,展示長連接提供的數據轉發和服務器主動推送能力是如何在業務場景落地的。

4.2.2 實踐 1:實時聊天場景下用戶發送消息
實踐場景

實時聊天場景下,用戶在聊天框向自己好友發送一條消息,消息如果發送失敗了,應用通常會在本條消息氣泡旁展示一個紅歎號,這個應用場景對於互聯網用戶應該都非常熟悉。從技術角度看,本質上是業務客戶端向自己的服務器上行一個請求,服務器再將請求結果返回給客戶端。這是一個典型的需要頻繁點到點通信的場景,非常適合基於長連接來實現。長連接 SDK 對外提供了封裝好的長連接請求類,外部業務方諸如 IMSDK 在上行長連接請求時通過創建該類的實例,將上行所需參數和數據賦值給請求實例,並設置回調閉包用於接收和處理請求回執數據和結果,最後將請求發出。業務不需要考慮數據傳輸及轉發等邏輯,長連接會充當業務客戶端和服務器之間的通路,黑盒處理這個過程。

技術難點

對於長連接 SDK 而言,在這條通路上最重要也是比較複雜的邏輯點在於,各個業務方的上行請求和下行通知都是併發進行的,長連接 SDK 如何有序地管理數據流向。上行請求即寫流,接收下行數據即讀流,下面就讀寫流的管理,與請求同回執數據的匹配問題的解決方案作簡要的介紹。

技術實現

長連接 SDK 內就讀寫數據維護有兩個隊列:讀隊列和寫隊列,以及維護了一個緩存池用作請求實例和請求回執數據的匹配。業務方上行一個長連接請求,實際上是將請求任務添加到寫隊列中,如果此時處於可寫流狀態,還會觸發寫流。當 socket 建連成功以後,會取出寫隊列隊頭的任務,開始寫流,寫流完畢會檢查寫隊列是否爲空,不爲空繼續取隊頭任務執行,直至寫隊列爲空爲止。同時 socket 建連成功還會添加一次讀任務到讀隊列中,並檢查如果此時處於可讀狀態,便取出隊頭第一個讀任務,開始讀流,讀流成功後會繼續添加一個讀任務到讀隊列,循環讀流操作。

讀流得到的服務端下行返回數據,通過 serviceId(業務編號)+ methodId(長連接請求方法編號)+ 請求發起的時間戳組成唯一鍵值,去緩存區匹配到下行返回數據對應的請求體,通過回調的方式,將請求結果返回到調用方。該請求一旦被回調過一次,其實例將從緩存區被刪除,及時釋放緩存區內存,並且保證一次請求不會發生多次回調的情況。

4.2.3 實踐 2:實時聊天場景下用戶收到新消息通知
實踐場景

實時聊天場景下,用戶是如何收到別的用戶發送給他的新消息通知的呢?其實是依靠服務器的下行通知到客戶端。長連接不僅提供爲業務客戶端轉發上行請求的能力,還提供了服務端主動推送的服務。比如在 IM 業務中,依靠 IM 服務器下行新消息通知,來完成消息的實時接收和拉取。這些通知又是如何到達 IMSDK 的呢?其實它與上一小節 IMSDK 上行長連接請求的過程類似。

技術實現

在 IMSDK 的長連接管理類初始化階段,會對需要接收的下行通知方法進行註冊,這裏的註冊實際上指的就是上行多個長連接請求,每個請求有對應的 serviceID(業務編號)和 methodID(需要註冊的通知方法號碼)。跟上一小節長連接請求不同的點在於,這些請求在收到回執數據後不會從長連接 SDK 請求緩存區裏移除,而是會長期存在,只要讀流時讀到了對應 methodID 的數據,就能在請求緩存區找到對應請求,將下行數據傳到 IMSDK 了。這樣一來,只要長連接在線,業務方就能實時接收到其服務器下行的通知消息了。

05 結語

長連接服務的核心大致可分爲:建連過程、連接維持過程以及數據傳輸過程。本文給出了搭建長連接服務過程中面臨的一些挑戰和解決方案,並結合長連接功能在百度 APP 即時通訊場景下的實踐,簡要介紹了百度 iOS 端長連接 SDK 的整體架構。

在移動端,長連接技術的應用前景非常廣闊。隨着 5G 和 6G 等高速移動網絡的發展,將使得移動應用程序能夠更加高效地使用長連接技術,從而實現更加實時和高效的數據交換。這也爲對實時數據交換有強需求的應用場景提供了更廣闊的想象空間,諸如物聯網、智能家居、虛擬現實和增強現實等技術,長連接都將在其中發揮更加重要的作用。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/5QvP30J0R4r3_uGHhfAxFA