系统通知,居然用拉取
廣義系統(tǒng)通知,有1對1的通知,以及一對多的通知,有相對實時的業(yè)務(wù)通知,也有能夠容忍一定延時的系統(tǒng)通知。任何脫離業(yè)務(wù)場景的架構(gòu)設(shè)計都是耍流氓,結(jié)合具體的場景來看下,這樣的一些系統(tǒng)通知,究竟是推還是拉?
?
第一大類:系統(tǒng)對1的通知
典型業(yè)務(wù),計數(shù)類通知:
(1)有10個美女添加了你為好友;
(2)有8個好友私信了你;
很多業(yè)務(wù)經(jīng)常有這類計數(shù)通知,通知結(jié)果只針對你,這類通知是推送,還是拉取的呢?常見的有這樣一些實踐:
?
如果業(yè)務(wù)需求對計數(shù)需求需要實時展現(xiàn),例如微博的加好友計數(shù),假如希望實現(xiàn)不刷新網(wǎng)頁,計數(shù)就實時變化:
(1)登錄微博時,會有一個計數(shù)的拉取,對網(wǎng)頁端的計數(shù)進(jìn)行初始化:
int getCountByType(int countType)
?
(2)在瀏覽微博的過程中,一旦有人加你為好友,服務(wù)端對網(wǎng)頁端進(jìn)行實時推送,告之增加了1個(或者N個)好友:
int addCountByType(int countType, int diff)
這里的思路是,一開始得到初始值,后續(xù)推送增量值,由網(wǎng)頁端計算最終計數(shù)并呈現(xiàn)最終結(jié)果。需要注意,針對不同業(yè)務(wù),計數(shù)變化的差值可增可減。
?
上述方案的壞處是,一旦有消息丟失,網(wǎng)頁端的計數(shù)會一直不一致,直至再次登錄重新初始化計數(shù)。這個計算計數(shù)可以優(yōu)化為在服務(wù)器直接計算并通知網(wǎng)頁端最終的結(jié)果,網(wǎng)頁端只負(fù)責(zé)呈現(xiàn)即可,這樣網(wǎng)頁端的邏輯會變輕。
?
如果業(yè)務(wù)對此類通知的展現(xiàn)不需要這么實時,完全可以通過拉取:
(1)只有在鏈接跳轉(zhuǎn),或者刷新網(wǎng)頁時,才重新拉取最新的通知,例如上述計數(shù)
int getCountByType(int countType)
這樣系統(tǒng)的實現(xiàn)會最簡單,需要注意,通知拉取要異步,不要影響主頁面的快速返回。
?
系統(tǒng)對1的推送,例如針對1個用戶的業(yè)務(wù)計數(shù)推送,計數(shù)的變化頻率其實非常低,使用cache來存儲這些計數(shù)能夠極大提升系統(tǒng)性能。
?
第二大類:系統(tǒng)對多的通知
系統(tǒng)對多的通知消息,會比系統(tǒng)對1的通知消息復(fù)雜一些,以兩個場景為例:
(1)QQ登錄彈窗新聞;
(2)QQ右下角彈窗廣告;
?
先說IM登錄彈窗新聞。
這個通知的需求是:
(1)同一天,用戶登錄彈出的新聞是相同的(很多業(yè)務(wù)符合這樣的場景),不同天新聞則不一樣(但所有用戶都一樣);
(2)每天第一次登錄彈出新聞,當(dāng)天的后續(xù)登錄不出新聞;
?
不妨設(shè)有一個表存放彈窗新聞:
t_msg(msg_id, date, msg_content)
有一個表來存放用戶信息:
t_user(user_id, user_info, …)
有一個表來存放用戶收到的新聞彈窗:
t_user_msg(user_id, msg_id, date)
?
這里的實現(xiàn)明顯不能采用推送的方式:
(1)將t_user_msg里對于所有user_id推送插入一個msg_id,表示未讀;
(2)在user每天第一次登錄的時候,將當(dāng)天的msg_id拉取出來,并刪除,表示已讀;
(3)在user每天非第一次登錄的時候,就拉取不到msg_id于是不會再次彈窗;
這個笨拙的方式,會導(dǎo)致t_user_msg里有大量的臟數(shù)據(jù),畢竟大部分用戶并不會登錄。
?
如果改為拉取的方式會好很多:
(1)在user每天第一次登陸時,將當(dāng)天的msg_id拉取出來,并插入t_user_msg,表示已讀;
(2)在user每天非第一次登陸時,則會插入t_user_msg失敗,則說明已讀,不再進(jìn)行二次彈窗展現(xiàn);
這個方式雖然有所優(yōu)化,但t_user_msg的數(shù)據(jù)量依然很大。
?
還有一種巧妙的方式,去除t_user_msg表,改為在t_user表加一列,表示用戶最近拉取的彈窗時間:
t_user(user_id, user_info,?last_msg_date, …)
這樣業(yè)務(wù)流程會升級為:
(1)在user每天第一次登錄時,將當(dāng)天的msg_id拉取出來,并將last_msg_date修改為今天;
(2)在user每天非第一次登錄時,發(fā)現(xiàn)last_msg_date為今天,則說明今天已讀;
這種方式不再存儲消息與用戶的笛卡爾關(guān)系,數(shù)據(jù)量會大大減少,是不是有點意思?
?
再說IM右下角彈窗廣告。
這個通知的需求是:
(1)每天會對一批在線用戶推送相同的彈窗TIPS廣告,例如球鞋廣告,手機廣告等;
畫外音:如果1個推送一塊錢,5KW用戶推送收入就有5KW收入喲,一天推個幾次,實現(xiàn)1個億的小目標(biāo)居然如此簡單。
?
最直觀的感受,這是一個for循環(huán)批量推送的過程。如果是推送,必須要考慮的問題是,推送限速控制,避免短時間內(nèi)對系統(tǒng)造成沖擊,引發(fā)雪崩。
?
能不能用拉取呢?
完全可以,這是一個對實時性要求不太高的場景,用戶早1分鐘晚1分鐘收到這個廣告影響不大,其實可以借助IM原本已有的keepalive請求,在請求返回時,告之“有消息拉取”,然后采用拉取的方式拉取廣告消息。
?
這個方案的好處是,由于5KW在線用戶的keepalive請求是均勻的,所以可以很均勻的將廣告拉取的請求同樣均勻的分散到一段時間內(nèi),避免5KW集中推送對系統(tǒng)造成沖擊。
?
總結(jié)
廣義系統(tǒng)通知,究竟是推送還是拉取呢?不同業(yè)務(wù),不同需求,實現(xiàn)方式不同。
系統(tǒng)對1的通知:
(1)實時性要求高,可以推送;
(2)實時性要求低,可以拉取;
?
系統(tǒng)對N的通知:
(1)登錄彈窗新聞,拉取更佳,可以用一個last_msg_date來避免大量數(shù)據(jù)的存儲;
(2)批量彈窗廣告,常見的方法是推送,需要注意限速,也可以拉取,以實現(xiàn)請求的均勻分散;
總結(jié)
以上是生活随笔為你收集整理的系统通知,居然用拉取的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 轻量级定时任务框架:APSchedule
- 下一篇: python 如何调用远程接口