「讀萬卷書,行萬里路」。我以爲這句話用在程序員的工做中就是:在網絡中找一萬篇資料,在實踐中作一萬種嘗試。php
<hr> **2014-09-17:** **在本文中,因爲做者事先不瞭解,設計不合理,使每一個設備採用prefix+CLIENT_ID的方式做爲topic,致使須要給每一個設備的topic單獨推送,才產生了一些問題,特別是推送的時間上的問題,是PHP循環往每一個topic寫入消息的時間。但願讀者不要被我誤導。** **給每一個設備一個topic,實際上只在作點對點的推送的時候須要,若是沒有這個需求,好比全局的推送,或者是幾個大類的推送,徹底能夠設計一個更合理的topic規則,把主要的精力放在client和broker的維護上。** <hr>html
###1. 基礎建設: 紙上得來終覺淺 絕知此事要躬行
java
以上四個基本條件是咱們具有了部署基於MQTT協議的Android的推送服務的基本條件。在最初的測試中,也沒有遇到過太大的問題,測試順利,因而咱們在咱們的應用和服務器之間部署了這套解決方案。android
###2. 從0到1的變化: 千里之行,始於足下
ios
因爲事先並無作推送的經驗,在實際實施的過程當中咱們明白的幾個基礎的概念:git
基於以上幾點,咱們也能夠發現如下的問題:程序員
經過前期的調研咱們也發現,這些問題也是其它的第三方推送服務也都會遇到的問題。只要邁出第一步,讓服務先work起來,其它的問題後續來優化。github
###3. 從1到1萬: 不積硅步,無以至千里
web
這個階段主要是豐富推送的功能,解決一些前表面上的問題,咱們作了如下的調整:shell
在設備量到10000的時候,遇到了一個問題:推送10000個設備時間過長。這個問題很快獲得瞭解決:這是因爲沒發送一個設備,都新建了一個從Web端到Broker的socket鏈接,這其實是沒有必要的,只要socket不斷開全部Publish的工做均可以經過一個socket進行(這和APNS有些不同的地方,在蘋果的推送服務中,若是有一個設備id是無效的,整個推送都會斷開),在前文提到過的Web端的庫中,是有指定重連的操做的。
豐富推送的內容。雖然推送的內容都是文本,可是文本的解析倒是客戶端維持的service來進行的,因此經過推送json的方式,實現了分別推送新聞、天氣等富文本信息,並能夠經過點擊跳轉到不一樣的頁面。
分地區推送的需求,這個實現方式通過一些迭代,最先是經過用戶註冊地來實現的,後來改成了用戶安裝應用時上報的地區的方式。
###4. 從1萬到10萬,必須作出的改變: 行百里者半於九十
數據量到達10萬的時候,一些問題也逐漸凸顯。
Android ID重複的問題 :
從網上查詢來的資料,大部分都是使用Android的系統參數ANDROID_ID
來作推送的。然而實踐代表,這個參數並非可靠的。生產環境中使用這個參數有極大的概率重複。因爲一個相同的設備id鏈接到Broker的時候,以前的鏈接就會斷開,這就會致使相同設備ID的設備只有一個會收到推送的消息。
在續的改造過程當中,咱們將設備ID換成了本身生成的一套惟一隨機的ID。
錯誤的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.
log_type
設定爲all
來記錄所有的log。mosquitto_sub -h 192.168.0.1 -p 1883 -t $SYS/broker/# -v
<br>
基於以上的策略,能夠在客戶端和Broker之間配置消息持久化和訂閱的持久化。配置過程當中須要在如下幾個地方注意: 1. Web端發送消息的時候,QoS設定爲1 2. Mosquitto的配置文件中,設定`persistence`爲`true` 3. 客戶端`MQTT_CLEAN_START`(Clean session)爲`false`,即不在服務啓動時清理session,`MQTT_QUALITIES_OF_SERVICE`(QoS)與Web端保持一致;
###5. 從10萬到more,更多要作的事情... 路遙知馬力
推送時間的優化調整 :
實際環境中,一臺4G內存,4核CPU的服務器,發送20萬臺設備的消息大概須要4分鐘左右,推送服務器並無什麼壓力,這個時間取決於Web端將全部的消息Publish到Broker服務器的時間。能夠經過多線程的方式進行優化。
及時清理失效的設備id :
因爲技術上的改造和迭代,一些設備ID在更新以後就不會再使用,服務端設定必定的策略來清理無效的設備ID能夠減輕推送的壓力。好比經過記錄設備最後一次鏈接到Broker的時間,若是這個時間超出某個限制(一個月),就清理掉這個設備id。下次設備從新連入的時候還會再發送設備ID,這樣即不會給服務器形成壓力,也不會漏掉某些設備的推送。
集羣部署 :
Mosquitto支持集羣部署的配置(Bridges),其原理也是將一個消息Puhlish到集羣中的其它服務器,而後由其它服務器來發送。
A bridge is a way of connecting multiple MQTT brokers together.
在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. 資源/資料收集
open source messaging and Integration Patterns server
,ActiceMQ,使用java編寫,使用與管理很方便,目前發現的問題是內存使用量較大:Apache ActiveMQ###8. 附上一篇iOS推送部署總結 詳情:http://xiaoler.github.io/blog/mobile/ios-push-apns-php-zendframework.html