網(wǎng)易****IM****云分層架構(gòu)圖解析
- 底層客戶端SDK悬垃,覆蓋了安卓,iOS,windows PC桌面端瞧栗,web網(wǎng)頁端和嵌入式設(shè)備等多個(gè)平臺。在SDK層使用的網(wǎng)絡(luò)協(xié)議有4層的TCP協(xié)議和基于7層的Socket.IO協(xié)議海铆,后者專門用于Web SDK中提供長連接能力迹恐;除了集成到應(yīng)用App中的SDK之外,還提供了供第三方服務(wù)器調(diào)用的API接口卧斟,基于Http協(xié)議殴边;最后的A/V SDK是基于UDP協(xié)議的實(shí)時(shí)音視頻SDK憎茂,用于實(shí)現(xiàn)基于網(wǎng)絡(luò)的語音和視頻通話。
網(wǎng)關(guān)層:提供客戶端直接接入并維護(hù)與服務(wù)器之間的長連接锤岸;其中WebSDK直連的是Weblink服務(wù)竖幔,這是一個(gè)基于Socket.IO協(xié)議實(shí)現(xiàn)的長連接服務(wù),而供AOS/IOS/PC等客戶端SDK直連的是基于TCP協(xié)議的Link服務(wù)是偷;在Link和WebLink服務(wù)中承擔(dān)的一個(gè)非常重要的功能就是所有客戶端長連接的管理拳氢,后面基于HTTP協(xié)議上的網(wǎng)關(guān)有API服務(wù),和LBS服務(wù)等蛋铆,其中LBS服務(wù)用于幫助客戶端SDK選取最合適自己的網(wǎng)關(guān)接入點(diǎn)馋评,優(yōu)化網(wǎng)絡(luò)效率;而API服務(wù)則直接提供來自第三方服務(wù)器的業(yè)務(wù)請求刺啦;
HA層:在網(wǎng)關(guān)接入層之上是HA層留特,網(wǎng)關(guān)接入層可提供給客戶端直連,在link層和Service層之間有一個(gè)HA層用來解耦并提供高可用和易擴(kuò)展等特性玛瘸;在HA的具體實(shí)現(xiàn)方式上蜕青,對Link和WebLink這兩個(gè)維持客戶端長連接的服務(wù),云信提供了協(xié)議路由的服務(wù)捧韵,代為分發(fā)業(yè)務(wù)請求市咆,路由層會按照預(yù)定義的規(guī)則將來自客戶端的請求轉(zhuǎn)發(fā)到相應(yīng)的業(yè)務(wù)節(jié)點(diǎn)上,當(dāng)業(yè)務(wù)集群擴(kuò)容之后路由服務(wù)馬上能發(fā)現(xiàn)新的可用節(jié)點(diǎn)再来,并將請求轉(zhuǎn)發(fā)過去蒙兰,當(dāng)發(fā)現(xiàn)業(yè)務(wù)節(jié)點(diǎn)出現(xiàn)異常時(shí)也會被路由層標(biāo)記并隔離下線以備替換。
業(yè)務(wù)節(jié)點(diǎn)集群:在HA層上就是具體的業(yè)務(wù)節(jié)點(diǎn)集群芒篷,我們稱為App服務(wù)搜变,該服務(wù)處理具體的客戶端請求,后端直連DB针炉、cache等各種基礎(chǔ)服務(wù)挠他,這個(gè)集群中的節(jié)點(diǎn)的特點(diǎn)是輕量,并且每個(gè)節(jié)點(diǎn)都是無狀態(tài)的篡帕,云信在實(shí)際部署這個(gè)集群時(shí)會跨網(wǎng)絡(luò)環(huán)境部署殖侵,比如在同城雙機(jī)房中分別部署一套業(yè)務(wù)服務(wù)節(jié)點(diǎn),前端通過路由層來分發(fā)業(yè)務(wù)請求镰烧,平時(shí)正常時(shí)業(yè)務(wù)互為熱備拢军,平均分擔(dān)線上的業(yè)務(wù)流量;當(dāng)單一網(wǎng)絡(luò)環(huán)境或者基礎(chǔ)設(shè)施出現(xiàn)故障時(shí)馬上會被路由服務(wù)檢測到怔鳖,并將該環(huán)境下的計(jì)算節(jié)點(diǎn)標(biāo)記下線茉唉,將線上的流量請求全部轉(zhuǎn)發(fā)到正常工作的集群中;從而提高了服務(wù)的整體可用性;配合監(jiān)控平臺等運(yùn)維工具度陆,業(yè)務(wù)節(jié)點(diǎn)的實(shí)時(shí)處理能力和容量使用情況都會被動態(tài)監(jiān)測起來艾凯,當(dāng)處理能力達(dá)到預(yù)設(shè)的水位線時(shí)會立即出發(fā)報(bào)警,運(yùn)維人員可以非常方便快捷得通過自動部署平臺對業(yè)務(wù)節(jié)點(diǎn)集群進(jìn)行擴(kuò)容懂傀。
業(yè)務(wù)層:其中包含了一些關(guān)鍵功能:核心的單聊消息趾诗、群聊消息和聊天室,通知等鸿竖;以及用戶信息托管沧竟,特殊關(guān)系管理等;還有面向API提供的如短信業(yè)務(wù),回?fù)茈娫捄蛯>€會議等;還有實(shí)時(shí)音視頻和直播功能等相關(guān)能力图柏。
最右邊列出的是從服務(wù)層上單獨(dú)列出來的更重要的功能,包括與開發(fā)者應(yīng)用的第三方數(shù)據(jù)同步糕非,個(gè)性化的內(nèi)容審核支持,超大群服務(wù)球榆,登陸登出事件日志朽肥,漫游消息和云端消息歷史功能,推送服務(wù)等等持钉。
網(wǎng)易****IM****云部署拓?fù)?/strong>
通過以下這張簡化后的部署拓?fù)鋱D可以對云信整體技術(shù)體系的有初步了解衡招。最右邊是客戶端,客戶端通過LBS服務(wù)獲取到網(wǎng)關(guān)接入點(diǎn)列表每强,再與Link和WebLink這類長連接服務(wù)器建立起長連接始腾,并進(jìn)行RPC操作,所有來自客戶端的請求都會通過路由層轉(zhuǎn)發(fā)到后端的APP層空执,APP層實(shí)時(shí)處理并下發(fā)同步請求的處理結(jié)果浪箭,并把一些異步任務(wù)通過隊(duì)列服務(wù)送到異步任務(wù)中,這些異步服務(wù)如大群消息的發(fā)送辨绊,推送服務(wù)奶栖,云端歷史消息的存儲和第三方的數(shù)據(jù)抄送同步服務(wù)等;在最下面的API接口上也是類似门坷,API直接提供給第三方的服務(wù)器調(diào)用請求宣鄙,API后端是各種獨(dú)立的業(yè)務(wù),如回?fù)茈娫捘觯绦诺瓤蚣剑煌瑯拥乃械腁PI后端業(yè)務(wù)請求也會產(chǎn)生相應(yīng)的日志;和APP上的日志樣敏簿,這些日志都會被通過日志采集平臺收集到大數(shù)據(jù)平臺中,一方面這類數(shù)據(jù)會存儲到HDFS上用于作為數(shù)據(jù)統(tǒng)計(jì)分析的數(shù)據(jù)源;另一方面會被導(dǎo)入到Hbase等數(shù)據(jù)倉庫中惯裕,用于提供日志檢索和二次分析温数。
高并發(fā)****IM****系統(tǒng)連接層的優(yōu)化實(shí)踐
即時(shí)通訊功能中最重要的連接管理服務(wù)怎么做?消息快速到達(dá)的前提是客戶端和服務(wù)器之間保持了穩(wěn)定的連接蜻势;可以理解為奠定云信服務(wù)穩(wěn)定性的基石撑刺。網(wǎng)關(guān)接入層需要解決的最重要的問題是什么?核心依然是穩(wěn)定握玛,安全和快速够傍。
如何保證穩(wěn)定?
網(wǎng)易云信SDK采用長連接機(jī)制來實(shí)現(xiàn)挠铲,并且由心跳的方式來檢測斷線和自動做重連冕屯,同時(shí)云信的SDK對移動網(wǎng)絡(luò)等弱網(wǎng)環(huán)境非常多的優(yōu)化工作,對移動端/PC端使用TCP來連接客戶端與服務(wù)器拂苹,對與Web端使用socketIO協(xié)議安聘,實(shí)現(xiàn)長連接的同時(shí)解決瀏覽器的兼容性問題;
如何實(shí)現(xiàn)安全瓢棒?
云信要求所有在公網(wǎng)傳輸?shù)臄?shù)據(jù)都必須被加密浴韭;在SDK與服務(wù)器的連接建立過程中有一個(gè)復(fù)雜的秘鑰協(xié)商過程,首先客戶端需要生成一個(gè)一次性使用的加密秘鑰脯宿,并使用非對稱加密方式將這個(gè)秘鑰加密之后傳給服務(wù)器念颈,加密數(shù)據(jù)會被服務(wù)器解密,之后該加密秘鑰被保留在該長連接的會話信息中连霉,數(shù)據(jù)來往均使用該秘鑰加密榴芳,這是一個(gè)流式加密,可以有效防止中間人攻擊和數(shù)據(jù)包回放等攻擊手段窘面。
如何保證快速翠语?
首先是在網(wǎng)關(guān)接入點(diǎn)的選擇上,借助LBS服務(wù)可以幫助客戶端尋找到最適合自己的網(wǎng)關(guān)接入點(diǎn)财边,比如從ip等信息判斷到的物理距離最近節(jié)點(diǎn)肌括,其次在連接建立之后,長連接的機(jī)制可以極大提升消息上下行的速度酣难,并且在數(shù)據(jù)傳輸過程中谍夭,云信會對數(shù)據(jù)包壓縮傳輸,降低網(wǎng)絡(luò)開銷來升消息收發(fā)的速度憨募;對頻繁的前后臺切換和重登陸這種移動客戶端場景紧索,SDK提供自動登錄和重連等機(jī)制,即在UI界面起來的同時(shí)已經(jīng)提前把消息通道建立菜谣;在接入網(wǎng)關(guān)的選擇策略中珠漂,通過并行來提升連接建立的速度晚缩。
客戶端與服務(wù)器建立長連接的過程展現(xiàn)
SDK接入的第一步是先請求LBS服務(wù),獲取可以進(jìn)入的接入網(wǎng)關(guān)地址列表媳危,LBS服務(wù)會根據(jù)多種策略條件來給客戶端分配地址荞彼,常見的條件如下:
appkey, 通過appkey可以將一個(gè)特定的應(yīng)用請求全部指向到一組特定的接入點(diǎn)待笑,可用于專屬服務(wù)器方案鸣皂;
客戶端ip,用于根據(jù)客戶端所處的地理位置暮蹂,為其就近分配接入網(wǎng)關(guān)寞缝,常見于海外節(jié)點(diǎn)的配置;
SDK版本號仰泻,將特定版本范圍的客戶端指向到特定網(wǎng)關(guān)荆陆,常用于新老版本升級的兼容方案,目前無實(shí)際使用案例我纪;
特定環(huán)境標(biāo)識慎宾,如智能客服環(huán)境等,用于將特定類型的app指向到特定網(wǎng)關(guān)浅悉,用于較大粒度環(huán)境隔離需求趟据。
在從LBS服務(wù)請求到接入網(wǎng)關(guān)地址之后,客戶端會按列表中的地址依次嘗試建立連接术健;如果嚴(yán)格按照這樣的順序汹碱,那客戶端建立連接的過程就會偏慢,為了加速接入過程荞估,實(shí)際上在操作時(shí)咳促,SDK都會使用本地緩存的最后一次LBS請求返回的地址列表來建立連接,同從LBS上拿一次新的地址列表緩存在本地勘伺,以備下次使用跪腹;當(dāng)列表中的所有地址在嘗試過一遍均失效,則會使用默認(rèn)的link地址來建立連接飞醉;默認(rèn)地址也失敗是會出現(xiàn)415或者408這種網(wǎng)絡(luò)錯(cuò)誤碼冲茸;
在獲取到目標(biāo)地址之后就會嘗試建立TCP長連接,連接建立之后就會與服務(wù)器協(xié)商加密秘鑰缅帘,并發(fā)出第一個(gè)鑒權(quán)包轴术,鑒權(quán)完成之后這個(gè)長連接就是一個(gè)安全有效的連接,客戶端可以發(fā)起后續(xù)的RPC請求钦无;服務(wù)器也可以往這個(gè)連接上下發(fā)消息通知逗栽;如果秘鑰協(xié)商失敗或者鑒權(quán)失敗,這個(gè)連接就會被認(rèn)為是一個(gè)非法的連接請求失暂,服務(wù)器會強(qiáng)制斷開彼宠;
最后聊一下加速節(jié)點(diǎn)的問題鳄虱,為了實(shí)現(xiàn)連接的快速,在網(wǎng)關(guān)接入點(diǎn)的分配時(shí)會優(yōu)先距離該客戶端最近的節(jié)點(diǎn)兵志;這里將的加速節(jié)點(diǎn)就是為了更靠近用戶提供的一種特殊節(jié)點(diǎn)醇蝴。
加速節(jié)點(diǎn)的原理背景是運(yùn)營商提供給個(gè)人用戶的線路,不管是移動網(wǎng)絡(luò)還是有線網(wǎng)絡(luò)想罕,其質(zhì)量和IDC中心之間的網(wǎng)絡(luò)總是有差異的;如果將整個(gè)用戶鏈路中的關(guān)鍵路徑替換成IDC之間的網(wǎng)絡(luò)線路霉涨,那么對提升連接的穩(wěn)定性和速度是有幫助的按价。
假設(shè)一個(gè)處于美國的客戶通過手機(jī)網(wǎng)絡(luò)訪問位于杭州的一個(gè)網(wǎng)關(guān)接入點(diǎn),由于客戶端所在的網(wǎng)絡(luò)是一個(gè)移動網(wǎng)絡(luò)笙瑟,直連到杭州服務(wù)器需要經(jīng)過的鏈路非常長而且可能跳轉(zhuǎn)的中間節(jié)點(diǎn)不可預(yù)期楼镐,在中國來說,還要跨越防火墻往枷;所以直連的情況大部分可能就是無法連接框产,或者連接之后頻繁斷線。
我們提供了多層的加速節(jié)點(diǎn):加入了加速節(jié)點(diǎn)之后错洁,用戶的整體鏈路中原來不可預(yù)期的那段鏈路都換成了質(zhì)量較好的線路秉宿,用戶直連到本地的加速節(jié)點(diǎn)的網(wǎng)絡(luò)往往就會好很多。
下面說說不同的投遞模式對消息送達(dá)效率的影響:
問題一:怎么讓消息投遞并發(fā)能力倍增屯碴?
在這張圖中描睦,上半部分表示的是一個(gè)點(diǎn)對點(diǎn)型的Link服務(wù)器,當(dāng)發(fā)送者A發(fā)送一條消息之后导而,通過Link這條消息提交到APP中處理忱叭,APP中查詢到該消息接收者B所在的Link服務(wù)器是Link y,于是向Link y服務(wù)器下發(fā)一條下行通知包今艺,Link y上再找到用戶B對應(yīng)的長連接并將通知下發(fā)到客戶端韵丑;這種模式下,所有的接入點(diǎn)Link對于所有的用戶來說都是對等的虚缎,他可以接入到任何一個(gè)服務(wù)器中撵彻,任何消息的發(fā)送都必須在業(yè)務(wù)層查詢到目標(biāo)接收者所在的Link服務(wù)器,并往相應(yīng)的Link服務(wù)器下發(fā)通知包遥巴,如果是一次群發(fā)行為千康,那就需要在業(yè)務(wù)APP上把所有群內(nèi)的成員所在的Link列表都查詢一遍;這是一個(gè)比較耗時(shí)的操作铲掐;并且是隨著消息接收成員的數(shù)量不斷上升開銷不斷增大拾弃;所以如果是需要往聊天室內(nèi)發(fā)送消息,由于聊天室內(nèi)的成員數(shù)量非常龐大摆霉,這種模式很快就會遇到性能瓶頸豪椿,消息投遞的延時(shí)會非常嚴(yán)重奔坟;
對于廣播型的Link服務(wù)器,云信在分配接入點(diǎn)時(shí)首先遵循一個(gè)原則搭盾,那就是同個(gè)聊天室內(nèi)的成員在分配聊天室時(shí)咳秉,盡量分配在同一組接入點(diǎn)上;在Link上維護(hù)了每個(gè)房間內(nèi)所有的成員的長連接集合鸯隅;而在App上維護(hù)的不再是特定用戶和Link之前的映射關(guān)系澜建,而是維護(hù)了特定房間分配的Link的集合;于是在任何一個(gè)成員發(fā)出一條聊天室廣播消息之后蝌以,消息通過link上行到App炕舵,App只要找到該聊天室已經(jīng)分配的Link地址列表,往每個(gè)Link上下發(fā)一個(gè)廣播消息跟畅,Link在收到下行的廣播消息之后再在本地做廣播分發(fā)咽筋;這個(gè)效率比點(diǎn)播的模式高出了不止一個(gè)數(shù)量級;
問題二:怎么解決單節(jié)點(diǎn)的性能瓶頸徊件?
在講完了點(diǎn)對點(diǎn)型和廣播型這兩種Link的區(qū)別之后奸攻;云信再回頭來看看另外一類基于socket.io實(shí)現(xiàn)的weblink的代理方案在云信中的演變優(yōu)化過程;
在這之前需要再強(qiáng)調(diào)下WebLink中兩個(gè)關(guān)鍵點(diǎn)虱痕,首先WebLink是基于Socket.io協(xié)議的睹耐,為了保證數(shù)據(jù)通道的可靠,云信需要使用Https來對通道加密皆疹,其次由于是Https的請求所以必須提供獨(dú)立的域名疏橄。
圖一中顯示的是最早的方案,后端Weblink提供連接略就,并實(shí)現(xiàn)SSL加密捎迫,多個(gè)節(jié)點(diǎn)前面通過LVS做代理,域名綁定在LVS代理之上表牢,LVS代理之上再做Keepalived方案來保證HA窄绒;這種方案對外暴露的域名只有一個(gè),而內(nèi)部實(shí)際有很多的節(jié)點(diǎn)崔兴,擴(kuò)容對外也是透明的彰导;Web客戶端在連接時(shí)只需要直連這個(gè)唯一域名就可以,對于單一產(chǎn)品來說這種方式最簡便快捷敲茄,客戶端可以繞過地址分配的過程位谋;缺點(diǎn)也集中在單一出口,如果這個(gè)單一出口受到DDOS攻擊堰燎,只能通過域名換綁來規(guī)避掏父,而域名換綁需要一定的生效時(shí)間,帶來和一些運(yùn)維上的代價(jià)秆剪,其次對于云信這種服務(wù)來說赊淑,單一出口就喪失了靈活性爵政;所有客戶直連到同一個(gè)入口,也無法實(shí)現(xiàn)專屬服務(wù)和業(yè)務(wù)隔離陶缺,無法實(shí)現(xiàn)加速節(jié)點(diǎn)方案钾挟;
于是便有了第二種方案,這種方案借鑒了Link業(yè)務(wù)中的LBS分配的方式饱岸,還是在Weblink節(jié)點(diǎn)上實(shí)現(xiàn)SSL加密掺出,并為每個(gè)Weblink節(jié)點(diǎn)分配獨(dú)立域名,客戶端在接入前先通過LBS服務(wù)來分配到合適的接入點(diǎn)伶贰;這種方案好處就是提供了更大的靈活性蛛砰,隨時(shí)可以給集群擴(kuò)容,也可以動態(tài)調(diào)整特定應(yīng)用的接入點(diǎn)地址黍衙,也提供做加速節(jié)點(diǎn)的可能性;但是這種方案的問題是每個(gè)節(jié)點(diǎn)都是單點(diǎn)荠诬,而且節(jié)點(diǎn)內(nèi)還是需要做SSL編碼琅翻,由于java的SSL對cpu資源開銷比較大,在突發(fā)用戶流量是會影響單個(gè)節(jié)點(diǎn)的服務(wù)能力柑贞;
于是又有了第三種方案方椎,這種方案前端使用Nginx做七層代理,并在Nginx配置SSL和域名綁定钧嘶,后端可以同時(shí)使用一組Weblink棠众;由于使用了Nginx,在端口的分配邏輯上也更加科學(xué)有决,提高了運(yùn)維的便捷性闸拿;最后云信就得到了目前在使用的一個(gè)組合方案,前端還是通過LBS服務(wù)來為SDK分配接入點(diǎn)书幕,以此提供靈活性新荤;后端使用多個(gè)Nginx集群做代理集群,每個(gè)集群分組的性能都得到了提高台汇。
即時(shí)通訊平臺服務(wù)化和高可用實(shí)踐
前面重點(diǎn)介紹了云信在客戶端接入層的實(shí)現(xiàn)和接入點(diǎn)的管理上使用的一些方法苛骨,通過這些技術(shù)手段為IM服務(wù)建立了一條穩(wěn)定可靠的消息通道,現(xiàn)在來聊聊在業(yè)務(wù)層做的服務(wù)化和高可用上面的工作苟呐。
網(wǎng)關(guān)接入層負(fù)責(zé)客戶端長連接的維護(hù)和管理痒芝,所有的接入節(jié)點(diǎn)甚至可以是無狀態(tài)的對等節(jié)點(diǎn),只負(fù)責(zé)客戶端與服務(wù)器之間請求的傳遞的轉(zhuǎn)發(fā)牵素,并優(yōu)化轉(zhuǎn)發(fā)效率严衬;而真正的業(yè)務(wù)處理邏輯還是需要有業(yè)務(wù)層來實(shí)現(xiàn)。
業(yè)務(wù)層需要處理大量請求并負(fù)責(zé)和DB两波,緩存瞳步,隊(duì)列闷哆,第三方接口等組件的交互,其穩(wěn)定性单起,可用性和擴(kuò)展能力直接影響了整個(gè)云服務(wù)的質(zhì)量抱怔;為了使業(yè)務(wù)層具有更好的彈性,云信在網(wǎng)關(guān)接入層和業(yè)務(wù)層之間引入了一個(gè)路由層來解耦嘀倒;業(yè)務(wù)節(jié)點(diǎn)在上線之后會將自己注冊到服務(wù)中心屈留,路由節(jié)點(diǎn)會轉(zhuǎn)接網(wǎng)關(guān)層的請求包,并從服務(wù)節(jié)點(diǎn)中挑選匹配的節(jié)點(diǎn)分發(fā)請求测蘑;這種三層架構(gòu)使系統(tǒng)整體具有更好的彈性灌危。
為了提高業(yè)務(wù)的可用性,云信會將業(yè)務(wù)節(jié)點(diǎn)分布到分屬于不同網(wǎng)絡(luò)的環(huán)境中碳胳,正常情況下可以同時(shí)提供服務(wù)勇蝙,一旦其中一個(gè)環(huán)境的網(wǎng)絡(luò)或者基礎(chǔ)設(shè)施出現(xiàn)故障,就可以快速得通過路由層來將故障集群下線挨约。
靈活支持灰度升級模式味混,云信可以將其中部分業(yè)務(wù)節(jié)點(diǎn)升級,然后通過路由層的配置將指定的用戶流量導(dǎo)入到新升級的節(jié)點(diǎn)中诫惭;
專屬服務(wù)的靈活支持翁锡,對于一些對資源獨(dú)占需求比較強(qiáng)烈的客戶,云信可以通過路由層將該客戶應(yīng)用下的所有流量導(dǎo)入到獨(dú)立的集群中夕土。
原文鏈接:https://juejin.im/post/5b1e2cc15188257d4529804b