國民應用QQ如何實現高可用的訂閱推送系統
目錄
1 業務背景與訴求
1.1 業務背景
1.2 技術訴求
2 實現方案
2.1 推拉結合
2.2 異構儲存
2.3 多重觸發
2.4 可控溫度
2.5 打散執行
2.6 引入訊息佇列
2.7 At least once推送
2.8 容災方案
3 總結
01
業務方在管理端建立推送任務; 使用者在終端訂閱推送任務; 預設時間到時,透過訊息服務給所有訂閱的使用者推送訊息。
推送可靠性:任何業務方在系統上配置的任務,都應該得到觸發;任何訂閱了提醒任務的使用者,都應該收到推送訊息。
推送可控性:訊息服務的容量是有上限的,系統的總體訊息推送速率不能超過該上限。而業務投放的任務卻有一定隨機性,可能某一時刻沒有任務,可能某一時刻多個任務同時觸發。所以系統必須在總體上做速率把控,避免推送過快導致下游處理失敗,影響業務體驗。如果造成下游消息服務雪崩,後果不堪設想。
推送高效性:QQ 團隊規劃提高系統的推送速度,以滿足業務的更高時效性的要求。實際上, QQ 團隊的業務場景下做高併發是相對簡單的,而做到高可靠和可控反而較複雜。話不多說,下面談談 QQ 團隊如何實現這些技術要點。
02
2.2 異構儲存
業務方建立的任務資料。包含任務的提醒時間和提醒內容; 使用者訂閱生成的訂閱數據。主要是訂閱使用者 uin 列表資料,這個列表元素級別可達到千萬以上,並且必須要能夠快速讀取。
Redis 單執行緒模型,有效避免讀寫衝突; set 底層基於 intset 和 hash 表實現,儲存整型 uin 在空間和時間上均高效; 原生支援去重; 原生支援高效的批次取介面(spop),適合於推送時使用。
2.3 多重觸發
2.4 可控排程
CREATE TABLE table_xxx(
ds BIGINT COMMENT '資料日期',
label_name STRING COMMENT '標籤名稱',
label_id BIGINT COMMENT '標籤id',
appid STRING COMMENT '小程式appid',
useruin BIGINT COMMENT 'useruin',
tag_name STRING COMMENT 'tag名稱',
tag_id BIGINT COMMENT 'tag id',
tag_value BIGINT COMMENT 'tag權重值'
)
PARTITION BY LIST( ds )
SUBPARTITION BY LIST( label_name )(
SUBPARTITION sp_xxx VALUES IN ( 'xxx' ),
SUBPARTITION sp_xxxx VALUES IN ( 'xxxx' )
)
值得關注的是,冪等性如何保證呢?講完了排程的實現,再來論證下冪等性是否成立。
假設第一種情況,排程器執行一半掛了,後面又再次對同一個任務進行排程。由於排程器每次對一個任務進行排程時,都會先檢視任務當前剩餘推送量(即任務還剩多少塊),根據任務的剩餘塊數來繼續排程。所以,當任務再次觸發時,排程器可以接著前面的任務繼續完成。
假設第二種情況,一個任務被同時觸發兩次,由兩個排程器同時進行排程,那麼兩個排程器會互相搶額度,搶到後用在同一個任務。從執行效果來看,和一個排程器沒有差別。因此,任務可以被重複觸發。
2.5 打散執行
那麼有開發者會問到:如何分塊呢?具體實現時排程器負責按配置值下發指令,指令類似到某個任務的列表上取一個任務塊,任務塊大小 5000 個uin,並執行下發。後端的推送器worker收到指令後,便到指定的任務訂閱列表上(redis set實現),透過 spop 獲取到 5000 個 uin ,執行推送。
2.6 引入訊息佇列
一般來說,訊息佇列的意義主要是削峰填谷、非同步解耦。對本專案而言,引入訊息佇列有以下好處:
將任務排程和任務執行解耦(排程服務並不需要關心任務執行結果);
非同步化,保證排程服務的高效執行,排程服務的執行是以 ms 為單位;
藉助訊息佇列實現任務的可靠消費( At least once );
將瞬時高併發的任務量打散執行,達到削峰的作用。
2.7 At least once推送
redis.replicate_commands()
local set_key, task_key = KEYS [1], KEYS [2]
local num = tonumber(ARGV [1])
local array
array = redis.call('SPOP', set_key, num)
if #array > 0 then
redis.call("SADD", task_key, unpack(array))
end
return redis.call('scard', task_key)
推送流程整體如下:
2.8 容災方案
技術責編|許揚
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70024420/viewspace-2934544/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 如何用 Redis 做實時訂閱推送的?Redis
- 高可用訂單系統設計
- 使用者破10億,國民應用微信高併發下的高可用之祕!
- 小程式訂閱訊息推送(含原始碼)java實現小程式推送,springboo原始碼JavaSpring
- RxJava是如何實現訂閱關係的?RxJava
- 實現Kubernetes跨叢集服務應用的高可用
- OpenKruise 如何實現應用的可用性防護?UI
- 【轉】如何建設高可用系統
- Redis 訂閱 + swoole_websocket 推送RedisWeb
- 小程式訊息推送訂閱
- 如何設計和實現高可用的MySQLMySql
- 如何實現一個簡單的釋出訂閱模式模式
- 如何設計和實現高可用MySQLMySql
- 搭建高併發、高可用的系統
- Adjust:調查發現美國人每月平均花20.78美元訂閱應用
- win10正式版系統如何關閉QQ看點推送Win10
- 如何在大促中做好系統高可用
- 如何設計一個高可用的運營系統
- go實現QR訂閱的幾種方法Go
- node 訂閱釋出及實現
- 使用keepalived實現nginx的高可用Nginx
- nginx實現keepalived高可用Nginx
- keepalived + nginx 實現高可用Nginx
- 數商雲:如何實現SRM供應商管理系統的應用價值?
- C++釋出訂閱者模式:實現簡單訊息傳遞系統C++模式
- 華為雲FunctionGraph構建高可用系統的實踐Function
- 如何設計一個高可用、高併發秒殺系統
- jQuery實現高仿QQ音樂jQuery
- Redis實現訊息釋出訂閱Redis
- [實戰]laravel + redis訂閱釋出 +swoole實現實時訂單通知LaravelRedis
- 高可用:美團點評智慧支付核心交易系統的可用性實踐
- MHA高可用架構的實現方式架構
- Apache Kyuubi 高可用的雲原生實現Apache
- Nginx&Keepalived 實現高可用Nginx
- keepalived+MySQL實現高可用MySql
- Keepalived實現服務高可用
- SpringBoot+MongoDB實現物流訂單系統Spring BootMongoDB
- 在K8S中,apiserver的高可用是如何實現的?K8SAPIServer