Pushlets 是經過長鏈接方式實現「推」消息的。推送模式分爲:Poll(輪詢)、Pull(拉)。本文圍繞 Pull 模式進行設計。瀏覽器
客戶端發起請求,服務端接收到請求後根據 Pushlets 協議進行處理。推數據經過 HTTP 響應返回。服務器
客戶端在接收到響應後根據 Pushlets 協議進行處理,從新發起請求。Pull 模式時序:ide
join:join 請求,服務器端創建 Pushlet 會話函數
join-ack:join 應答,返回會話 idspa
listen:訂閱並監聽主題線程
listen-ack:監聽應答,返回會話 id,訂閱 id設計
subscribe(可選):訂閱主題3d
subscribe-ack(可選):訂閱主題應答,返回會話 id,訂閱orm
refresh:長鏈接請求,實參會話 id
refresh-ack:長鏈接響應,包括下一次 refresh 請求間隔
hb:心跳響應
data:推數據
leave:清空訂閱
leave-ack:清空訂閱應答
服務器端主要負責維護會話,根據請求處理應答。使用內存隊列維護每一個會話的主題事件。
事件產生後經過分發器(Dispatcher)將事件發佈到指定訂閱者的事件隊列裏。Pull 模式使用阻塞隊列,讀超時(沒有事件)後返回 hb 與 refresh 指令的應答。
廣播:將事件發佈給全部訂閱者
多播:將事件發佈給匹配的訂閱者
單播:將事件發給某個訂閱者
訂閱者的事件隊列配置:
queue.size=24
隊列大小爲 24。若是隊列滿了新發布到該隊列的事件將被丟棄。
queue.read.timeout.millis=20000
隊列讀超時 20 秒。讀超時後返回 hb 與 refresh 指令的應答。該項配置即請求線程最長 hold 時間。
queue.write.timeout.millis=20
隊列寫超時 20 毫秒。若是隊列是滿的,等待 20 毫秒後若是還滿,則銷燬該訂閱者。
刷新時長配置:
pull.refresh.timeout.millis=45000
服務器端刷新超時 45 秒。若是服務器端某訂閱者超過 45 秒沒有收到客戶端的 listen 或 refresh 請求,則銷燬該訂閱者。該超時判斷髮生在發佈事件時。
pull.refresh.wait.min.millis=2000
pull.refresh.wait.max.millis=6000
refresh 指令中指定客戶端下次請求的等待時間區間,值取該區間內的隨機值。
Pushlets 支持多種客戶端,例如瀏覽器客戶端、Java 客戶端。瀏覽器客戶端又分爲 iframe 和 AJAX 兩種。
初始化客戶端後,客戶端發起監聽、訂閱請求,並根據服務器返回指令發送 refresh 請求。當有 data 應答時,回調客戶端 onData(event) 函數實現消息處理。
對 Pushlets 作接口封裝以屏蔽其特性細節,也便於之後兼容其餘服務器消息推送技術(例如 WebSocket)作好鋪墊。
封裝的服務器推機制定義爲 Channel 服務,提供服務器到瀏覽器客戶端的消息推送。
經過 Channel API 在 JS 客戶端與服務器端創建長鏈接,使服務器端能夠實時地發送消息給客戶端。
oaweb.Channel() 類:
init()
初始化服務器調用 URL、客戶端狀態。
open()
發送 join 請求,服務端建立會話。
subscribe(listeners : {topic, onmessage, onerror})
發送 subscribe 請求,服務端建立訂閱者,添加訂閱主題。
unsubscribe(topic)
發送 unsubscribe 請求,服務端移除訂閱。
close()
發送 leave 請求,服務端銷燬會話。
均衡器經過源地址保持策略保證同一 IP 的請求均會分發到固定服務節點。
當服務節點進行業務邏輯處理後,發送消息到消息服務系統;
服務節點訂閱消息主題,當監聽到新消息時調用 Channel 服務發佈消息到具體的推送實現組件(Pushlets)。
消息推送技術
Google App Engine Channel API
HTML5 WebSocket API