MQTT(使用mosquitto作broker)作Android推送部分總結

「讀萬卷書,行萬里路」。我以爲這句話用在程序員的工做中就是:在網絡中找一萬篇資料,在實踐中作一萬種嘗試。php

<hr> **2014-09-17:** **在本文中,因爲做者事先不瞭解,設計不合理,使每一個設備採用prefix+CLIENT_ID的方式做爲topic,致使須要給每一個設備的topic單獨推送,才產生了一些問題,特別是推送的時間上的問題,是PHP循環往每一個topic寫入消息的時間。但願讀者不要被我誤導。** **給每一個設備一個topic,實際上只在作點對點的推送的時候須要,若是沒有這個需求,好比全局的推送,或者是幾個大類的推送,徹底能夠設計一個更合理的topic規則,把主要的精力放在client和broker的維護上。** <hr>html

###1. 基礎建設: 紙上得來終覺淺 絕知此事要躬行java

  1. 理論支撐 :使用MQTT做爲Android實現方案的緣由源於一篇四年前的文章:How to Implement Push Notifications for Android
  2. 與Web管理的對接 : 文章的做者同時也提供了PHP端的Client方案:PhpMQTTClient
  3. 服務端 : 固然,這只是Web端的實現方案,至於後端須要使用的Broker,咱們找到了mosquitto
  4. 客戶端 : 在客戶端中,咱們使用的是來自IBM的wmqtt.jar的包:wmqtt

以上四個基本條件是咱們具有了部署基於MQTT協議的Android的推送服務的基本條件。在最初的測試中,也沒有遇到過太大的問題,測試順利,因而咱們在咱們的應用和服務器之間部署了這套解決方案。android

###2. 從0到1的變化: 千里之行,始於足下ios

因爲事先並無作推送的經驗,在實際實施的過程當中咱們明白的幾個基礎的概念:git

  1. MQTT協議是一個即時通信協議,推送實際上用到的只是它能夠publish內容給topic的功能。
  2. 爲了保證客戶端可以實時的收到推送消息,即便是程序退出,客戶端用於接收消息的service也須要處於保持狀態。
  3. 客戶端與Broker、Broker和Web端的都是socket通訊,推送的過程是用於Web端的client發佈一個消息到Broker,Broker再將消息發送給當前其它鏈接到Broker的Client。因此能及時收到消息的只是如今和Broker保持鏈接狀態的設備。
  4. 服務端須要維護一個設備id列表,這個列表中的id必須都是惟一的(在前期,咱們選擇使用Android ID,這也帶來了不少麻煩)。

基於以上幾點,咱們也能夠發現如下的問題:程序員

  1. 不是全部的設備都可以及時的獲取到推送的內容。
  2. 客戶端的service隨時會有被各類安全軟件幹掉的風險。

經過前期的調研咱們也發現,這些問題也是其它的第三方推送服務也都會遇到的問題。只要邁出第一步,讓服務先work起來,其它的問題後續來優化。github

###3. 從1到1萬: 不積硅步,無以至千里web

這個階段主要是豐富推送的功能,解決一些前表面上的問題,咱們作了如下的調整:shell

  1. 在設備量到10000的時候,遇到了一個問題:推送10000個設備時間過長。這個問題很快獲得瞭解決:這是因爲沒發送一個設備,都新建了一個從Web端到Broker的socket鏈接,這其實是沒有必要的,只要socket不斷開全部Publish的工做均可以經過一個socket進行(這和APNS有些不同的地方,在蘋果的推送服務中,若是有一個設備id是無效的,整個推送都會斷開),在前文提到過的Web端的庫中,是有指定重連的操做的。

  2. 豐富推送的內容。雖然推送的內容都是文本,可是文本的解析倒是客戶端維持的service來進行的,因此經過推送json的方式,實現了分別推送新聞、天氣等富文本信息,並能夠經過點擊跳轉到不一樣的頁面。

  3. 分地區推送的需求,這個實現方式通過一些迭代,最先是經過用戶註冊地來實現的,後來改成了用戶安裝應用時上報的地區的方式。

###4. 從1萬到10萬,必須作出的改變: 行百里者半於九十

數據量到達10萬的時候,一些問題也逐漸凸顯。

  1. Android ID重複的問題
    從網上查詢來的資料,大部分都是使用Android的系統參數ANDROID_ID來作推送的。然而實踐代表,這個參數並非可靠的。生產環境中使用這個參數有極大的概率重複。因爲一個相同的設備id鏈接到Broker的時候,以前的鏈接就會斷開,這就會致使相同設備ID的設備只有一個會收到推送的消息。
    在續的改造過程當中,咱們將設備ID換成了本身生成的一套惟一隨機的ID。

  2. 錯誤的id字符
    在查看MQTT的文檔中,咱們只注意到了設備ID須要在1~23位之間,卻並無注意到字符的限制。最初生成的id是base64的編碼。在後面的測試中 ,老是發現推送到某些設備以後推送就斷開了。通過檢查發現,這是因爲一些設備id中存在+符號致使的。
    在Topic中,+#會被看成通配符處理,致使出現 Socket error 的錯誤。
    通過諮詢,獲得瞭如下的答案:

Roger Light (roger.light) said :
Are you saying that clients that have a client id with '+' in are rejected? This shouldn't happen. If you mean that clients are publishing to a topic with '+' in, then you are correct that this is not allowed.

  1. 從Broker中獲取有用的信息
    生產環境中須要經過從Broker中獲取一些有用的信息用於監控推送的狀態。在Mosquitto的配置中,能夠把log_type設定爲all來記錄所有的log。
    經過訂閱Mosquitto的一個特定的Topic,能夠獲取到一些推送的統計信息:
mosquitto_sub -h 192.168.0.1 -p 1883 -t $SYS/broker/# -v
  1. 對於不在線的設備的處理(消息持久化)
    IOS和Windows Phone的設備的推送服務因爲是系統提供的服務,只要設備網絡在線,都是能夠及時收到消息的,對於Android的自建推送服務來講,顯然沒法保證這一點。然而經過消息持久化的配置,也能夠實現如下策略:
    • 應用處於打開狀態,設備在線的時候,能夠及時的收到消息
    • 應用退出、推送的Service在線的時候,能夠收到推送消息
    • 應用和Service都被關閉,下次應用啓動的時候,能夠收到一天內的推送消息

<br>

基於以上的策略,能夠在客戶端和Broker之間配置消息持久化和訂閱的持久化。配置過程當中須要在如下幾個地方注意:  
1. Web端發送消息的時候,QoS設定爲1  
2. Mosquitto的配置文件中,設定`persistence`爲`true`  
3. 客戶端`MQTT_CLEAN_START`(Clean session)爲`false`,即不在服務啓動時清理session,`MQTT_QUALITIES_OF_SERVICE`(QoS)與Web端保持一致;
  1. 安全策略的控制
    在Mosquitto的後端配置中,可使用限定客戶端前綴,使用ACL權限控制,配置SSL鏈接的方式進行安全控制。

###5. 從10萬到more,更多要作的事情... 路遙知馬力

  1. 推送時間的優化調整
    實際環境中,一臺4G內存,4核CPU的服務器,發送20萬臺設備的消息大概須要4分鐘左右,推送服務器並無什麼壓力,這個時間取決於Web端將全部的消息Publish到Broker服務器的時間。能夠經過多線程的方式進行優化。

  2. 及時清理失效的設備id
    因爲技術上的改造和迭代,一些設備ID在更新以後就不會再使用,服務端設定必定的策略來清理無效的設備ID能夠減輕推送的壓力。好比經過記錄設備最後一次鏈接到Broker的時間,若是這個時間超出某個限制(一個月),就清理掉這個設備id。下次設備從新連入的時候還會再發送設備ID,這樣即不會給服務器形成壓力,也不會漏掉某些設備的推送。

  3. 集羣部署
    Mosquitto支持集羣部署的配置(Bridges),其原理也是將一個消息Puhlish到集羣中的其它服務器,而後由其它服務器來發送。

A bridge is a way of connecting multiple MQTT brokers together.

  1. 如何讓客戶端的service始終在線
    參考:

在android中,service被殺死後在沒有被系統/安全軟件禁止的條件下是可以自啓動的,具體可自行網上搜索「android service onstartcommand START_STICKY」

###6. Mosquitto的配置優化
部分配置:

<!-- lang: shell -->
allow_zero_length_clientid false
persistent_client_expiration 1d
max_connections -1
persistence true
log_type all
connection_messages false
allow_anonymous false

###7. 資源/資料收集

  1. Apache的open source messaging and Integration Patterns server,ActiceMQ,使用java編寫,使用與管理很方便,目前發現的問題是內存使用量較大:Apache ActiveMQ
  2. Eclipse的客戶端庫:Eclipse Paho
  3. MQTT v3.1協議規範:MQTT V3.1 Protocol Specification
  4. Mosquitto文檔:Mosquitto Documentation

###8. 附上一篇iOS推送部署總結 詳情:http://xiaoler.github.io/blog/mobile/ios-push-apns-php-zendframework.html

相關文章
相關標籤/搜索