1. 卓聘IM開發背景 智聯卓聘是智聯旗下高端人才招聘平臺,成立快4年了,業務增漲每年以100%速度增漲,業務增漲快在開發和上線速度要求也比較高。 2016年6月提出IM開發需求,7月初上線,開發人員三名,開發時間20多天,後期可以不斷滿足業務需求。前期階段我們考慮網上各種提供IM的雲平臺,這些平臺 ...
1. 卓聘IM開發背景
智聯卓聘是智聯旗下高端人才招聘平臺,成立快4年了,業務增漲每年以100%速度增漲,業務增漲快在開發和上線速度要求也比較高。
2016年6月提出IM開發需求,7月初上線,開發人員三名,開發時間20多天,後期可以不斷滿足業務需求。前期階段我們考慮網上各種提供IM的雲平臺,這些平臺都有一個問題,聊天記錄管理上,有著各種限制和不方便,所以我們決定自己去完成一個。
一個完整的IM,需考慮通信協議和傳輸協議。通信協議目前XMPP、MQTT ...傳輸協議TCP、HTTP,下麵我就從前期技術選擇和我們自己在IM開發中遇到問題和如何解決做一些描述。
2. IM 技術選型
IM在選擇上,更多我們需要考慮傳輸協議與通信協議使用。一個實時不經常掉線的IM必須有具有穩定可靠通信。
通信協議無非是在UDP、TCP、HTTP 選擇。傳輸協議最多使用XMPP 它是基於XML,每次一大段XML Post到服務端。如果是PC還好,手機端讓人抓狂。MQTT反而短小,更適合當下,易用、耗能少。不過目前還沒找到使用MQTT協議像Openfire一樣強大的開源項目,就是一但出了問題我們風險無法控制。
以下就是經常被用於IM的相關選擇。
2.1 Openfire
在Openfire 之前,IM開發者們,一邊考慮著通信協議,一邊考慮使用什麼樣傳輸協議,一切從0開始做起,從Openfire開始,IM開發者發現開發IM簡單很多,只要把XMPP協議瞭解了都可以快速開發,無論你是Web、還是手機,都有著不錯開源項目可用。效率也高,後面使用了Mina,想要功能直接寫插件、XMPP協議也適應了當時流行的XML。但這一切只是暫時的。
為了保證通信穩定與安全XMPP協議XML冗餘太長了,我們也有了更高效的Netty可用,關係性資料庫變的不再適合存儲這類數據。 XMPP要傳一張圖變的很痛苦。
2.2 WebSocket
像socket一樣提供了一組API,它基於了HTPP協議,它並不是一套完整IM解決方案。在HTTP熟悉的協議中多了Upgrade: websocket,Connection: Upgrade這二項,你的Nginx和新版Tomcat對這二項會有支持。最重要二個函數一個就是Send方法,一個就是Receive,簡單像是我們回到了HTTP Request和Response。可是最大問題在低版本瀏覽器上不能使用。
2.3 長輪詢
談到長輪詢就不得不說Comet的技術,使的HTTP協議有了主動推送機制。Comet本身有長連接與長輪詢二種方式。但是長連接在IE、 Firefox 下端的進度欄都會顯示載入沒有完成,而且 IE 上方的圖標會不停的轉動,表示載入正在進行。長輪詢本身技術很簡單,是利用HTTP超時機制,重發,看起來像是與客戶端建立了個永久連接。現在的開源有Comet4j、CometD。
缺點:消息實時性差,每打開一個網頁都要保持一個連接,對伺服器資源消耗大,發一條信息速度還好,如果是一張圖或者大量信息接收時,都會直接影響伺服器資源,在手機上使用不穩定。
優點:實現簡單、部署成本低、相容性好,只要可以HTTP請求各種平臺都可以實現,開源多相關解決方案成熟,一但出現問題我們可以第一時間解決。這是最重要的。
在開始做IM之前,我們有幾個需要考慮的自身業務特點需要考慮。
首先,我們需要相容全部瀏覽器。
讓我們在客戶端實現方式並不多,WebSocket好用簡單,可PC低版本瀏覽器不能使用。但在手機上又有著廣泛的支持。Openfire 有Smack可它的協議冗餘太長,要是在客戶端重新定義再到伺服器端轉化,效率不高。要是使用長輪詢如何避免用戶打個過多頁,白白消耗伺服器資源,使用了HTTP協議如何保持它的狀態和集群搭建也是問題。
可以同時線上多種客戶端,離線後可推送。
手機App、PC瀏覽器也可以同時線上、同時收發信息,我們既要可以在瀏覽器上使用像長輪詢這樣方式,同是也可以在手機上使用WebSocket這樣穩定收發方式。App發PC收,或PC發App收取。而且需要在App退出後,又可以使用推送平臺用戶手機上。
3. 卓聘聊聊架構
在分析了各種方案優缺點、根據我們目前業務需求和後期擴展,我們將架構做瞭如下設計。
通知服務可以隨時上線、下線,動態註冊在路由規則器中,前端根據需要或長輪詢、或WebSocket,在路由規則器獲取雙方(自己和對方)ID,在通過REST服務發送的數據是帶有ID的報文。通知服務在推給推送服務時,推送服務計算“規則”就可準確推送給指定客戶。客戶接到通知,再次通過REST服務拉取具體內容。
架構雖然簡單,可同時也遇到不少問題,以下就是架構詳細介紹及遇到問題和改進方式。
4. 存在問題及改進方式
4.1 用戶頻繁線上打開N多頁面產生大量長輪詢
用戶瀏覽器可以多開,同一用戶打開不同瀏覽器、同一用戶每開一個瀏覽器打開N多個頁面。每個一個頁,都會多產生一個連接,長輪詢很消耗服務資源,在CometD代碼中,就發現同一用戶會限制長輪詢個數,這是必要的,安全和減少伺服器資源。 但是不能解決實際問題。 每個用戶會打開很多頁簽,這是用戶習慣問題,我們無法限制。而同過觀察用戶行為,平時我們IM在收起狀態時,在整個頁面右下角。(見圖一),用戶本身可能不會主動去操作IM工具,如果能減少這樣不必要連接可以減少50%-60%無用長輪詢,但是有二點要解決。用戶不主動點擊登錄IM。
1、你的好友可以看到你線上 。
2、你如何收到你的好友推給你的消息
圖一、
我們採用了虛擬登錄,你沒有展開時不去開啟長輪詢,只有點擊展開視窗才真正的長輪詢。
1、用戶頁面載入時,發出你登錄信息,同過心跳保持線上狀態
2、你的好友推你信息時,我們通過短輪詢拉取,我們採用 Nginx+Lua+Redis ,這樣請求不會打到後面服務。
3、可以將上面二個步驟做成一個連接,減少連接數。
4.2 發送數據大小與接收速度
最早開始做時我們對IM瞭解比較少,做到一半時測試時,輸入內容越多或隨著業務發展,要求發表情,圖文時,會隨著長度增加接收和發送會有影響,後來同過學習和觀察發現,IM需要推拉同時使用,這也是IM普遍做法,可介紹的人比較少 見下圖。好處顯而易見,推送時解析協議獲取到一個個短小命令,而客戶端接到命令再去主動拉去實際內容。
1、發送客戶端把發送內容發到指定Web伺服器。
2、Web伺服器收到後,生成相應指令,和具體發送內容。
3、分別把指令傳送到接收伺服器,內容直接存放到資料庫中
4、接收服務收到指令後發送到後面推送服務。
5、推送服務推到指定用戶。
6、接收用戶收到指令後,再通過拉取,從資料庫中拉到實際內容。
4.3如何集群
Web集群很簡單,因為是無狀態的,用戶每次請求都會被負載到不同伺服器,不會有問題,而IM麻煩就在狀態性,你不可能簡單把它負載到不同伺服器,我們使用Hash演算法可以將同一用戶會被分到一臺指定伺服器,同時又出現其它問題,跨伺服器消息傳遞,如A用戶(AM)機器向B用戶(BM)機器 ,實現如下圖。
路由選擇器保存我們全部用戶及用戶連接,我們可以很輕鬆知道,每個用戶具體指向的推送伺服器。
1、用戶在登錄時在路由規則器註冊自己。
2、當A用戶發向B用戶信息時,通過路由規則器找到B對應的推送服務
3、推送服務相應信息通過Comet推送給指定客戶。
4.4 後續遷移
由於前期時間短和業務要求,我們很快上線,可我們要考慮後期代碼重構,業務在增長,重構時我們不是推翻重來,我們考慮僅替換瓶頸服務。所以我們將發送服務和推送服務分開,(見下圖)發送介面和定義協議不會變(變的成本更高),我們要變的是,可以方便增加或替換推送模塊。圖中紅色區域就是可以隨時被我們替換和增加的,黃色通信協議模塊相對穩定。
1、發送者發送數據時,我們會把內容寫到資料庫把命令發到接收服務中。
2、命令接收服務可是一個消息中間件,也可以是自己寫一個Netty服務去解析。
3、把解析後結果再次發到推送服務,推送服務在PC上可能它是一個Web服務,也可能是WebSocket服務,也可以是第三方平臺。當然也可以二種或多種同時存在。
5. 總結與未來方向
IM是一種時實要求高的系統,最大問題是用戶是否可以正常登錄,一但登錄,就可以收發信息,而當用戶量和用戶同時線上交流不斷增加時,集群的建設和收發速度都是影響用戶體驗的重要因素。IM中每個用戶狀態,信息敏感度都是必不可少監控項。目前我們也在不斷優化自動擴容、風險監控這些方向。希望給獵頭、企業HR、應聘者提供更好交流方式。