关于实时推送系统的那点事
出處:
http://mp.weixin.qq.com/s?__biz=MjM5NTU2MTQwNA==&mid=401006254&idx=1&sn=d69a0efc740e04ddefe3cdca14d56eb0&mpshare=1&scene=1&srcid=0302M9o0GjqZL27d4bRUBB1X#rd?
于小波,系統(tǒng)架構(gòu)師,2011年加入魅族,主要從事服務(wù)端后臺開發(fā)工作,專注于系統(tǒng)高并發(fā),分布式等解決方案。
大家好,我是于小波,2011年加入魅族,現(xiàn)在在魅族移動互聯(lián)網(wǎng)部門,主要負責(zé)服務(wù)端后臺架構(gòu)設(shè)計和開發(fā)工作。
很感謝ChinaUnix給的這個機會,非常榮幸可以和大家在這里分享我們魅族的一些技術(shù)。下面,我們進入今天的主題:關(guān)于實時推送系統(tǒng)的那點事。
今天的內(nèi)容主要分4個方面:系統(tǒng)介紹、架構(gòu)設(shè)計&微服務(wù)、踩過的坑&心得、監(jiān)控和灰度發(fā)布。重點介紹一下第三點,也就是一個心得分享。
我們先介紹一下這個系統(tǒng)。
魅族推送系統(tǒng)主要為魅族用戶提供以下服務(wù):系統(tǒng)&應(yīng)用升級、查找手機、聯(lián)系人同步、應(yīng)用商店、在線音樂、閱讀、游戲中心等,這里就不一一列舉了。
我們實時在線用戶是2500W左右,日PV 50億,在現(xiàn)有資源的情況下,推送速度最快可以到600W/分鐘。
這個是我們的系統(tǒng)架構(gòu)圖。
從邏輯上劃分了4層,最下面的是接入層,為用戶提供TCP長連接的接入和http服務(wù)。
第二層是消息分發(fā)層,主要功能是上行業(yè)務(wù)消息的分發(fā)到各個service,下行推送消息路由到用戶所接入的接入服務(wù)器,再由接入服務(wù)器發(fā)送到指定的用戶。路由表就是用來保存用戶的長連接信息和所在的接入服務(wù)器的位置。Webservice的功能后面會提到。
第三層是業(yè)務(wù)邏輯層,主要處理不同的業(yè)務(wù)邏輯。
第四層是存儲層,存儲用戶的離線消息和訂閱消息。
還有兩個比較獨立的監(jiān)控平臺和服務(wù)管理。
這個系統(tǒng)的是由很多小的服務(wù),每一個服務(wù)功能都比較單一,而且是獨立的集群,可以單獨部署。這里的服務(wù)都是異步無狀態(tài),要求高并發(fā)消息處理延遲低于1ms。
還有一個推送平臺,不在今天的討論范圍。
我們在開發(fā)這套系統(tǒng)的過程中,碰到了很多問題,下面列了幾個比較典型的問題和大家一起分享。
首先,是微服務(wù)的問題:
因為所有服務(wù)都要求高性能,所以我們開發(fā)了一套RPC框架 在魅族內(nèi)部叫kiev。kiev碰到了兩個問題:
1、同步調(diào)用
最開始我們這套框架都是同步調(diào)用,使用簡單,服務(wù)的開發(fā)效率高??墒请S著用戶量的增多,性能已經(jīng)滿足不了我們的要求。而且同步調(diào)用,我們?yōu)榱颂岣咝阅苁褂昧硕嗑€程,很多多線程的問題隨之而來。于是我們改進了我們的框架,使用異步。
2、異步問題
非常多的回調(diào)函數(shù),一套完整的業(yè)務(wù)邏輯被打散在各個回調(diào)函數(shù)來實現(xiàn),代碼的可維護性差,開發(fā)效率也不高,而且還有一個很突出的問題,我們在項目中使用了redis、mongodb、mysql的lib庫,而這些庫都是同步的,如果要做成全異步 那工作量會非常大。后面我們參照go語言用C++實現(xiàn)了一個協(xié)程版本的kiev,hook系統(tǒng)的IO調(diào)用 比如 send,recv等,把這些系統(tǒng)調(diào)用改成異步,達到的效果就是同步的調(diào)用,異步的性能。
我們碰到的第二個問題就是手機功耗問題。主要有兩個點:
1、手機流量消耗
這里就涉及到選擇怎樣的協(xié)議,傳統(tǒng)的方式就是XMPP和sip 這兩個協(xié)議是純文本協(xié)議,非常多的開源組件,能夠快速的搭建一套系統(tǒng),但是這兩個協(xié)議都是互聯(lián)網(wǎng)時代的產(chǎn)物,非常消耗流量。協(xié)議本身也非常復(fù)雜、冗余,單標準文檔就是幾十頁。
為了降低流量,我們的系統(tǒng)使用的是自定義的二進制協(xié)議,可以高度定制,編解碼的速度是上面兩個協(xié)議的10倍以上,流量節(jié)約了50%-70%。
2、手機電量消耗
因為我們是tcp長連接服務(wù),手機端為了保持這個長連接需要定期的發(fā)送心跳來維持。
一般的做法就是固定3分鐘或者5分鐘發(fā)一次心跳。因為發(fā)送心跳需要喚醒手機,如果心跳消息太頻繁 就會導(dǎo)致電量的消耗比較大,如果太久發(fā)一次心跳又沒法保證連接的穩(wěn)定性。
所以我們根據(jù)不同的網(wǎng)絡(luò)情況 指定了一套智能心跳模式,根據(jù)當前的網(wǎng)絡(luò)情況來設(shè)定發(fā)送心跳消息的間隔。
還有我們有一個延遲推送的策略。其實很多消息對實時性的要求并沒有那么高,比如說系統(tǒng)升級的推送,用戶早幾分鐘或者晚幾分鐘收到升級的推送并沒有多大的影響。針對這種情況,我們對于實時性要求不高的消息可以在手機處于喚醒狀態(tài)才推送,那問題來了,服務(wù)端怎么知道手機是喚醒的呢? 其實很簡單,收到用戶的心跳包,再推送消息。
第三個問題消息重復(fù)問題。
移動網(wǎng)絡(luò)的特點是不穩(wěn)定、高延遲。服務(wù)端發(fā)送消息給客戶端,客戶端收到消息返回應(yīng)答,如果應(yīng)答返回失敗了,服務(wù)端沒有收到這個應(yīng)答怎么辦?
1、超時重傳 這里就需要服務(wù)器保存每條消息的狀態(tài)那么服務(wù)端的邏輯就會非常復(fù)雜
2、等下次客戶端連接上來之后再重傳。
不管是怎么樣,這條消息都會重新發(fā)送,就導(dǎo)致客戶端收到重復(fù)消息。
解決辦法:改進消息流程如下圖。
當客戶端有消息的時候只發(fā)送一個通知告訴他,然后客戶端自己上來拉取消息,當然需要告訴服務(wù)端從什么地方開始拉取。所以客戶端需要保存最近收到的消息最大的序列號。
這個流程的好處就是客戶不會拉取到重復(fù)消息,而且服務(wù)端不用保存每條消息的狀態(tài),真正做到了業(yè)務(wù)無狀態(tài)。
第四個問題,移動網(wǎng)絡(luò)的DNS問題。
運營商的DNS服務(wù)是很不靠譜的,經(jīng)常宕機,延遲也很大,還容易被劫持。我們采用了全IP的接入方式。
具體就是客戶端通過http服務(wù)拉取接入層的IP列表,然后選擇一個IP直連。
這里訪問http服務(wù)的時候也可能會被劫持,我們使用預(yù)埋IP的策略,優(yōu)先使用域名訪問,域名不可用使用預(yù)埋的IP訪問。
第五個問題,海量連接的負載均衡問題。
我們單臺接入服務(wù)器可以承受400W的長連接。如果使用LVS來做負載均衡肯定是不行的,首先LVS存在單點問題。
我們解決的方式:
1、在客戶端獲取IP列表的時候,其實就是已經(jīng)排序過的,負載低的服務(wù)器IP排在前面。
2、客戶端跑馬策略,客戶端隨機選擇幾個IP 同時發(fā)送探測包 哪個IP響應(yīng)快就用哪個IP,這里服務(wù)端需要一個策略就是收到探測包 需要根據(jù)自己的實際負載情況決定是否延遲返回。這個跑馬策略解決了負載均衡的同時也解決了跨運營商網(wǎng)絡(luò)訪問慢的問題。
關(guān)于監(jiān)控:我們的系統(tǒng)是由很多的小的服務(wù)構(gòu)成,每個服務(wù)都是單獨的集群,如果集群中一個服務(wù)出問題,并不會影響整個業(yè)務(wù)的使用,但是如果這種問題累計起來,最后可能會導(dǎo)致系統(tǒng)不可用。
所以,只是單純的依靠簡單的業(yè)務(wù)監(jiān)控,很難發(fā)現(xiàn)未來可能出現(xiàn)的系統(tǒng)故障,所以 我們需要一套嚴格的監(jiān)控體系來發(fā)現(xiàn)潛在的問題。我們針對每一個服務(wù)都定義了一些強監(jiān)控指標。比如:
最后說一下灰度發(fā)布,灰度發(fā)布非常重要,線上的很多問題都是發(fā)布引起的,我們?yōu)榱私档桶l(fā)布的風(fēng)險,引入了灰度發(fā)布。灰度發(fā)布流程如下圖:
在沒有灰度發(fā)布之前我們開發(fā)人員都是凌晨才敢發(fā)布,所以我們的狀態(tài)就像下面這張圖。
有了灰度之后再也不用熬夜發(fā)布了。
好了,今天的分享就到這里結(jié)束了,感謝大家的支持,如果大家有什么問題的話,我們可以直接在這里一起探討,也可以加我微信私下探討。
【互動篩選】
Q1:灰度是什么?
A1:灰度是介于黑白之間的,平滑發(fā)布。
Q2:重復(fù)消息的問題,可否客戶端保存最近接收成功但應(yīng)答失敗的消息id,重復(fù)推送的消息客戶端直接忽略?
A2:這個客戶端不知道應(yīng)答發(fā)送失敗了。
Q3:推送的到達時間和一次到達率能達到多少?
A3:推送到達時間300ms以內(nèi)可以到達。到達率理論上是100% 因為我們有離線消息存儲,推送不成功的消息會下次再推送。
Q4:移動端的消息推送,和PC端的消息推送,區(qū)別在哪兒?實現(xiàn)的難點又在哪兒?
A4:移動端有盡量少的功耗( 電量和流量),pc端不用考慮這個問題。而且移動網(wǎng)絡(luò)非常不穩(wěn)定。
Q5:接入服務(wù)器均衡,負載高低度量指標是什么,鏈接數(shù)還系統(tǒng)級資源負載,或者其他的?
A5:鏈接數(shù)是其中一個指標。
Q6:如果移動端三天或三十天未上線,服務(wù)端要保存這么久么?
A6:不會,我們離線消息有超時機制,一般都是7天。
Q7:關(guān)于預(yù)埋ip策略,老師能講解下嗎?
A7:預(yù)埋IP就是在手機端寫死IP地址,如果需要變更 直接推送新的IP地址。
Q8:關(guān)于灰度發(fā)布這項技術(shù)魅族有打算開源嗎?
A8:目前還沒有計劃。
Q9:還有一個非技術(shù)問題,設(shè)計數(shù)百萬規(guī)模的推送系統(tǒng),由于公司不太自信,是購買商業(yè)產(chǎn)品還是自研好?
A9:如果你們有100W用戶了 當然是自己做,如果還沒有 可以用一些開源的。有100W用戶了說明你們的產(chǎn)品很好,當然要做的更好,吸引更多的用戶。
總結(jié)
以上是生活随笔為你收集整理的关于实时推送系统的那点事的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 慧荣SM2246XT、SM2246EN开
- 下一篇: GNU系统概览