【融云分析】 IM 即時(shí)通訊之鏈路保活

眾所周知螃诅,IM 即時(shí)通訊是一項(xiàng)對(duì)即時(shí)性要求非常高的技術(shù)啡氢,而保障消息即時(shí)到達(dá)的首要條件就是鏈路存活。那么在復(fù)雜的網(wǎng)絡(luò)環(huán)境和國(guó)內(nèi)安卓手機(jī)被深度定制化的條件下术裸,如何保障鏈路存活呢倘是?本文詳解了融云安卓端 SDK 在基于 TCP 協(xié)議實(shí)現(xiàn)鏈路保活方面的探索和經(jīng)驗(yàn)袭艺。

IM 系統(tǒng)整體框架

如上圖所示搀崭,為了保障鏈路存活,一套成熟的 IM 系統(tǒng)一般會(huì)包含消息鏈路和推送鏈路兩條長(zhǎng)連接通道猾编。當(dāng)有新消息到達(dá)時(shí)瘤睹,消息服務(wù)首先會(huì)判斷消息鏈路是否存活,如果消息鏈路處于存活狀態(tài)答倡,消息優(yōu)先從消息鏈路下發(fā)到客戶端轰传,否則會(huì)被路由到推送服務(wù)器,由推送鏈路下發(fā)瘪撇。

綜上所述获茬,鏈路保活涉及到消息鏈路和推送鏈路兩條鏈路的本蠹龋活策略恕曲。基于這兩條鏈路使用場(chǎng)景的不同叉存,甭肓活策略上除了心跳機(jī)制是相同的,其它奔吣螅活策略各有不同稿存。下面將詳細(xì)講解。

鏈路蓖啵活的必要性

基于 TCP 的 Socket 連接建立之后瓣履,如果不做任何處理,這個(gè)連接會(huì)長(zhǎng)時(shí)間存在并且可用嗎练俐?答案是否定的袖迎。原因有兩點(diǎn):

一、默認(rèn) Socket 連接無法及時(shí)探測(cè)到鏈路的異常情況,即使將 Socket 的屬性參數(shù) keepAlive 設(shè)置為 true 仍然無法及時(shí)獲取到鏈路存活狀態(tài)燕锥。這是因?yàn)?Socket 的連接狀態(tài)是由一個(gè)狀態(tài)機(jī)進(jìn)行維護(hù)的辜贵,連接完畢后,雙方都會(huì)處于建立狀態(tài)归形。假如某臺(tái)服務(wù)器因?yàn)槟承┰驅(qū)е仑?fù)載超高托慨,無法及時(shí)響應(yīng)業(yè)務(wù)請(qǐng)求,這時(shí) TCP 探測(cè)到的仍然是連接狀態(tài)暇榴,而實(shí)際上此鏈路已經(jīng)不可用了厚棵。

二、國(guó)內(nèi)運(yùn)營(yíng)商的 NAT 超時(shí)機(jī)制會(huì)把一定時(shí)間內(nèi)沒有數(shù)據(jù)交互的連接斷開蔼紧,這個(gè)時(shí)間可能只有幾分鐘婆硬,遠(yuǎn)無法滿足我們的長(zhǎng)連接需求。

通用奔槔活機(jī)制 - 心跳機(jī)制

基于以上原因彬犯,要維持 Socket 連接長(zhǎng)時(shí)間存活,就需要實(shí)現(xiàn)自己的绷ㄖ粒活機(jī)制躏嚎。最通用的一種保活機(jī)制就是心跳機(jī)制菩貌。即客戶端每隔一段時(shí)間給服務(wù)器發(fā)送一個(gè)很小的數(shù)據(jù)包,根據(jù)能否收到服務(wù)器的響應(yīng)來判斷鏈路的可用性重荠。為了節(jié)省流量箭阶,這個(gè)包一般非常小,甚至沒有內(nèi)容戈鲁。

那么客戶端如何實(shí)現(xiàn)定時(shí)發(fā)送心跳包呢仇参?一般有兩種方式:

一種是通過 Java 里的 Timer 來實(shí)現(xiàn)。最基本的步驟如下:

1婆殿、建立一個(gè)要執(zhí)行的任務(wù)TimerTask诈乒。

2、創(chuàng)建一個(gè)Timer實(shí)例婆芦,通過Timer提供的schedule()方法怕磨,將 TimerTask 加入到定時(shí)器Timer 中,設(shè)置每隔一段時(shí)間執(zhí)行 TimerTask , 在 TimerTask 里發(fā)送心跳包消约。這種方式實(shí)現(xiàn)起來較簡(jiǎn)單肠鲫,而且省電,不需要持有 WakeLock 或粮。缺點(diǎn)也很明顯导饲,長(zhǎng)時(shí)間在后臺(tái),進(jìn)程被回收或者系統(tǒng)休眠后, Timer 機(jī)制隨之失效渣锦。

另外一種方式是利用安卓系統(tǒng)的定時(shí)任務(wù)管理器 AlarmManager 循環(huán)執(zhí)行發(fā)送心跳包的任務(wù)硝岗。這種方式不會(huì)因?yàn)橄到y(tǒng)休眠而失效,系統(tǒng)休眠后仍然可以通過 WakeLock 喚醒袋毙,執(zhí)行心跳任務(wù)型檀,因此相對(duì) Timer 機(jī)制,這種方式比較費(fèi)電娄猫,使用的時(shí)候一定要注意如下幾點(diǎn):

首先根據(jù)需求合理使用 AlarmManager 的鬧鐘參數(shù)贱除。鬧鐘各參數(shù)的區(qū)別參考下表:

其次 AlarmManager 提供了 cancel() 方法,在設(shè)置新的定時(shí)任務(wù)前媳溺,通過 cancel() 方法取消系統(tǒng)里設(shè)置的同類型任務(wù)月幌,避免設(shè)置冗余任務(wù)。

最后悬蔽,安卓從 6.0 版本引入了 Doze 模式扯躺,并提供了新的鬧鐘設(shè)置方法 setExactAndAllowWhileIdle(),通過該方法設(shè)置的鬧鐘時(shí)間蝎困,系統(tǒng)會(huì)智能調(diào)度录语,將各個(gè)應(yīng)用設(shè)置的事務(wù)統(tǒng)一在一次喚醒中處理,以達(dá)到省電的目的禾乘。推薦在安卓 6.0 以上系統(tǒng)中澎埠,優(yōu)先使用該方法。

消息鏈路笔寂海活機(jī)制

消息鏈路作為收發(fā)消息的主要通道蒲稳,需要最大程度保障鏈路的可用性。在鏈路不可用或者異常斷開時(shí)伍派,能及時(shí)探測(cè)并啟動(dòng)重連等保障機(jī)制江耀。基于以上特性诉植,消息鏈路除了前面所說的心跳機(jī)制外悬垃,還另外維護(hù)了兩套鏈路優(yōu)化機(jī)制:復(fù)合連接機(jī)制和重連機(jī)制张弛。

復(fù)合連接機(jī)制的基本步驟如下:

1. 客戶端連接導(dǎo)航服務(wù)器箫爷,導(dǎo)航服務(wù)器會(huì)下發(fā)應(yīng)用對(duì)應(yīng)的配置信息场绿,其中包括連接服務(wù)器的地址列表。

2. 客戶端從第一個(gè)服務(wù)器地址嘗試連接建车,并啟動(dòng)超時(shí)機(jī)制扩借,如果連接失敗或沒有及時(shí)收到服務(wù)響應(yīng), 則繼續(xù)嘗試連接下一個(gè)直到成功連接,將成功連接的地址保存到本地缤至,作為最優(yōu)地址潮罪,后面連接時(shí)優(yōu)先使用此地址康谆。通過這種機(jī)制,能保障客戶端優(yōu)先選用最優(yōu)鏈路嫉到,縮短連接時(shí)間沃暗。

重連機(jī)制,則是指業(yè)務(wù)層在檢測(cè)到與服務(wù)器的連接斷開后何恶,嘗試 N 次重新連接服務(wù)器孽锥,首次斷開 1 秒后會(huì)重新連接,如果仍然連接不成功细层,會(huì)在 2 秒后(重連間隔時(shí)間為上次重連間隔時(shí)間乘 2 )嘗試重新連接服務(wù)器惜辑,以此類推當(dāng)嘗試重連 N 次后,仍然連不上服務(wù)器將不再嘗試重新連接疫赎,只有在網(wǎng)絡(luò)情況發(fā)生變化或重新打開應(yīng)用時(shí)才會(huì)再次嘗試重連盛撑。

推送鏈路保活機(jī)制

推送鏈路作為消息到達(dá)的補(bǔ)充手段捧搞,要求盡可能延長(zhǎng)在后臺(tái)的存活時(shí)間抵卫。即使被殺后,仍然能被再次喚醒胎撇。iOS 手機(jī)有 APNS 來達(dá)到以上效果介粘,但安卓的官方推送系統(tǒng) FCM 在國(guó)內(nèi)基本不可用。那在國(guó)內(nèi)安卓系統(tǒng)上如何保障推送到達(dá)呢晚树?首先咱們需要先了解下安卓系統(tǒng)上進(jìn)程管理的兩大機(jī)制:

一種是 LMK 機(jī)制姻采,英文是 Low Memory Killer, 基于 Linux 的內(nèi)存管理機(jī)制衍生而來。主要是通過進(jìn)程的 oom_adj 值來判定進(jìn)程的重要程度爵憎,從而決定是否回收這些進(jìn)程偎谁。oom_adj 的值越低,代表重要度越高纲堵,比如 native 進(jìn)程,framework 層啟動(dòng)的系統(tǒng)進(jìn)程闰渔,優(yōu)先級(jí)一般都為負(fù)數(shù)席函。其次是前臺(tái)可見進(jìn)程,系統(tǒng)也不會(huì)回收冈涧。然而可見進(jìn)程退到后臺(tái)后茂附, oom_adj 的值會(huì)立即升高,在系統(tǒng)定時(shí)清理時(shí)被殺督弓。

另外一種機(jī)制是安卓原生的權(quán)限管理機(jī)制(AppOps)营曼,各大廠家在此基礎(chǔ)上又進(jìn)行了深度定制化,比如小米的安全中心愚隧,華為的手機(jī)管家等蒂阱,都用來進(jìn)行權(quán)限管理。該權(quán)限管理機(jī)制運(yùn)行在安卓系統(tǒng)的框架層,上層各應(yīng)用的進(jìn)程如果想嘗試重新啟動(dòng)录煤,系統(tǒng)首先會(huì)去權(quán)限管理中心檢查該進(jìn)程有沒有自啟動(dòng)權(quán)限鳄厌,如果有,才準(zhǔn)予啟動(dòng)妈踊。否則了嚎,從框架層直接限制系統(tǒng)的啟動(dòng)。

基于以上兩種機(jī)制廊营,推送鏈路的蓖嵊荆活也可分為兩大類,

一 進(jìn)程甭锻玻活呐伞。它的思路是根據(jù) LMK 機(jī)制提高進(jìn)程優(yōu)先級(jí),降低被殺的幾率邀窃。主要有以下幾種方法:

監(jiān)聽黑屏事件荸哟,啟動(dòng) 1 像素透明 Activity ,使應(yīng)用進(jìn)程轉(zhuǎn)為可視進(jìn)程瞬捕,降低被殺概率鞍历。在屏幕亮?xí)r,關(guān)閉該 Activity肪虎。

雙服務(wù)守護(hù)劣砍。A 服務(wù)以 startForeground() 形式啟動(dòng),發(fā)送一個(gè)通知扇救,B 服務(wù)同樣以 startForeground() 形式啟動(dòng)刑枝,且發(fā)送和 A 相同 ID 的通知,然后在 B 服務(wù)里調(diào)用 stopForeground() 方法迅腔,取消通知装畅。這樣 A 服務(wù)就會(huì)以前臺(tái)進(jìn)程的形式存活,且不影響用戶感知沧烈。

根據(jù)文件鎖互斥原理掠兄,監(jiān)視 Java 進(jìn)程存活狀態(tài),若被殺锌雀,Linux 層成功持有文件蚂夕,則通過 exec() 命令,打開一個(gè)純 Linux 的可執(zhí)行文件腋逆,開啟一個(gè) Daemon 進(jìn)程, 該進(jìn)程因?yàn)閺?Linux 層啟動(dòng)婿牍,在安卓 5.0 之前,優(yōu)先級(jí)會(huì)比較高惩歉,不會(huì)被殺等脂。在安卓 5.0 之后俏蛮,該方式不再有效。

二 進(jìn)程拉活的策略和安卓系統(tǒng)的 AppOps 機(jī)制有關(guān)慎菲,一般有如下幾種:

一嫁蛇、利用 Service 本身的 Sticky 屬性,在 Service 的 onStartCommand() 中返回START_STICKY露该,這樣當(dāng) Service 被殺掉后睬棚,系統(tǒng)會(huì)自動(dòng)嘗試重啟。不過在國(guó)內(nèi)定制化的系統(tǒng)上解幼,這種方式能成功重啟的幾率很低抑党,需要用戶在權(quán)限管理中心打開自啟動(dòng)等權(quán)限,才能成功拉活撵摆。

二底靠、也就是前面講過的心跳機(jī)制,不過這里要求使用 AlarmManager 設(shè)置 ELAPSED_REALTIME_WAKEUP 屬性的鬧鐘特铝,在系統(tǒng)休眠后暑中,才會(huì)正常接受到心跳事件,從而將進(jìn)程拉活鲫剿。

三鳄逾、通過監(jiān)聽網(wǎng)絡(luò)切換,用戶行為等事件灵莲,拉起進(jìn)程雕凹。

四、應(yīng)用間互相拉活政冻。比如系統(tǒng)里有好幾個(gè)應(yīng)用集成了同一個(gè) SDK , 那么在用戶啟動(dòng)其中某一個(gè) App 的時(shí)候枚抵,SDK 會(huì)去掃描其它應(yīng)用,把"兄弟姐妹" 拉活明场。這種方式對(duì)用戶體驗(yàn)傷害非常大汽摹,會(huì)造成系統(tǒng)莫名其妙的耗電。

隨著安卓系統(tǒng)版本的迭代苦锨,對(duì)后臺(tái)進(jìn)程的啟動(dòng)管控越來越嚴(yán)竖慧。為了解決推送的問題,各手機(jī)廠家推出了自己的系統(tǒng)級(jí)推送服務(wù)逆屡。由廠家在 Framework 層統(tǒng)一維護(hù)一條推送通道,上層所有應(yīng)用共同使用該推送鏈路踱讨,不需要再維護(hù)單獨(dú)進(jìn)程魏蔗。當(dāng)前支持系統(tǒng)級(jí)推送的廠家有:小米、華為痹筛、魅族莺治、vivo廓鞠、OPPO,這種系統(tǒng)級(jí)別的推送省電,省內(nèi)存谣旁,到達(dá)率高床佳。應(yīng)用可以根據(jù)手機(jī)型號(hào)的不同,優(yōu)先使用廠家系統(tǒng)級(jí)別的推送榄审,再配合自身的逼雒牵活機(jī)制,最大程度保障推送的到達(dá)率搁进。

集成第三方系統(tǒng)級(jí)推送之后浪感,整個(gè)消息的收發(fā)流程可以參考下圖:

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市饼问,隨后出現(xiàn)的幾起案子影兽,更是在濱河造成了極大的恐慌,老刑警劉巖莱革,帶你破解...
    沈念sama閱讀 211,948評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件峻堰,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡盅视,警方通過查閱死者的電腦和手機(jī)捐名,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,371評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來左冬,“玉大人桐筏,你說我怎么就攤上這事∧磁椋” “怎么了梅忌?”我有些...
    開封第一講書人閱讀 157,490評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)除破。 經(jīng)常有香客問我牧氮,道長(zhǎng),這世上最難降的妖魔是什么瑰枫? 我笑而不...
    開封第一講書人閱讀 56,521評(píng)論 1 284
  • 正文 為了忘掉前任踱葛,我火速辦了婚禮,結(jié)果婚禮上光坝,老公的妹妹穿的比我還像新娘尸诽。我一直安慰自己,他們只是感情好盯另,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,627評(píng)論 6 386
  • 文/花漫 我一把揭開白布性含。 她就那樣靜靜地躺著,像睡著了一般鸳惯。 火紅的嫁衣襯著肌膚如雪商蕴。 梳的紋絲不亂的頭發(fā)上叠萍,一...
    開封第一講書人閱讀 49,842評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音绪商,去河邊找鬼苛谷。 笑死,一個(gè)胖子當(dāng)著我的面吹牛格郁,可吹牛的內(nèi)容都是我干的腹殿。 我是一名探鬼主播,決...
    沈念sama閱讀 38,997評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼理张,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼赫蛇!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起雾叭,我...
    開封第一講書人閱讀 37,741評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤悟耘,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后织狐,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體暂幼,經(jīng)...
    沈念sama閱讀 44,203評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,534評(píng)論 2 327
  • 正文 我和宋清朗相戀三年移迫,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了旺嬉。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,673評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡厨埋,死狀恐怖邪媳,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情荡陷,我是刑警寧澤雨效,帶...
    沈念sama閱讀 34,339評(píng)論 4 330
  • 正文 年R本政府宣布,位于F島的核電站废赞,受9級(jí)特大地震影響徽龟,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜唉地,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,955評(píng)論 3 313
  • 文/蒙蒙 一据悔、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧耘沼,春花似錦极颓、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,770評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春浸赫,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背赃绊。 一陣腳步聲響...
    開封第一講書人閱讀 32,000評(píng)論 1 266
  • 我被黑心中介騙來泰國(guó)打工既峡, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人碧查。 一個(gè)月前我還...
    沈念sama閱讀 46,394評(píng)論 2 360
  • 正文 我出身青樓运敢,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親忠售。 傳聞我的和親對(duì)象是個(gè)殘疾皇子传惠,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,562評(píng)論 2 349

推薦閱讀更多精彩內(nèi)容

  • [TOC] 即時(shí)通訊IM技術(shù)領(lǐng)域提高篇 即時(shí)通訊IM技術(shù)領(lǐng)域基礎(chǔ)篇[http://www.reibang.com...
    AllenWu閱讀 2,445評(píng)論 0 13
  • 國(guó)家電網(wǎng)公司企業(yè)標(biāo)準(zhǔn)(Q/GDW)- 面向?qū)ο蟮挠秒娦畔?shù)據(jù)交換協(xié)議 - 報(bào)批稿:20170802 前言: 排版 ...
    庭說閱讀 10,930評(píng)論 6 13
  • [TOC] 即時(shí)通訊IM技術(shù)領(lǐng)域基礎(chǔ)篇 即時(shí)通訊IM技術(shù)領(lǐng)域提高篇 議題 準(zhǔn)備工作(協(xié)議選型)網(wǎng)絡(luò)傳輸協(xié)議選擇 和...
    AllenWu閱讀 5,974評(píng)論 0 16
  • 在kindle上看到了簡(jiǎn)書…… 過來試一試,希望自己能夠經(jīng)常有輸出
    17年蝶閱讀 116評(píng)論 0 0
  • Part 1《寫作的早期訓(xùn)練》讀后感: 自媒體時(shí)代稻扬,為什么你的寫作不能變現(xiàn)卦方? 我今天看了篇文章,主要內(nèi)容就...
    侯沫若閱讀 370評(píng)論 1 1