大數據

以友盟+U-Push為例,深度解讀消息推送的篩選架構解決方案應用與實踐

本文作者:友盟+技術專家 劉章軍

業務背景

友盟+消息推送U-Push日均消息下發量百億級,其中篩選任務日均數十萬,篩選設備每分鐘峰值可達7億+,本文將分享友盟+技術架構團隊在長期生產實踐中沉澱的篩選架構解決方案。
**
如何保證百億級的下發量?**

友盟+U-Push篩選是Push產品的核心功能,其中實時篩選是面向推送要求較高的付費Pro用戶提供的核心能力之一,實現了用戶實時打標、篩選、分發、觸達的功能。友盟+U-Push的設備識別以device_token為基準,為保證儘可能的觸達我們留存了近期所有可能觸達客戶的device_token,以10億真實設備為例,每個設備安裝10個集成友盟+SDK的應用可以產生10個device_token,牽扯到硬件環境變動導致的device_token漂移問題,可能產生更多device_token。

image001.png

( 圖1.1.1 友盟+U-Push業務數據流簡圖)

image003.png

圖1.1.2 友盟+U-Push功能清單

U-Push篩選架構概覽

2.1 上下行兩個核心鏈路

U-Push服務由兩個關鍵鏈路組成,下行鏈路保證客戶消息的觸達,上行鏈路承載終端採數和與客戶服務端的數據同步。其中下行鏈路主要分為任務調度、篩選中心,上行鏈路主要服務是多種收數通道(為兼容歷史問題)和設備中心,上行通過設備中心實現跟下行橋接。

image005.png

圖2.1.1 友盟+U-Push篩選業務場景

在U-Push服務中,依照業務場景不同定義了多種任務類型,其中除單播、列播直接下發外組播、廣播、自定義播、自定義文件播均需要通過篩選服務處理後才可執行下發,下行鏈路中(如圖2.1.2)優先級最高是的任務受理和任務發送流程(紅色鏈路),即無論發生什麼情況都要保證客戶消息的正確下發,是U-Push服務穩定性的底線。出於融災考慮,篩選服務在架構上與主鏈路解耦。

image007.png

圖2.1.2 篩選和核心鏈路隔離

2.2 數據架構目標和設計

提到篩選,其本質是通過建立合理的標籤索引系統實現數據的快速定位。篩選的目標是U-Push核心設備庫,但是為避免篩選請求影響到核心庫穩定需要將待篩選集合分庫冗餘存儲,與一般OLAP,OLTP場景不同,U-Push篩選的應用場景更加苛刻。

不俗的在線任務併發能力

篩選本質還是在線場景,具有一定的併發能力,併發壓力主要在於壓榨系統IO上,通過合理的中間件使用、嚴謹的服務調度、針對性場景的差異化設計降低單次篩選的執行時間,提高併發。

實時海量數據分析和傳輸能力

篩選提供了多種分析維度(圖2.2.2),支持靈活的語法組合。篩選服務不僅要滿足對海量數據的實時查詢分析,還要支持對單次可能破億的結果集做低成本傳輸。

image009.png

圖2.2.2 篩選支持的字段類型

成本可控

一切問題都是成本問題,從行業看全民上雲後服務架構的成本問題更是備受關注,尤其在友盟+龐大的業務量下成本問題更加重要。

為下游任務並行發送創造條件

友盟+U-Push的發送層集群用於大量的發送節點,最理想的設計就是在任務篩選階段即完成數據切片、分發、調度,下游直接並行發送以達到最高效率。

U-Push篩選在持續的技術迭代中,和多領域專業團隊深度合作,充分利用不同組件的特性,通過整合Tair、AnalyticDB for MySQL(ADS)、OSS、MaxCompute(ODPS)、Lindorm、HBase、SchedulerX等產出了一套兼顧穩定、性能、和成本的均衡解決方案。

篩選分為離線和實時兩部分,離線通過ODPS生成設備主庫快照,導入ADS。實時通過消費數據上行服務的設備信息更新事件,實時更新ADS或者RDB庫。在執行篩選時候,對於較大結果集通過upload或者dump到OSS的方式輸出多個小文件,傳輸給發送鏈路下游執行並行發送。

image011.png

圖2.2.4 篩選服務數據流向

上述業務鏈路和數據結構介紹了篩選目前的整體設計,但是要應付複雜的客情和多變的業務場景還需要做更多細節設計。

設計細節

3.1 篩選庫的場景設計

從上面的概覽可以看出,篩選架構中的主要矛盾就是消息下行鏈路中海量數據的讀和上行鏈路中設備屬性更新的高頻寫的矛盾,解決這個矛盾需要大量的資源來保證數據一致性和性能,在常規的設計思路中在目前的成本資源下幾乎是不可行。大數據三大寶,冷熱分離分庫分表,通過業務分析調研,U-Push將業務分成若干場景,基於客戶的不同生命週期的業務訴求和服務能力將客戶指向不同場景,儘量優化客戶體驗。

image013.png

圖3.1.1 篩選庫的場景設計

組播和廣播篩選我們主要圍繞ADS來建設,ADS提供了實時和離線兩種更新方式,在產品形態上只對Pro客戶開放實時篩選能力,在架構設計上通過分庫的方式隔離不同層客戶的數據,提供差異化服務,提高穩定性。

離線部分:通過離線主庫保證了所有客戶的T+1篩選能力。在實際業務中離線主庫只有讀請求作為所有極端場景下的兜底,離線主庫以device_token分區,可以實現完全打散但是聚合查詢的時候性能稍差。為了提高部分客戶尤其是新客戶的體驗我們設計了新客戶離線庫,修改為客戶分區,提高了單客戶聚合查詢的效率。但是新客戶離線庫因客戶間的規模差異容易引發分區傾斜,生產中這個表需要持續關注,及時清理和轉移,否則在跑ads_loader的時候可能破線。

image015.png

圖3.1.2 離線主庫的分區狀態

image017.png

圖3.1.3 以客戶為分區的分區傾斜情況

實時部分:保證實時篩選服務體驗是整個系統的重點,將實時篩選再細分為VIP實時庫、測試設備庫(方便客戶接入階段實時獲取測試效果)、新客戶實時庫(新增客戶一般設備量很小,U-Push會免費提供一段時間的實時篩選服務)。與離線分區類似,在分區設計上同樣對大規模場景數據和較少規模場景的數據分表,特別的測試設備庫可能產生大量髒數據,整體隔離出來。

image019.png

圖3.1.2 客戶場景遷移

新客戶接入伊始基於客戶規模區分,在不同的生命週期節點會被引入特定的場景,在保證大盤能力的前提下儘量輸出更優質的客戶體驗。

3.2 利用OSS傳輸和切分文件

在上述設計中通過離線和實時的區分,降低了高頻寫可能對設備庫造成的影響。但是始終繞不過海量數據的傳輸問題,為規避這個問題U-Push採用差異化的設計思路,以結果集規模做區分,對大結果集直接通過ADS dump到OSS,基於不同客戶的並行度做遠程切分,在OSS完成upload和split操作後返回文件路徑集合,後續鏈路只保留文件路徑集,直至進入發送層執行並行發送。對小結果集通過select拉取到內存整合消息報文傳輸,後續鏈路直接發送設備ID。通過OSS做中間存儲,極大的降低冗餘的IO損耗。

ADS3.0由於整體架構改動改為通過外部表的方式dump到OSS,與2.0可以dump出單個文件不同3.0在dump後會產生一系列小文件直接導致原有的方案不可行,在通過和ADS團隊溝通後ADS特地在3.0版本完善了dump單個文件的功能,致謝ADS的同學。

image021.png

圖3.2.1 篩選查詢中的性能瓶頸風險

3.3 查詢緩存和預篩選

談到查詢場景,必然會有緩存的一席之地,與一般設計思路不同,U-Push直接放棄了針對實時篩選能力的查詢緩存,因為在這樣的設備量級下隨時的設備更新是必然。U-Push的實時篩選庫是一個高頻寫低頻讀的場景,但是對單次讀的要求比較苛刻,首先對未開啟實時功能的離線客戶,因為設備庫是快照形式,一天內的多次讀拿到的結果必然相同這時候設置緩存就很有意義,比如新聞、氣象、工具類客戶的習慣,一天內發送多次廣播,就不必每次再去重新生成篩選集文件。

image023.png

圖3.3.1 查詢緩存邏輯流程圖

預篩選功能的開發是個小插曲,前面講到U-Push放棄了對實時的查詢緩存,導致客戶的每次消息發送都要重新去生成文件,在保證數據實時性的角度考慮無可非議,但是遇到“較真”的客戶就很有壓力。比如新聞類客戶極度關注消息下發的時效性,通過開發者控制檯可以查看每個任務的篩選時間,有時候同類消息2s的差異也會引發客戶在DING群的"客訴"。客戶的訴求可以理解但是這也耗費了團隊大量的精力。通過和個別客戶溝通U-Push開發了預篩選功能,在客戶習慣性發送消息的前一段時間預先調度執行篩選邏輯生成設備ID集合,通過損失少量的數據時效性來壓縮消息下發時間,爭取消息發送速度。

image025.png

圖3.3.1 友盟+U-Push消息軌跡

3.4 Alias篩選的優化

篩選請求可以歸類為兩種場景:

Alias功能依賴的ID Mapping場景,NvN的設備ID和Alias映射。

tag組播和iOS廣播功能的select場景,條件查詢,基於ADS實現。

Alias功能簡介:Alias允許開發者為設備綁定別名,別名由alias_type,alias兩個屬性組成,譬如開發者可以標識設備A,為他增加alias_type=telephone_number, alias=13900000000以此來給設備A增加手機號的屬性。在發送消息時候可以繞開device_token,直接通過服務端指定alias實現觸達,alias是一個典型的NVN ID Mapping場景,一個設備在同一個alias_type下面同時只能擁有一個alias。這也是符合一般業務場景的,比如上例一般一個設備只有一個手機號,設置新手機號後會覆蓋原alias。如果需要滿足雙卡雙待的功能,需要設置兩個alias_type,即alias_type=telephone_number_main,alias_type=telephone_number_secondary。alias的一般使用場景是開發者通過自定義文件播上傳一批文件,文件內容為某個alias_type下若干設備alias的集合(百萬千萬級)。篩選服務掃描文件後依次找出alias值mapping的device_token。

3.4.1 Alias的早期設計

說到Mapping,輪詢,高吞吐查詢,首當其衝選Redis,早期的U-Push也是如此。

image027.png

圖3.5.1 alias早期數據結構設計

alias利用Redis的Set和Hash結構實現正查和反差的功能,為什麼反差用hash,前面講到1個設備在1個alias_type下只保存最新的alias。這也是出於保護用戶的目的,如果1個設備同時存在多個alias下,在開發者執行圈選的時候可能會多次選出這個設備造成多次無效觸達。

這個設計平淡無奇,的確也可以滿足絕大部分客戶的篩選場景,但是隨著業務量的增加有幾個問題逐漸暴露

輪詢成為海量設備查詢的瓶頸,且不可突破。

Redis數據持久化難的問題凸顯,數據分析難上加難。

Alias無法很好的滿足數據返還鏈路的需求。

3.4.2 研究Alias的解法

分庫的確是很好的思路但是仍然無法滿足性能問題和持久化問題,而且隨著行業對大數據的關注,數據返還也成為更多開發者的訴求。打通數據返還鏈路做好客戶數據的存、取、管、用已經是一個重要的行業方向。為了解決這個問題U-Push通過離線和實時相結合制定措施

分庫,增加KA級別客戶獨享庫,壓縮橫向擴容空間。

分層,基於Lindorm做持久化分層存儲。

離線留存,通過日誌系統留存下行篩選結果,一方面完善統計需求,一方面通過回執返還客戶。

3.4.3 基於Lindorm寬表的分層設計

用寬表代替Redis的Set設計做正查,用普通表基於設備ID的聯合主鍵做反查,在查詢時候通過將單次輪詢改為多次mget儘量壓縮IO損耗尋找響應性能和服務穩定的中間值,Lindorm的磁盤存儲可以滿足業務需求的同時通過exporter的配置實現lindorm數據T+1同步至ODPS。

image029.png

圖3.5.2 基於Lindorm款表的分層設計

3.4.4 數據遷移的嘗試和思考

數據遷移是在很多業務架構中都是痛中之痛,如何保證穩定、平滑、安全的遷移需要付出大量的成本。U-Push在Alias的數據遷移中做了多種方案的研究和思考。

Tair整體dump遷移,dump方案理論上可行但是有較大的業務風險,出於穩定性的考慮放棄。

寫請求增量更新,通過客戶的寫請求逐key遷移,會有漫長的灰度時間,且無法執行徹底清理,勝在穩定性強。

掃描設備主庫,分客戶批次灰度遷移。在U-Push的功能中,提供了appkey下alias_type的功能,客戶可以在開發者控制檯查詢appkey下的alias_type列表,為實現這個功能對appkey和alias_type做了集合索引,這個索引成為數據遷移的關鍵。通過掃描設備庫獲取appkey和device_token,結合alias_type去反查庫查找alias,再拿appkey+alias_type+alias去正查庫查詢device_token列表完成遷移。

第三種方法可以實現存量數據的完美遷移,對線上服務幾乎沒影響,但是在百億級設備下,以1wTPS計算仍然需要10天的時間,好在該方案可以實現單個客戶的灰度與回滾。

結語

U-Push篩選服務只是U-Push眾多服務中的一環,在友盟+巨大的業務量下,為滿足形形色色的各行業需求輸出了大量精緻的設計,本文列出的只是冰山一角,日均消息下發量百億級做到遊刃有餘離不開其他技術架構團隊在篩選服務迭代中的共同協作。

目前U-Push已經以Push通道為基礎,整合了微信、短信、隱私短信升級為多通道觸達服務,為眾多知名的App如:今日頭條、澎湃新聞、作業幫、易車等提供了觸達能力,後續持續接入支付寶小程序、頭條號等更多運營場景通道,持續為客戶提供穩定、高性能、低成本的觸達能力保證。

友盟+,國內領先的第三方全域數據智能服務商,截至2020年6月已累計為200萬移動應用和890萬家網站提供十年的專業數據服務。

Leave a Reply

Your email address will not be published. Required fields are marked *