標籤:
轉: http://geek.csdn.net/news/detail/58738
文/孫玄
本文詳細講述58同城高效能移動Push推送平台架構演化的三個階段,並介紹了什麼是移動Push推送,為什麼需要,原理和方案對比;移動Push推送第一階段(單平台)架構如何設計;移動Push推送典型效能問題分析解決,以及高可用、高效能、高穩定性如何保證。
什麼是移動Push推送
移動Push推送是移動互連網最基礎的需求之一,用於滿足移動互聯環境下訊息到達App用戶端。以轉轉(58趕集旗下真實個人的閑置交易平台)為例,當買家下單後,我們通過移動Push推送訊息告訴賣家,當賣家已經發貨時,我們通過移動Push訊息告訴買家,讓買賣雙方及時掌握二手商品交易的即時訂單動態。
為什麼需要移動Push推送?
移動互連網絡環境下,經常會出現弱網環境,特別是2G、3G等網路環境下,網路不夠穩定,App用戶端和相應伺服器端的長串連已經斷開,訊息無法觸達App用戶端。而我們業務需要把Message(轉轉App交易訊息等)、Operation(轉轉App運營活動等)、Alert(轉轉紅包未消費提醒等)等訊息推送給App用戶端,從而觸發使用者看到這些訊息,通過點擊這些Push訊息達到相應目標。
推送原理和方案對比
移動Push推送主要有以下三種實現方式。
- 移動App輪詢方式(PULL)
App用戶端定期發起Push訊息查詢請求,來達到訊息推送的目的。PULL方案的優點和缺點都比較明顯,整體架構簡單但即時性較差,我們可以通過加快查詢頻率,提高即時性,但這會造成電量、流量消耗過高。
- 移動App基於簡訊推送方式(SMS Push)
通過簡訊發送推送訊息,並在用戶端置入簡訊攔截模組,能攔截簡訊,並解析後轉寄給App應用處理。這個方案即時性好、到達率高,但成本很高。
- 移動App長串連方式(Push)
移動Push推送基於TCP長串連實現,訊息即時性好,這是目前主流的實現方式,需要維護App用戶端和服務端的長串連心跳,會帶來額外的電量、流量消耗;在架構設計時,需要做些折中,以避免流量和電量的大量消耗。此外Push推送技術架構複雜度較高,維護移動App用戶端的海量長串連請求,並建立與App用戶端通訊的加密通道,整合成內部少量有限的長串連,對通訊資料進行壓縮與解壓,以節省流量。
目前移動Push推送技術基本都是結合這3個方案進行,但對於不同的移動終端平台,又有各自不同的實現,這裡詳細介紹iOS和Android平台上的具體實現方案。
iOS平台
對於iOS平台,由於其特殊性,移動Push推送相對簡單,iOS應用是不允許service後台常駐的,所以你沒有別的選擇,也沒辦法通過開發自己的Push service來完成推送下發,只能通過蘋果APNS方式來完成。iOS移動Push推送流程1所示。
圖1 iOS移動PUSH推送流程
Android平台
在Android平台上,由於對service常駐沒有限制,可用的方案就多一些:可以通過Google官方C2DM 完成、開源方案(例如XMPP)、藉助第三方,或者完全自主研發的移動Push推送方案。
Google C2DM的主要流程2所示。
圖2 C2DM移動PUSH推送流程
Google C2DM和Apple APNS流程大致類似,但其最大的問題是移動Push推送伺服器在國外,很容易被屏蔽,而且Push推送延遲較大。此外由於 Android社區分裂比較嚴重,很多廠商直接就把C2DM模組給去掉了,所以在國內這個方案極不可靠,變成了一個理論上的方案。
移動Push推送開源方案
對於開源移動Push推送協議,常見的有XMPP等, 事實上Google的C2DM底層也是基於XMPP協議實現的,我們通過線下測試發現,開源移動Push推送方案主要有兩個問題:第一,沒有ACK機制,訊息到達沒有保證,不可靠;第二,當移動Push訊息請求量並發增大時,系統開始變得不穩定,甚至出現了模組宕機的情況。因此直接使用移動Push推送開源方案,也不是非常可靠,我個人建議:在大規模使用開源的移動Push推送方案之前,必須做到對開源技術方案整體把握住,不然一旦出現問題,無法及時定位和修複的話,帶來的後果將會是災難性的。
藉助第三方移動Push推送方案
除此之外,目前移動Push推送市場上,還有不少第三方推送產品可供選擇,但需要面臨以下幾個問題:
到達率
雖然第三方移動Push推送產品都宣傳到達率高於90%,但是實際使用起來,發現遠遠達不到。當然到達率低的問題,除了第三方移動Push推送平台本身技術原因外,還和業務推送方的使用者選取有很大關係,如果使用者較活躍,到達率就會高些,如果使用者不活躍,或者使用者已經卸載了相應的App用戶端,必然造成到達率進一步降低。
即時性&控制度
第三方移動Push推送產品的推送通道是共用的,會面向多個推送客戶,如果某一個客戶Push推送量特別大,那麼其他的訊息即時性可能就會受到影響,這些都是業務推送方不可控的,會比較被動。
完全自主研發的移動Push推送方案
我們曾經考慮實現一套完全自主的移動Push推送平台,如果從零開始來做,需要解決幾個痛點:第一,移動Push推送服務端對移動App用戶端海量長串連的維護管理。第二,App用戶端常駐 service穩定性,如何使Push service常駐?我們可以藉助父子進程互相監控的方式來做到,一旦發現對方進程不在了,會重建立立,繼續迴圈監控。第三,手機記憶體不足時,系統會殺掉Push service,甚至有些作業系統比較強勢,它會向iOS系統一樣並不允許第三方Push service 常駐。第四,移動Push推送到達率的提高,除了技術手段外,還有一些PR的手段,比如移動App用戶端Push service通過在相應作業系統上添加白名單的方式使其永久常駐。總之,在移動互聯複雜的情境下如何讓移動Push推送到達率變得更高,不是一件簡單的事兒。
58同城移動Push推送方案
我們綜合考慮前面講述的開源、基於第三方、完全自主研發方案,58同城並沒有選擇從零開始完全自主研發而是採用了基於第三方移動Push推送平台和自主研發高效能Provider的方案(3所示),滿足每天百億量級的輸送量,並通過動態組合和擴充的方式,結合離線的移動Push推送資料分析,不同手機使用不同的推送策略,針對性地最佳化。在Android平台,我們融合多種第三方移動Push平台,從而有效提升到達率。
圖3 58同城移動PUSH推送平台技術架構
第一階段(單平台):架構如何設計
背景&需求
2011年我們研發了58幫幫,這是一款滿足58使用者和商戶之間溝通的即時通訊軟體,使用者間可以互相添加好友、收發訊息等。58幫幫的訊息推送基於App用戶端和伺服器的長串連,一旦這條長串連斷開,那麼IM服務端的訊息將無法推送給App用戶端,使用者也無法看到這些訊息。在iOS平台上,58幫幫App切換到後台後,App與IM的長串連斷開,訊息無法觸達,這時候我們需要藉助iOS APNS機制,IM訊息需要發送給APNS,APNS再轉寄對應的訊息到58幫幫App。Android切換至後台,App與IM的長串連保持,IM訊息可以正常推送,因此在這個階段我們需要解決的問題是在iOS平台上,當58幫幫App切後台後,IM在長串連斷開後的訊息觸達需求。
設計目標
基於上述的背景和需求,我們在設計移動Push推送第一階段(單平台)架構時,首先要滿足在iOS平台上,當IM長串連斷開後,IM訊息的能夠觸達到App用戶端。其次我們的移動Push推送協議設計也具備很好的擴充性,在可以預見的未來,Push推送平台將逐步接入更多的App,因此我們設計目標iOSProvider是一個通用的iOS推送服務。不同App通過使用不同的移動Push推送認證藉助同一iOSProvider完成移動Push訊息推送,對於不同App的接入,我們採用了設定檔方式動態擴充接入,iOSProvider根據所配置App認證與APNS建立並維護多條TSL串連。設定檔的格式如下:
第一個域#第二個域#第三個域#第四個域
其中,第一個域為推送服務類型Type,以備擴充,1為APNS;第二個域為內部定義的APPID號,對應服務的App;第三個域為App的Apple認證檔案名稱;第四個域為與APNS建立的串連數;
每個App接入的配置為一行,舉例如下:
1 #88 #zhuanzhuan.p12 #641 #66 #58tongcheng.p12 #32
除此之外,iOSProvider需要對每個接入App的APNS串連池進行管理,動態增刪TSL串連,具備動態重連機制,並具有單獨的反饋接收線程,用於非同步接收APNS返回無效的Token,反饋給移動Push推送業務方,用於下次移動Push訊息推送的最佳化。iOSProdiver根據Type、APPID選擇對應的APNS串連,通過推送線程組裝APNS包發送到APNS伺服器,4所示。
圖4 iOSProvider架構圖
第二階段(多平台):架構如何設計最佳化
隨著移動互聯時代的到來,58同城研發了多個App,每一個App都有移動Push訊息推送的需求(訊息、運營活動、到期提醒等),並且每一款App同時具有多個終端:Android版、iOS版等。在這樣的需求背景下,我們的移動Push推送平台需要繼續演化,如何演化呢?
iOS移動Push推送通道可以很好的滿足業務推送需求,但目前還不具備Android移動Push推送的能力,因此我們急需要研發Android移動Push推送通道。如何做?綜合目前可選擇的方案,我們選擇了基於第三方推送平台以及自主研發高效能AndroidProvider的方案。
首先重點講述針對Android移動Push推送的流程:第一,App用戶端向第三方移動Push推送平台註冊,擷取對應的App唯一標示(Token)。第二,App將Token資訊發送給AndroidProvider並集中儲存,以便後續基於Token的移動Push推送。第三,AndroidProvider通過HTTPS或者TSL的方式和第三方移動Push推送平台建立串連,並把需要推送的訊息發送到第三方移動Push推送平台。第四,第三方移動Push推送平台收到AndroidProver推送的訊息後,會把此訊息及時推送到App,從而完成整個推送過程,5所示。
圖5 Android移動PUSH推送流程
AndroidProvider子系統整體結構分為四個層次,第一層為業務方移動Push推送接入,用於眾多移動Push推送業務方的接入。第二層為網路互動層,用於接收移動Push推送業務方的訊息資料以及發送請求處理層的處理資料給業務推動調用。第三層為請求處理層,用於處理網路互動層放入請求隊列的資料,組裝成第三方移動Push推送介面需要的資料,通過HTTP或者HTTPS的方式調用下遊的介面,並等待請求結果的返回,把請求返回的結果放入回應隊列。第四層為第三方移動Push推送平台,由第三方提供,開放給使用方介面,供調用其功能,6所示。
圖6 AndroidProiver系統架構圖
隨著越來越多的移動App接入,移動Push推送需求趨向多樣化,同時移動Push推送商務邏輯複雜化(多終端、批量發送、商務規則多樣),公用策略每個業務方重複開發(深夜防打擾功能、發送頻率和發送速率的限制等),造成開發效率低下。為瞭解決這些問題,我們抽象了公用的邏輯,並進行了統一的封裝,對業務調用方透明,這些公用的邏輯包括:通用的策略和通用的控制,7所示。
圖7 Android移動PUSH推送演化業務架構
在移動Push推送第二階段(多平台)階段,我們具備了Android、iOS的通道服務能力,滿足推送訊息的需求。但是我們沒有提供統一的發送介面,業務方需要各自組包(Android、iOS)發送不同的推送通道,除此之外,推送通道效能方面還有待提升,推送通道穩定性還有待提升,此外推送通道包含了相對共同的商務邏輯,推送通道還不夠“純粹”。
第三階段:架構和協議如何設計和最佳化
移動Push推送第二階段還存在一系列的問題,因此在第三階段需要解決,並且隨著更多App接入,我們需要提供公司級統一的高效能移動Push推送平台。基於第三方移動Push推送平台,我們自主研發了滿足每天推送百億量級的高效能Provider,推送平台具備了高穩定性、接入方便,並提供了較高的推送到達率。
移動Push推送平台第三階段我們如何架構和設計?首先我們滿足對下遊接入方多種串連的管理(HTTP、HTTPS、TCP、SSL、TSL),具備了多種串連動態伸縮性,從而滿足Provider層對移動Push推送串連的要求。其次平台要具備高並發的特性,通過完全非同步設計和多線程支援,做到了高並發和支援10萬QPS輸送量。再次我們需要對接入下遊的錯誤進行處理,一旦發現串連被斷開等錯誤後,要能夠自動使用新的串連,並且對已經發出還沒到達App用戶端的推送訊息進行重發,以保證訊息不丟失。第四我們需要對通道進行封裝,對外提供統一的友好接入介面,屏蔽底層iOS和Android接入的差異性。最後在AndroidAlibaba Cloud Mobile Push方面,我們接入了更多的第三方推送平台,以達到更高的到達率。
基於這些方面的考慮,58同城移動Push推送平台採用了低耦合的分層架構設計(3所示),分為三層Push Entry、Push Transfer、Provider(iOSProvider和AndroidProvider)。其中Push Entry是業務方調用的入口,我們採用非同步訊息佇列的方式,提供了較高的業務方發送的速度,並且具備了訊息緩衝的功能,使得高峰期的海量移動Push訊息推送對整個平台衝擊較少,也起到了保護推送系統的作用。Push Transfer會從Push Entry層接收訊息進行解析,對推送訊息進行合法性檢查,如果格式不合法,直接丟棄,同時會進行接收到的推送訊息格式轉換成內部的訊息格式,分平台轉寄到iOSProvider或者AndroidProvider上;provider接收到Push Transfer的訊息後,會按照下遊需要的訊息格式(APNS協議、Android協議)進行轉換,進行訊息的下發,在下發的過程中,會進行訊息的重發,以確保訊息下發到第三方推送平台。
Provider模組內部如何設計?以iOSProvider為例,它分為三個層次:接入邏輯、商務邏輯、APNS出口。其中接入邏輯主要處理網路互動和請求分發;商務邏輯主要處理線程分裂擴充、並發處理和錯誤處理;APNS出口處理向APNS的發送邏輯,8所示。
圖8 iOSProvider模組結構圖
對於移動Push推送平台來說,追求達到率是我們最核心的指標,沒有之一。因此在Android方面,我們融合了多個第三方推送平台,通過機型控制,對不同的機型使用不同通道,進一步提升推送到達率。AndroidProvider層進行訊息推送策略的控制,先推送一通道,根據此推送通道ACK情況,是否繼續推送其他通道。推送多個Push通道,會出現推送訊息重複到達App用戶端的情形,此時需要App用戶端根據推送訊息ID進行去重,收到的重複推送訊息忽略處理。
典型效能問題分析解決以及高可用、高效能、高穩定性如何保證
在移動Push推送不斷演化的過程中,我們遇到了AndroidProvider並發低的問題,仔細分析,是因為我們採用HTTPS庫,由於庫中HTTPS的串連實現不是安全執行緒的,對每個HTTPS的請求都加鎖序列化處理,以保證線程的安全性。發現問題後,我們通過線上上增加多進程部署的方式暫時解決,使得我們有足夠的時間分析此問題產生的根本原因。經過深入分析,發現原因是我們對HTTPS的庫掌握不夠,導致加鎖粒度過大,通過HTTPS庫提供的更小粒度的鎖,我們不僅解決了線程不安全的問題,也提升了AndroidProvider的並發度,9所示。
圖9 HTTPS庫細部鎖定實現方式
總之,58同城統一的高效能移動Push推送平台通過無狀態化設計和冗餘部署等方式確保了推送平台的高可用,通過純非同步、動態多線程的支援提供推送平台的高效能,通過品質保證、多種監控機制(進程監控、語義監控、錯誤記錄檔監控、資料波動監控等),有問題及時發現處理保證了推送平台的高穩定性。
最後,我要感謝項目組的同學,特別感謝姚勁同學,有了你們持續不斷的努力和付出,才有了今天這篇文章;也感謝老婆大人,有你在背後默默的支援,才有了今天這篇文章。
孫玄:58趕集集團系統架構師,技術負責人,技術委員會架構組主任,也是58同城即時通訊、C2C技術負責人,負責58核心系統的架構以及最佳化工作。分布式系統儲存專家,前百度進階工程師,參與社區搜尋部多個基礎系統的設計與實現。
本文為《程式員》原創文章,未經允許不得轉載,訂閱2016年《程式員》請點擊 http://dingyue.programmer.com.cn
轉: 58同城高效能移動Push推送平台架構演化之路