系統通知,居然有人使用拉取?

無痕幽雨發表於2018-05-22

系統通知,居然有人使用拉取?

任何脫離業務場景的架構設計都是耍流氓。

 

廣義系統通知,有11的通知,以及一對多的通知,有相對實時的業務通知,以及能夠容忍一定延時的系統通知。結合具體的場景來看下,這樣的一些系統通知,究竟是推還是拉?

 

一、系統對1的通知

典型業務,計數類通知:

  • 10個美女新增了你為好友

  • 8個好友私信了你

很多業務經常有這類計數通知,通知結果只針對你,這類通知是推送,還是拉取的呢?常見的有這樣一些實踐:

 

如果業務需求對計數需求需要實時展現,例如微博的加好友計數,假如希望實現不重新整理網頁,計數就實時變化

  • 登入微博時,會有一個計數的拉取,對網頁端的計數進行初始化

int getCountByType(int countType)

  • 在瀏覽微博的過程中,一旦有人加你為好友,服務端對網頁端進行實時推送,告之增加了1個(或者N個)好友

int addCountByType(int countType, int diff)

這裡的思路是,一開始得到初始值,後續推送增量值,由網頁端計算最終計數並呈現最終結果。需要注意,針對不同業務,計數變化的差值可增可減。

 

上述方案的壞處是,一旦有訊息丟失,網頁端的計數會一直不一致,直至再次登入重新初始化計數。這個計算計數可以優化為在伺服器直接計算並通知網頁端最終的結果,網頁端只負責呈現即可,這樣網頁端的邏輯會變輕。

 

如果業務對此類通知的展現不需要這麼實時,完全可以通過拉取:

  • 只有在連結跳轉,或者重新整理網頁時,才重新拉取最新的通知,例如上述計數

int getCountByType(int countType)

這樣系統的實現會最簡單。需要注意,通知拉取要非同步,不要影響主頁面的快速返回。

 

系統對1的推送,例如針對1個使用者的業務計數推送,計數的變化頻率其實非常低,使用cache來儲存這些計數能夠極大提升系統效能。


更多計數系統架構實踐可詳見《計數系統架構實踐一次搞定》。

 

二、系統對多的通知

系統對多的通知訊息,會比系統對1的通知訊息複雜一些,以兩個場景為例:

  • QQ登入彈窗新聞

  • QQ右下角彈窗廣告

 

IM登入彈窗新聞

這個通知的需求是:

  • 同一天,使用者登入彈出的新聞是相同的(很多業務符合這樣的場景),不同天新聞則不一樣(但所有使用者都一樣)

  • 每天第一次登入彈出新聞,當天的後續登入不出新聞

 

不妨設有一個表存放彈窗新聞

t_msg(msg_id, date, msg_content)

有一個表來存放使用者資訊

t_user(user_id, user_info, …)

有一個表來存放使用者收到的新聞彈窗

t_user_msg(user_id, msg_id, date)

 

這裡的實現明顯不能採用推送的方式:

  • t_user_msg裡對於所有user_id推送插入一個msg_id,表示未讀

  • user每天第一次登入的時候,將當天的msg_id拉取出來,並刪除,表示已讀

  • user每天非第一次登入的時候,就拉取不到msg_id於是不會再次彈窗

這個笨拙的方式,會導致t_user_msg裡有大量的髒資料,畢竟大部分使用者並不會登入。

 

如果改為拉取的方式會好很多:

  • user每天第一次登陸時,將當天的msg_id拉取出來,並插入t_user_msg,表示已讀

  • user每天非第一次登陸時,則會插入t_user_msg失敗,則說明已讀,不再進行二次彈窗展現

這個方式雖然有所優化,但t_user_msg資料量依然很大

 

還有一種巧妙的方式,去除t_user_msg表,改為t_user表加一列,表示使用者最近拉取的彈窗時間

t_user(user_id, user_info, last_msg_date, …)

這樣業務流程會升級為:

  • user每天第一次登入時,將當天的msg_id拉取出來,並將last_msg_date修改為今天

  • user每天非第一次登入時,發現last_msg_date為今天,則說明今天已讀

這種方式不再儲存訊息與使用者的笛卡爾關係,資料量會大大減少,是不是有點意思?

 

IM右下角彈窗廣告

這個通知的需求是:

  • 每天會對一批線上使用者推送相同的彈窗TIPS廣告,例如球鞋廣告,手機廣告等

畫外音:如果1個推送一塊錢,5KW使用者推送收入就有5KW收入喲,一天推個幾次,實現1個億的小目標居然如此簡單。

 

最直觀的感受,這是一個for迴圈批量推送的過程。如果是推送,必須要考慮的問題是,推送限速控制,避免短時間內對系統造成衝擊,引發雪崩。

 

能不能用拉取呢?

完全可以,這是一個對實時性要求不太高的場景,使用者早1分鐘晚1分鐘收到這個廣告影響不大,其實可以藉助IM原本已有的keepalive請求,在請求返回時,告之“有訊息拉取”,然後採用拉取的方式拉取廣告訊息。


這個方案的好處是,由於5KW線上使用者的keepalive請求是均勻的,所以可以很均勻的將廣告拉取的請求同樣均勻的分散到一段時間內,避免5KW集中推送對系統造成衝擊。

 

三、總結

廣義系統通知,究竟是推送還是拉取呢?不同業務,不同需求,實現方式不同。

系統對1的通知:

  • 實時性要求高,可以推送

  • 實時性要求低,可以拉取

 

系統對N的通知:

  • 登入彈窗新聞,拉取更佳,可以用一個last_msg_date來避免大量資料的儲存

  • 批量彈窗廣告,常見的方法是推送,需要注意限速,也可以拉取,以實現請求的均勻分散

系統通知究竟是推還是拉,是一個相對比較簡單的場景。對於feed流,單聊群聊,狀態同步會更為複雜,這些場景,下期分解。


挖坑篇:《feed流,單聊群聊,系統通知,狀態同步,到底是推還是拉?

相關文章