京東的客服即時通信系統名爲咚咚是。咚咚之於京東至關於旺旺之於淘寶,它們都是服務於買家和賣家的溝通。 自從京東開始爲第三方賣家提供入駐平臺服務後,咚咚也就隨之誕生了。 咱們首先看看它誕生之初是什麼樣的。php
爲了業務的快速上線,1.0 版本的技術架構實現是很是直接且簡單粗暴的。 如何簡單粗暴法?請看架構圖,以下:
<ignore_js_op>
1.0 的功能十分簡單,實現了一個 IM 的基本功能,接入、互通消息和狀態。 另外還有客服功能,就是顧客接入諮詢時的客服分配,按輪詢方式把顧客分配給在線的客服接待。 用開源 Mina 框架實現了 TCP 的長鏈接接入,用 Tomcat Comet 機制實現了 HTTP 的長輪詢服務。 而消息投遞的實現是一端發送的消息臨時存放在 Redis 中,另外一端拉取的生產消費模型。
這個模型的作法致使須要以一種高頻率的方式來輪詢 Redis 遍歷屬於本身鏈接的關聯會話消息。 這個模型很簡單,簡單包括多個層面的意思:理解起來簡單;開發起來簡單;部署起來也簡單。 只須要一個 Tomcat 應用依賴一個共享的 Redis,簡單的實現核心業務功能,並支持業務快速上線。
但這個簡單的模型也有些嚴重的缺陷,主要是效率和擴展問題。 輪詢的頻率間隔大小基本決定了消息的延時,輪詢越快延時越低,但輪詢越快消耗也越高。 這個模型其實是一個高功耗低效能的模型,由於不活躍的鏈接在那作高頻率的無心義輪詢。 高頻有多高呢,基本在 100 ms 之內,你不能讓輪詢太慢,好比超過 2 秒輪一次,人就會在聊天過程當中感覺到明顯的會話延遲。 隨着在線人數增長,輪詢的耗時也線性增加,所以這個模型致使了擴展能力和承載能力都很差,必定會隨着在線人數的增加碰到性能瓶頸。
1.0 的時代背景正是京東技術平臺從 .NET 向 Java 轉型的年代,我也正是在這期間加入京東並參與了京東主站技術轉型架構升級的過程。 以後開始接手了京東咚咚,並持續完善這個產品,進行了三次技術架構演進。html
咱們剛接手時 1.0 已在線上運行並支持京東 POP(開放平臺)業務,以後京東打算組建自營在線客服團隊並落地在成都。 無論是自營仍是 POP 客服諮詢業務當時都起步不久,1.0 架構中的性能和效率缺陷問題尚未達到引爆的業務量級。 而自營客服當時還處於起步階段,客服人數不足,服務能力不夠,顧客諮詢量遠遠超過客服的服務能力。 超出服務能力的顧客諮詢,當時咱們的系通通一返回提示客服繁忙,請稍後諮詢。 這種情況致使高峯期大量顧客不管怎麼刷新請求,都極可能沒法接入客服,體驗不好。 因此 2.0 重點放在了業務功能體驗的提高上,以下圖所示。
<ignore_js_op>
針對沒法及時提供服務的顧客,能夠排隊或者留言。 針對純文字溝通,提供了文件和圖片等更豐富的表達方式。 另外支持了客服轉接和快捷回覆等方式來提高客服的接待效率。 總之,整個 2.0 就是圍繞提高客服效率和用戶體驗。 而咱們擔憂的效率問題在 2.0 高速發展業務的時期尚未出現,但業務量正在逐漸積累,咱們知道它快要爆了。 到 2012 年底,度過雙十一後開始了 3.0 的一次重大架構升級。android
經歷了 2.0 時代一全年的業務高速發展,實際上代碼規模膨脹的很快。 與代碼一塊膨脹的還有團隊,從最初的 4 我的到近 30 人。 團隊大了後,一個系統多人開發,開發人員層次不一,規範難統一,系統模塊耦合重,改動溝通和依賴多,上線風險難以控制。 一個單獨 tomcat 應用多實例部署模型終於走到頭了,這個版本架構升級的主題就是服務化。
服務化的第一個問題如何把一個大的應用系統切分紅子服務系統。 當時的背景是京東的部署還在半自動化年代,自動部署系統剛起步,子服務系統若按業務劃分太細太多,部署工做量很大且難管理。 因此當時咱們不是按業務功能分區服務的,而是按業務重要性級別劃分了 0、一、2 三個級別不一樣的子業務服務系統。 另外就是獨立了一組接入服務,針對不一樣渠道和通訊方式的接入端,見下圖。
<ignore_js_op>
更細化的應用服務和架構分層方式可見下圖。
<ignore_js_op>
此次大的架構升級,主要考慮了三個方面:穩定性、效率和容量。 作了下面這些事情:
算法
前 6 條基本屬於考慮系統穩定性、可用性方面的改進升級。 這一塊屬於陸續迭代完成的,承載不少失敗轉移的配置和控制功能在上面圖中是由管控中心提供的。 第 7 條主要是隨着業務量的上升,單日消息量愈來愈大後,使用了 MongoDB 來單獨存儲量最大的聊天記錄。
第 8 條是針對 1.0 版本消息輪詢效率低的改進,改進後的投遞方式以下圖所示:
<ignore_js_op>
再也不是輪詢了,而是讓終端每次創建鏈接後註冊接入點位置,消息投遞前定位鏈接所在接入點位置再推送過去。 這樣投遞效率就是恆定的了,並且很容易擴展,在線人數越多則鏈接數越多,只須要擴展接入點便可。 其實,這個模型依然還有些小問題,主要出在離線消息的處理上,能夠先思考下,咱們最後再講。
3.0 通過了兩年的迭代式升級,單純從業務量上來講還能夠繼續支撐很長時間的增加。 但實際上到 2014 年末咱們面對的再也不是業務量的問題,而是業務模式的變化。 這直接致使了一個全新時代的到來。數據庫
2014 年京東的組織架構發生了很大變化,從一個公司變成了一個集團,下設多個子公司。 原來的商城成爲了其中一個子公司,新成立的子公司包括京東金融、京東智能、京東到家、拍拍、海外事業部等。 各自業務範圍不一樣,業務模式也不一樣,但無論什麼業務老是須要客服服務。 如何複用原來爲商城量身訂作的咚咚客服系統並支持其餘子公司業務快速接入成爲咱們新的課題。
最先要求接入的是拍拍網,它是從騰訊收購的,因此是徹底不一樣的帳戶和訂單交易體系。 因爲時間緊迫,咱們把爲商城訂作的部分剝離,基於 3.0 架構對接拍拍又單獨訂作了一套,並獨立部署,像下面這樣。
<ignore_js_op>
雖然在業務要求的時間點前完成了上線,但這樣作也帶來了明顯的問題:
編程
之前咱們都是面向業務去架構系統,現在新的業務變化形勢下咱們開始考慮面向平臺去架構,在統一平臺上跑多套業務,統一源碼,統一部署,統一維護。 把業務服務繼續拆分,剝離出最基礎的 IM 服務,IM 通用服務,客服通用服務,而針對不一樣的業務特殊需求作最小化的定製服務開發。 部署方式則以平臺形式部署,不一樣的業務方的服務跑在同一個平臺上,但數據互相隔離。 服務繼續被拆分的更微粒化,造成了一組服務矩陣(見下圖)。
<ignore_js_op>
而部署方式,只須要在雙機房創建兩套對等集羣,並另外建一個較小的灰度發佈集羣便可,全部不一樣業務都運行在統一平臺集羣上,以下圖。
<ignore_js_op>
更細粒度的服務意味着每一個服務的開發更簡單,代碼量更小,依賴更少,隔離穩定性更高。 但更細粒度的服務也意味着更繁瑣的運維監控管理,直到今年公司內部彈性私有云、緩存雲、消息隊列、部署、監控、日誌等基礎系統日趨完善, 使得實施這類細粒度劃分的微服務架構成爲可能,運維成本可控。 而從當初 1.0 的 1 種應用進程,到 3.0 的 六、7 種應用進程,再到 4.0 的 50+ 更細粒度的不一樣種應用進程。 每種進程再根據承載業務流量不一樣分配不一樣的實例數,真正的實例進程數會過千。 爲了更好的監控和管理這些進程,爲此專門定製了一套面向服務的運維管理系統,見下圖。
<ignore_js_op>
統一服務運維提供了實用的內部工具和庫來幫助開發更健壯的微服務。 包括中心配置管理,流量埋點監控,數據庫和緩存訪問,運行時隔離。
以下圖所示是一個運行隔離的圖示:
<ignore_js_op>
細粒度的微服務作到了進程間隔離,嚴格的開發規範和工具庫幫助實現了異步消息和異步 HTTP 來避免多個跨進程的同步長調用鏈。 進程內部經過切面方式引入了服務加強容器 Armor 來隔離線程, 並支持進程內的單獨業務降級和同步轉異步化執行。而全部這些工具和庫服務都是爲了兩個目標:
緩存
最後咱們回到前文留下的一個懸念,就是關於消息投遞模型的缺陷。 一開始咱們在接入層檢測到終端鏈接斷開後,消息沒法投遞,再將消息緩存下來,等終端重鏈接上來再拉取離線消息。 這個模型在移動時表明現的很很差,由於移動網絡的不穩定性,致使常常斷鏈後重連。 而準確的檢測網絡鏈接斷開是依賴一個網絡超時的,致使檢測可能不許確,引起消息假投遞成功。 新的模型以下圖所示,它再也不依賴準確的網絡鏈接檢測,投遞前待確認消息 id 被緩存,而消息體被持久存儲。 等到終端接收確認返回後,該消息纔算投妥,未確認的消息 id 再從新登錄後或重鏈接後做爲離線消息推送。 這個模型不會產生消息假投妥致使的丟失,但可能致使消息重複,只需由客戶終端按消息 id 去重便可。
<ignore_js_op> tomcat
京東咚咚誕生之初正是京東技術轉型到 Java 之時,經歷這些年的發展,取得了很大的進步。 從草根走向專業,從弱小走向規模,從分散走向統一,從雜亂走向規範。 本文主要重心放在了幾年來咚咚架構演進的過程,技術架構單獨拿出來看我認爲沒有絕對的好與很差, 技術架構老是要放在彼時的背景下來看,要考慮業務的時效價值、團隊的規模和能力、環境基礎設施等等方面。 架構演進的生命週期適時匹配好業務的生命週期,纔可能發揮最好的效果。安全
[1] 網絡編程基礎資料:
《TCP/IP詳解 - 第11章·UDP:用戶數據報協議》
《TCP/IP詳解 - 第17章·TCP:傳輸控制協議》
《TCP/IP詳解 - 第18章·TCP鏈接的創建與終止》
《TCP/IP詳解 - 第21章·TCP的超時與重傳》
《理論經典:TCP協議的3次握手與4次揮手過程詳解》
《理論聯繫實際:Wireshark抓包分析TCP 3次握手、4次揮手過程》
《計算機網絡通信協議關係圖(中文珍藏版)》
《NAT詳解:基本原理、穿越技術(P2P打洞)、端口老化等》
《UDP中一個包的大小最大能多大?》
《Java新一代網絡編程模型AIO原理及Linux系統AIO介紹》
《NIO框架入門(三):iOS與MINA二、Netty4的跨平臺UDP雙向通訊實戰》
《NIO框架入門(四):Android與MINA二、Netty4的跨平臺UDP雙向通訊實戰》
>> 更多同類文章 ……
[2] 有關IM/推送的通訊格式、協議的選擇:
《爲何QQ用的是UDP協議而不是TCP協議?》
《移動端即時通信協議選擇:UDP仍是TCP?》
《如何選擇即時通信應用的數據傳輸格式》
《強列建議將Protobuf做爲你的即時通信應用數據傳輸格式》
《移動端IM開發須要面對的技術問題(含通訊協議選擇)》
《簡述移動端IM開發的那些坑:架構設計、通訊協議和客戶端》
《理論聯繫實際:一套典型的IM通訊協議設計詳解》
《58到家實時消息系統的協議設計等技術實踐分享》
>> 更多同類文章 ……
[3] 有關IM/推送的心跳保活處理:
《Android進程保活詳解:一篇文章解決你的全部疑問》
《Android端消息推送總結:實現原理、心跳保活、遇到的問題等》
《爲什麼基於TCP協議的移動端IM仍然須要心跳保活機制?》
《微信團隊原創分享:Android版微信後臺保活實戰分享(進程保活篇)》
《微信團隊原創分享:Android版微信後臺保活實戰分享(網絡保活篇)》
《移動端IM實踐:實現Android版微信的智能心跳機制》
《移動端IM實踐:WhatsApp、Line、微信的心跳策略分析》
>> 更多同類文章 ……
[4] 有關WEB端即時通信開發:
《新手入門貼:史上最全Web端即時通信技術原理詳解》
《Web端即時通信技術盤點:短輪詢、Comet、Websocket、SSE》
《SSE技術詳解:一種全新的HTML5服務器推送事件技術》
《Comet技術詳解:基於HTTP長鏈接的Web端實時通訊技術》
《WebSocket詳解(一):初步認識WebSocket技術》
《socket.io實現消息推送的一點實踐及思路》
>> 更多同類文章 ……
[5] 有關IM架構設計:
《淺談IM系統的架構設計》
《簡述移動端IM開發的那些坑:架構設計、通訊協議和客戶端》
《一套原創分佈式即時通信(IM)系統理論架構方案》
《從零到卓越:京東客服即時通信系統的技術架構演進歷程》
《蘑菇街即時通信/IM服務器開發之架構選擇》
《騰訊QQ1.4億在線用戶的技術挑戰和架構演進之路PPT》
《微信技術總監談架構:微信之道——大道至簡(演講全文)》
《如何解讀《微信技術總監談架構:微信之道——大道至簡》》
《快速裂變:見證微信強大後臺架構從0到1的演進歷程(一)》
《17年的實踐:騰訊海量產品的技術方法論》
>> 更多同類文章 ……
[6] 有關IM安全的文章:
《即時通信安全篇(一):正確地理解和使用Android端加密算法》
《即時通信安全篇(二):探討組合加密算法在IM中的應用》
《即時通信安全篇(三):經常使用加解密算法與通信安全講解》
《即時通信安全篇(四):實例分析Android中密鑰硬編碼的風險》
《傳輸層安全協議SSL/TLS的Java平臺實現簡介和Demo演示》
《理論聯繫實際:一套典型的IM通訊協議設計詳解(含安全層設計)》
《微信新一代通訊安全解決方案:基於TLS1.3的MMTLS詳解》
《來自阿里OpenIM:打造安全可靠即時通信服務的技術實踐分享》
>> 更多同類文章 ……
[7] 有關實時音視頻開發:
《即時通信音視頻開發(一):視頻編解碼之理論概述》
《即時通信音視頻開發(二):視頻編解碼之數字視頻介紹》
《即時通信音視頻開發(三):視頻編解碼之編碼基礎》
《即時通信音視頻開發(四):視頻編解碼之預測技術介紹》
《即時通信音視頻開發(五):認識主流視頻編碼技術H.264》
《即時通信音視頻開發(六):如何開始音頻編解碼技術的學習》
《即時通信音視頻開發(七):音頻基礎及編碼原理入門》
《即時通信音視頻開發(八):常見的實時語音通信編碼標準》
《即時通信音視頻開發(九):實時語音通信的迴音及迴音消除概述》
《即時通信音視頻開發(十):實時語音通信的迴音消除技術詳解》
《即時通信音視頻開發(十一):實時語音通信丟包補償技術詳解》
《即時通信音視頻開發(十二):多人實時音視頻聊天架構探討》
《即時通信音視頻開發(十三):實時視頻編碼H.264的特色與優點》
《即時通信音視頻開發(十四):實時音視頻數據傳輸協議介紹》
《即時通信音視頻開發(十五):聊聊P2P與實時音視頻的應用狀況》
《即時通信音視頻開發(十六):移動端實時音視頻開發的幾個建議》
《即時通信音視頻開發(十七):視頻編碼H.26四、V8的前世此生》
《簡述開源實時音視頻技術WebRTC的優缺點》
《良心分享:WebRTC 零基礎開發者教程(中文)》
>> 更多同類文章 ……
[8] IM開發綜合文章:
《移動端IM開發須要面對的技術問題》
《開發IM是本身設計協議用字節流好仍是字符流好?》
《請問有人知道語音留言聊天的主流實現方式嗎?》
《IM系統中如何保證消息的可靠投遞(即QoS機制)》
《談談移動端 IM 開發中登陸請求的優化》
《徹底自已開發的IM該如何設計「失敗重試」機制?》
《微信對網絡影響的技術試驗及分析(論文全文)》
《即時通信系統的原理、技術和應用(技術論文)》
《開源IM工程「蘑菇街TeamTalk」的現狀:一場虎頭蛇尾的開源秀》
>> 更多同類文章 ……
[9] 開源移動端IM技術框架資料:
《開源移動端IM技術框架MobileIMSDK:快速入門》
《開源移動端IM技術框架MobileIMSDK:常見問題解答》
《開源移動端IM技術框架MobileIMSDK:壓力測試報告》
《開源移動端IM技術框架MobileIMSDK:Android版Demo使用幫助》
《開源移動端IM技術框架MobileIMSDK:Java版Demo使用幫助》
《開源移動端IM技術框架MobileIMSDK:iOS版Demo使用幫助》
《開源移動端IM技術框架MobileIMSDK:Android客戶端開發指南》
《開源移動端IM技術框架MobileIMSDK:Java客戶端開發指南》
《開源移動端IM技術框架MobileIMSDK:iOS客戶端開發指南》
《開源移動端IM技術框架MobileIMSDK:Server端開發指南》
>> 更多同類文章 ……
[10] 有關推送技術的文章:
《iOS的推送服務APNs詳解:設計思路、技術原理及缺陷等》
《Android端消息推送總結:實現原理、心跳保活、遇到的問題等》
《掃盲貼:認識MQTT通訊協議》
《一個基於MQTT通訊協議的完整Android推送Demo》
《求教android消息推送:GCM、XMPP、MQTT三種方案的優劣》
《移動端實時消息推送技術淺析》
《掃盲貼:淺談iOS和Android後臺實時消息推送的原理和區別》
《絕對乾貨:基於Netty實現海量接入的推送服務技術要點》
《移動端IM實踐:谷歌消息推送服務(GCM)研究(來自微信)》
《爲什麼微信、QQ這樣的IM工具不使用GCM服務推送消息?》
>> 更多同類文章 ……
[11] 更多即時通信技術好文分類:
http://www.52im.net/forum.php?mod=collection&op=all服務器