本文由vivo互聯(lián)網(wǎng)服務器團隊李青鑫分享,有較多修訂和改動。
1、引言
本文內容來自vivo互聯(lián)網(wǎng)服務器團隊李青鑫在“2021 vivo開發(fā)者大會”現(xiàn)場的演講內容整理而成(現(xiàn)場演講稿可從本文末附件中下載)。
本文將要分享的是手機廠商vivo的系統(tǒng)級推送平臺在架構設計上的技術實踐和總結。這也是目前為止首次由手機廠商分享的自建系統(tǒng)級推送平臺的技術細節(jié),我們也得以借此機會一窺廠商ROOM級推送通道的技術水準。
(本文已同步發(fā)布于:http://www.52im.net/thread-4008-1-1.html)
2、關于作者
李青鑫,vivo互聯(lián)網(wǎng)服務器團隊架構師。
3、為什么需要消息推送
消息推送對于移動端APP來說,是很常見的業(yè)務特征,比如新聞APP中的最新資訊、社交應用中的系統(tǒng)通知、IM即時通訊應用的離線聊天消息等等。
可以說,沒有消息推送能力,APP就失去了實時觸達的能力,對于一個應用來說,它對用戶的“粘性”將大大下降。而對于用戶來說,信息實時獲取的能力也將大大降低,用戶體驗也將大幅下降。
4、消息推送的技術障礙
以我們日常最常見的IM應用來說,離線消息的推送是必備能力。
但隨著Android系統(tǒng)的不斷升級,離線推送已經(jīng)不單單是一個后臺服務加長連接那么理所當然了。
對于早期的Android系統(tǒng)來說,想要實現(xiàn)IM的離線消息推送并不困難,搞個后臺服務再加上socket長連接就算是齊活了。
但隨著Android系統(tǒng)的升級,針對后臺進程和網(wǎng)絡服務限制不斷加碼,為了繼續(xù)實現(xiàn)離線消息的推送,開發(fā)者們不得不跟系統(tǒng)斗志斗勇,搞出了各種?;詈诳萍迹热纾篈ndroid4.0之后的雙進程守護、Android6.0及之后的防殺復活術、以及發(fā)展到后來的騰訊TIM進程永生技術,一時間群魔亂舞、無比風騷(有興趣的同學,可以讀讀《Android進程永生技術終極揭秘:進程被殺底層原理、APP應對被殺技巧》這篇針對所有?;詈诳萍嫉目偨Y性文章)。
隨著Andriod 9.0的到來,基本從系統(tǒng)上堵死了各種?;詈诳萍嫉幕盥罚?span style="color: #888888;">詳見《Android P正式版即將到來:后臺應用?;睢⑾⑼扑偷恼嬲瑝?/a>》),各Android廠商的ROOM系統(tǒng)級推送通道也應運而生——華為推送、小米推送、魅族推送、OPPO推送、vivo推送,一時間從用戶的噩夢(?;詈诳萍紝τ脩衾_很大)變成了開發(fā)者的惡夢并持續(xù)至今(想要做好IM離線推送,如今的IM開發(fā)者們不得不一家家對接各手機廠商的離線推送,你說煩不煩)。
也別跟我說為什么不用Android官方的FCM服務(在國內這鏈接你能打開算我輸,至于為什么,你懂的。。。),也別我跟提那個統(tǒng)一推送聯(lián)盟(4、5年過去了,看樣子還要繼續(xù)等下去)。
于是,為了繼續(xù)搞定離線消息推送,IM的開發(fā)者們目前只有兩條路可選:
- 1)舉白旗向系統(tǒng)投降,放棄?;詈诳萍迹苯右龑в脩羰謩蛹影酌麊危ㄔ斠姟?a target="_blank" rel="noopener" style="color: #1d58d1; text-decoration-line: none;">Android保活從入門到放棄:乖乖引導用戶加白名單吧》);
- 2)一家一家對接各廠商的系統(tǒng)級推送通道(華為、小米、魅族、OPPO、vivo,悲劇的是,有些小眾廠商并沒自建推送的能力)。
隨著Android系統(tǒng)對于開發(fā)者保活黑科技的“堵”,手機廠商們搞出自家的系統(tǒng)級推送通道來“疏”,也算是理所當然。而這些廠商之中,vivo的系統(tǒng)級推送通道出現(xiàn)的算是比較晚的。
本篇文章的余下技術內容,算是目前為止首次由手機廠商分享的自建系統(tǒng)級推送平臺的技術細節(jié),我們一起來學習。
5、從技術角度了解推送平臺
推送平臺是做什么的?

從技術的角度上來看,推送平臺就是一個通過TCP長連接,將消息發(fā)送給用戶的平臺。所以推送平臺的本質其實就是借助網(wǎng)絡通道,將消息發(fā)送到用戶設備上。
大家日常都收到過快遞通知吧!當快遞員將快遞放到快遞柜中,快遞后臺就會自動推送一條消息,通知你有快遞。我相信,如果你是一位運營人員,你也會喜歡這種自動下發(fā)消息高效的方式。
大家感興趣的,可以通過vivo開放平臺入口,選擇消息推送來更進一步了解更多技術細節(jié),這里就不做展開了。
6、短連接與長連接
消息推送平臺的本質,就是通過長連接將內容、服務、用戶連在一起,將內容分發(fā)給用戶,為終端設備提供實時、雙向通信能力。
這里有個概念長連接,那么什么是長連接?
所謂的長連接就是:客戶端與服務端維持的一條、在相對較長的時間里、都能夠進行網(wǎng)絡通信的網(wǎng)絡連接(比如:基于TCP的長連接)。
為什么我們要采用長連接而不是短連接作為平臺底層的網(wǎng)絡通信?
先來看看短連接下消息下發(fā)的場景:使用短連接的方式就是輪詢,即客戶端定時的去詢問后臺有沒有設備A的消息,當有設備A的消息時后臺返回對應的消息,可能很多情況下都是無功而返,浪費流量。當后臺有消息需要發(fā)送給設備A時,因為設備A沒有過來取導致消息無法下發(fā)。
而使用長連接:當有設備A的消息時后臺直接發(fā)送給設備A而不用等設備A自己過拉取,所以長連接讓數(shù)據(jù)交互更加自然、高效。
7、業(yè)務需求驅動架構升級
對于系統(tǒng)的技術架構來說,它是動態(tài)的,不同階段都可能會發(fā)生變化。而推動架構進行演進的推力,主要來自于業(yè)務需求,一起來回顧,平臺的業(yè)務發(fā)展歷程。
自2015年立項以來,隨著業(yè)務量增長,不斷為系統(tǒng)添加功能特性,豐富整個系統(tǒng)的能力使其滿足不同的業(yè)務場景需求。比如支持內容完全審核、支持IM、支持IoT、支持WebSocket 通信等。
從圖上可以看到,業(yè)務量幾乎每年都有幾十億的增長,不斷攀高,給系統(tǒng)帶來了挑戰(zhàn),原有的系統(tǒng)架構存在的問題,也逐漸浮出水面,比如延遲、性能瓶頸。
架構服務于業(yè)務,2018年之前我們平臺所有服務都放在云上,但是依賴的其他內部業(yè)務部署在自建機房。
隨著業(yè)務量增長與自建機房的數(shù)據(jù)傳輸,已經(jīng)出現(xiàn)了延遲的問題,并且在逐漸惡化,不利于我們平臺功能的拓展。
所以在2018年下半年,我們對部署架構進行調整:將所有核心邏輯模塊都遷移到自建機房,架構優(yōu)化之后,數(shù)據(jù)延遲問題得到徹底解決,同時也為架構進一步演進奠定了基礎。從上面的圖中可以看到我們接入網(wǎng)關也進行優(yōu)化三地部署。
為什么要進行三地部署而不是更多區(qū)域部署呢?
主要基于以下三點考慮:
- 1)第一是基于用戶分布及成本的考慮;
- 2)第二是能為用戶提供就近接入;
- 3)第三是能夠讓接入網(wǎng)關具備一定容災能力。
大家可以設想下,如果沒有三地部署,接入網(wǎng)關機房故障時,那么平臺就癱瘓了。
隨著平臺業(yè)務規(guī)模的進一步擴大,日吞吐量達到10億的量級,用戶對于時效性、并發(fā)要求越來越高。而2018年的邏輯服務的系統(tǒng)架構已經(jīng)無法業(yè)務高并發(fā)的需求或者需要更高的服務器成本才能滿足高并發(fā)需求。
所以從平臺功能、成本優(yōu)化出發(fā),在2019年對系統(tǒng)進行了重構,為用戶提供更加豐富的產品功能及更穩(wěn)定、更高性能的平臺。
8、利用長連接能力給更多業(yè)務賦能
作為公司較大規(guī)模的長連接服務平臺,團隊積累了非常豐富的長連接經(jīng)驗。我們也一直在思考,如何讓長連接能力為更多業(yè)務賦能。
我們平臺服務端各個模塊之間通過RPC調用,這是一種非常高效的開發(fā)模式,不用每個開發(fā)人員都去關心底層網(wǎng)絡層數(shù)據(jù)包的。
我們設想一下,如果客戶端也能通過RPC調用后臺,這一定是非常棒的開發(fā)體驗。
未來我們將會提供VRPC通信框架,用于解決客戶端與后臺通信及開發(fā)效率問題,為客戶端與后臺提供一致的開發(fā)體驗,讓更多的開發(fā)人員不再關心網(wǎng)絡通信問題,專心開發(fā)業(yè)務邏輯。
作為一個吞吐量超過百億的推送平臺其穩(wěn)定性、高性能、安全都非常重要,接下來和大家分享,我們在系統(tǒng)穩(wěn)定性、高性能、安全方面的實踐經(jīng)驗。
9、vivo推送平臺的領域模型
從上圖的領域模型可以看出,推送平臺以通信服務作為核心能力,在核心能力的基礎上我們又提供了,大數(shù)據(jù)服務以及運營系統(tǒng),通過不同接口對外提供不同的功能、服務。
以通信服務為核心的推送平臺,其穩(wěn)定性和性能都會影響消息的時效性。
消息的時效性是指,消息從業(yè)務方發(fā)起用設備收到的耗時。
那么如何衡量消息的時效性呢?我們繼續(xù)往下看。
10、如何實現(xiàn)消息時效性的監(jiān)控與質量度量?
傳統(tǒng)的消息時效性測量方法如上圖左所示:發(fā)送端和接收端在兩個設備上,在發(fā)送的時候取時間t1、在接收到消息的時候取時間t2,這兩個時間相減得到消息的耗時。
但是這種方法并不嚴謹,為什么呢?因為這兩個設備的時間基準,很有可能是不一致的。
我們采用的解決方案如上圖右圖所示:將發(fā)送端和接收端放在同一個設備上,這樣就可以解決時間基準的問題。我們就是基于該方案,搭建了一套撥測系統(tǒng),來主動監(jiān)控消息送達耗時分布。
11、如何實現(xiàn)高性能、穩(wěn)定的長連接網(wǎng)關?
過去10年討論單機長連接性能時面對的是單機一萬連接的問題(C10K問題),而作為一個上億級設備同時在線的平臺,我們要面對的是單機100萬連接的問題。
作為長連接網(wǎng)關,主要職責是維護與設備端的TCP連接及數(shù)據(jù)包轉發(fā)。
對于長連接網(wǎng)關:我們應該盡可能使其輕量化。
我們從以下幾方面進行了自上而下的重構優(yōu)化:
- 1)架構設計;
- 2)編碼;
- 3)操作系統(tǒng)配置;
- 4)硬件特性配置。
具體的實施方法,比如:
- 1)調整系統(tǒng)最大文件句柄數(shù)、單個進程最大的文件句柄數(shù);
- 2)調整系統(tǒng)網(wǎng)卡軟中斷負載均衡或者開啟網(wǎng)卡多隊列、RPS/RFS;
- 3)調整TCP相關參數(shù)比如keepalive(需要根據(jù)宿主機的session時間進行調整)、關閉timewait recycles;
- 4)硬件上使用AES-NI指令加速數(shù)據(jù)的加解密。
經(jīng)過我們優(yōu)化之后,線上8C32GB 的服務器可以穩(wěn)定支持170萬的長連接。

另外一大難點在于連接保活:一條端到端的 TCP連接,中間經(jīng)過層層路由器、網(wǎng)關,而每個硬件的資源都是有限的,不可能將所有TCP連接狀態(tài)都長期保存。
所以為了避免TCP資源,被中間路由器回收導致連接斷開,我們需要定時發(fā)送心跳請求,來保持連接的活躍狀態(tài)(為什么TCP有這樣的問題?有興趣可以讀這兩篇:《為什么說基于TCP的移動端IM仍然需要心跳?;??》、《徹底搞懂TCP協(xié)議層的KeepAlive?;顧C制》)。
心跳的發(fā)送頻率多高才合適?發(fā)送太快了會引起功耗、流量問題,太慢了又起不到效果,所以為了減少不必要的心跳及提升連接穩(wěn)定性,我們采用智能心跳,為不同網(wǎng)絡環(huán)境采用差異性的頻率。
有關長連接心跳機制的更詳細資料,可以參閱:
12、如何實現(xiàn)億級設備的負載均衡?
我們平臺超過億級設備同時在線,各個設備連接長連接網(wǎng)關時是通過流量調度系統(tǒng)進行負載均衡的。
當客戶端請求獲取IP時,流量調度系統(tǒng)會下發(fā)多個就近接入網(wǎng)關IP:
那么調度系統(tǒng)是如何確保下發(fā)的ip是可用的呢?大家可以簡單思考下。
對于我來來說,我們采用四種策略:
- 1)就近接入 ;
- 2)公網(wǎng)探測 ;
- 3)機器負載;
- 4)接口成功率。
到底采用這幾種策略呢?大家可以想下,這兩個問題:
- 1)內網(wǎng)正常,公網(wǎng)就一定能聯(lián)通嗎?
- 2)連接數(shù)少服務器,就一定是可用的嗎?
答案是否定的,因為長連接網(wǎng)關與流量調度系統(tǒng)是通過內網(wǎng)進行心跳保活的,所以在流量調度系統(tǒng)上看到的長連接網(wǎng)關是正常的,但是很有可能長連接網(wǎng)關公網(wǎng)連接是異常的比如沒有開通公網(wǎng)權限等。
所以我們需要結合多種策略,來評估節(jié)點的可用性,保障系統(tǒng)的負載均衡、為系統(tǒng)穩(wěn)定性提供保障。
13、如何滿足高并發(fā)需求?
有這么一個場景:以每秒1000的推送速度,將一條新聞發(fā)送給幾億用戶,那么有的用戶可能是幾天后才收到這條消息,這就非常影響用戶體驗,所以高并發(fā)對消息的時效性來說是非常重要的。
從上圖的推送流程來看:會不會覺得TiDB會成為推送的性能瓶頸?
其實不會:初步看可能會覺得它們作為中心存儲,但因為我們采用分布式緩存,將中心存儲的數(shù)據(jù),根據(jù)一定的策略緩存到各個業(yè)務節(jié)點,充分利用服務器資源,提升系統(tǒng)性能、吞吐量。我們線上的分布式緩存命中率99.9% 為中心存儲擋住了絕大部分請求,即使TiDB短時間故障,對我們影響也比較小。
14、如何保障系統(tǒng)穩(wěn)定性?
14.1 概述
作為推送平臺,平臺的流量主要分為外部調用及內部上下游之間的調用。它們大幅波動都會影響系統(tǒng)的穩(wěn)定性,所以需要進行限流、控速,保障系統(tǒng)穩(wěn)定運行。
14.2 推送網(wǎng)關限流
推送網(wǎng)關作為流量入口,其穩(wěn)定性非常重要。
要讓推送網(wǎng)關穩(wěn)定運行,我們首先要解決流量均衡的問題即避免流量傾斜的問題。因為流量傾斜之后,很有可能會引起雪崩的情況。
我們是采用輪詢的機制,進行流量的負載均衡,來避免流量傾斜問題。
但是這里有兩個前提條件:
- 1)所有推送網(wǎng)關節(jié)點,服務器配置要保持一致,否則很有可能會因為某個處理能力不足導致過載問題;
- 2)應控制流入我們系統(tǒng)的并發(fā)量,避免流量洪峰穿透推送網(wǎng)關導致后端服務過載。
我們采用的是令牌桶算法,控制每個推送網(wǎng)關投放速度,進而能夠對下游節(jié)點起到保護作用。
那么令牌數(shù)量設置多少才合適呢?設置低了,下游節(jié)點資源不能充分利用;設置太高了,下游節(jié)點有可能扛不住。
我們可以采用主動+被動的動態(tài)調整的策略:
- 1)當流量超過下游集群處理能力時,通知上游進行限速;
- 2)當調用下游接口超時,達到一定比例是進行限流。
14.3 系統(tǒng)內部限速:標簽推送平滑下發(fā)
既然推送網(wǎng)關已經(jīng)限流了,為什么內部節(jié)點之間還要限速?
這個是由于我們平臺的業(yè)務特點決定的,平臺支持全量、標簽推送,要避免性能較好的模塊,把下游節(jié)點資源耗盡的情況。
標簽推送模塊(提供全量、標簽推送)就是一個性能較高的服務,為了避免它對下游造成影響。我們基于Redis和令牌桶算法實現(xiàn)了平滑推送的功能,控制每個標簽任務的推送速度,來保護下游節(jié)點。
另外:平臺支持應用創(chuàng)建多個標簽推送,它們的推送速度會疊加,所以僅控制單個標簽任務的平滑推送是不夠的。需要在推送下發(fā)模塊對應用粒度進行限速,避免推送過快對業(yè)務后臺造成壓力。
14.4 系統(tǒng)內部限速:消息下發(fā)時限速發(fā)送
為了實現(xiàn)應用級別的限速,我們采用Redis實現(xiàn)分布式漏桶限流的方案,具體方案如上圖所示。
這里我們?yōu)槭裁床捎玫氖莄lientId(設備唯一標識),而不是使用應用ID來做一致性hash?主要是為了負載均衡。
自從實現(xiàn)了這個功能之后,業(yè)務方再也不用擔心推送太快,造成自己服務器壓力大的問題。
那么被限速的消息會被丟掉嗎?當然不會,我們會將這些消息存儲到本地緩存、并且打散存儲到Redis,之所以需要打散存儲主要是為了避免后續(xù)出現(xiàn)存儲熱點問題。
14.5 熔斷降級
推送平臺,一些突發(fā)事件、熱點新聞會給系統(tǒng)帶來較大的突發(fā)流量。我們應該如何應對突發(fā)流量呢?
如上圖左所示:傳統(tǒng)的架構上為了避免突發(fā)流量對系統(tǒng)的沖擊,冗余部署大量機器,成本高、資源浪費嚴重。在面臨突發(fā)流量時,無法及時擴容,導致推送成功率降低。
我們是怎么做的呢?我們采用增加緩沖通道,使用消息隊列和容器的解決方案(這種方案系統(tǒng)改動小)。當無突發(fā)流量時以較小量機器部署,當遇到突發(fā)流量時我們也不需要人工介入,它會根據(jù)系統(tǒng)負載自動擴縮容。
15、基于Karate的自動化測試系統(tǒng)
在日常開發(fā)中大家為了快速開發(fā)需求,往往忽視了接口的邊界測試,這將會給線上服務造成很大的質量風險。
另外,不知道大家有沒有注意到,團隊中不同角色溝通時使用的不同媒介比如使用word、excel、xmind等,會導致溝通的信息出現(xiàn)不同程度折損。
所以為了改善以上問題,我們開發(fā)了一個自動化測試平臺,用于提升測試效率與接口用例覆蓋率,我們采用領域統(tǒng)一的語言減少團隊中不同角色溝通信息折損。另外還可以對測試用例統(tǒng)一集中管理,方便迭代維護。
16、內容安全
作為推送平臺,當然要為內容安全把好關,我們提供了內容審計的能力。
審計方法采用自動審核為主、人工審核為輔機制來提升審核效率。同時結合基于影響面及應用分級的策略進行內容審計。
從下圖中可以看到業(yè)務請求經(jīng)過接入網(wǎng)關轉發(fā)給內容審系統(tǒng)進行第一層本地規(guī)則的內容審計,如果沒有命中本地規(guī)則則調用我們諦聽系統(tǒng)進行內容反垃圾審計。
17、未來規(guī)劃
前面我們主要介紹了推送平臺這幾年的架構演進及演進過程中的系統(tǒng)穩(wěn)定性、高性能、安全等方面的技術實踐,接下來介紹未來的重點工作。
為了提供更易用、更穩(wěn)定、更安全的推送,未來將在以下方面持續(xù)投入建設:
- 1)在單模塊數(shù)據(jù)一致性的基礎上,實現(xiàn)全系統(tǒng)數(shù)據(jù)一致性;
- 2)將繼續(xù)完善各系統(tǒng)的熔斷降級能力;
- 3)平臺的易用性方面持續(xù)優(yōu)化,提供更加便捷的平臺服務;
- 4)建設異常流量識別的能力。
18、演講稿附件下載
本文內容對應的演講原稿附件下載:
vivo推送平臺架構演進(52im.net).pdf (1.93 MB )
演講原稿內容概覽:
19、參考資料
[1] Android6.0以下的雙進程守護保活實踐
[2] Android6.0及以上的保活實踐(進程防殺篇)》
[3] 為何基于TCP協(xié)議的移動端IM仍然需要心跳保活機制?
[4] Android版微信后臺?;顚崙?zhàn)分享(進程?;钇?
[5] 實現(xiàn)Android版微信的智能心跳機制
[6] Android P正式版即將到來:后臺應用?;睢⑾⑼扑偷恼嬲瑝?/a>
[7] 融云安卓端IM產品的網(wǎng)絡鏈路?;罴夹g實踐
[8] 正確理解IM長連接的心跳及重連機制,并動手實現(xiàn)
[9] 史上最強Android?;钏悸罚荷钊肫饰鲵v訊TIM的進程永生技術
[10] Android進程永生技術終極揭秘:進程被殺底層原理、APP對抗被殺技巧
[11] Web端即時通訊實踐干貨:如何讓你的WebSocket斷網(wǎng)重連更快速?
(本文已同步發(fā)布于:http://www.52im.net/thread-4008-1-1.html)