轉(zhuǎn)帖|行業(yè)資訊|編輯:黃竹雯|2017-02-21 17:23:26.000|閱讀 281 次
概述:對于一個(gè)即時(shí)通信服務(wù)器來說,在用戶量少的時(shí)候,一臺(tái)服務(wù)器就足以提供所有的服務(wù)。可是當(dāng)用戶數(shù)量越來越多時(shí),一臺(tái)服務(wù)器已經(jīng)無法所有用戶的需求,這時(shí)就要進(jìn)行服務(wù)擴(kuò)容,進(jìn)行分布式部署。
# 界面/圖表報(bào)表/文檔/IDE等千款熱門軟控件火熱銷售中 >>
對于一個(gè)即時(shí)通信服務(wù)器來說,在用戶量少的時(shí)候,一臺(tái)服務(wù)器就足以提供所有的服務(wù)。而這種架構(gòu)也最簡單,舉個(gè)例子,用戶A與用戶B互為好友,A向B發(fā)消息,服務(wù)器接收到消息時(shí),解析出接收消息的人,直接轉(zhuǎn)發(fā)給B即可。可是當(dāng)用戶數(shù)量越來越多時(shí),一臺(tái)服務(wù)器已經(jīng)無法所有用戶的需求,這時(shí)就要進(jìn)行服務(wù)擴(kuò)容,進(jìn)行分布式部署。
如圖所示,不同的用戶可能登錄到不同的服務(wù)器上,那么用戶A給用戶B發(fā)消息時(shí),服務(wù)器收到消息,首先判斷B是否也登錄在本服務(wù)器上,如果是,那么直接轉(zhuǎn)發(fā)消息即可。如果B不在本服務(wù)器上,那應(yīng)該往哪里轉(zhuǎn)發(fā)這條消息呢?最簡單的做法就是向服務(wù)器集群中的其他服務(wù)器廣播這條消息,對于每個(gè)收到這條消息的服務(wù)器,首先判斷消息的目的用戶是否登錄在自己身上,如果不是,直接忽略該消息。如果是,那么向目的用戶轉(zhuǎn)發(fā)該消息。固然,這種暴力粗獷的做法是最簡單直接的,但是會(huì)產(chǎn)生很多無效的消息轉(zhuǎn)發(fā),對于服務(wù)器性能產(chǎn)生很大的影響。曾看過蘑菇街開源的即時(shí)通信軟件Teamtalk的代碼,服務(wù)器就是這種實(shí)現(xiàn)方式。其服務(wù)器架構(gòu)如下:
不同的msg服務(wù)器連接到同一臺(tái)route server上,所有msg服務(wù)器之間的轉(zhuǎn)發(fā)全部通過route server。這無疑會(huì)加重route server的負(fù)載。即時(shí)msg server部署的再多,根據(jù)木桶理論,一個(gè)系統(tǒng)的性能是由其最薄弱的環(huán)節(jié)所決定的。所以也注定這樣的架構(gòu),其系統(tǒng)容量也是有限的。那么如何改善這種系統(tǒng)呢,很明顯服務(wù)器之間的消息轉(zhuǎn)發(fā)不能直接全部廣播,而應(yīng)該有一套明確的路由系統(tǒng),即服務(wù)器在轉(zhuǎn)發(fā)消息時(shí),應(yīng)該知道這條消息應(yīng)該轉(zhuǎn)發(fā)到哪一臺(tái)服務(wù)器,這樣就不需要每條消息都在所有服務(wù)器之間廣播了。
那么如何實(shí)現(xiàn)這樣一套路由系統(tǒng)呢?
簡單的做法是,每個(gè)用戶上線時(shí),通過其連接的msg server向其他所有msg server廣播自己的登錄信息,告知其他服務(wù)器自己登錄在哪臺(tái)服務(wù)器上面。這樣當(dāng)某個(gè)用戶向其好友發(fā)消息時(shí),首先通過好友id查看其登錄的msg server。如果好友與自己是同一臺(tái)服務(wù)器,那么直接轉(zhuǎn)發(fā)即可;如果不是,服務(wù)器向route server發(fā)送轉(zhuǎn)發(fā)該消息,并且?guī)夏繕?biāo)msg server的id.這樣route server 收到消息后,解析出目標(biāo)的msg server,進(jìn)行一次轉(zhuǎn)發(fā)即可,省去了大量的廣播消息。這種方式雖然解決了廣播消息的問題,但是在每臺(tái)msg server上都要保存所有用戶的路由信息。當(dāng)所有用戶都登錄時(shí),幾乎就退化成了單點(diǎn)模型,msg server肯定承受不了。
那么如何解決這個(gè)問題呢?試想一下,既然所有的msg server上都保存著同樣的路由信息,那么我們可以把這些數(shù)據(jù)從msg server剝離出來,存在一個(gè)單獨(dú)的服務(wù)器上,供msg server查詢。我們暫且把這個(gè)服務(wù)器叫做route info server(路由信息服務(wù)器).對于一個(gè)用戶要存儲(chǔ)的數(shù)據(jù)為
{
userid,
msgserverid
}
假設(shè)這兩個(gè)數(shù)據(jù)都是32Byte,那么存儲(chǔ)一億個(gè)用戶需要的內(nèi)存32B*10^8=3.2G。目前好點(diǎn)的服務(wù)器都有50G的內(nèi)存,很顯然內(nèi)存不是問題。那么就剩訪問量的問題。如果所有的msg server都從這一臺(tái)服務(wù)器上讀取數(shù)據(jù), 肯定會(huì)影響整個(gè)系統(tǒng)的性能。所以路由信息服務(wù)器不能采用這種單點(diǎn)模型。考慮到這種路由信息的特點(diǎn),很明顯是一種讀多寫少的數(shù)據(jù)。一個(gè)用戶只有在登錄的時(shí)候才會(huì)寫一次路由信息,其他時(shí)候就是轉(zhuǎn)發(fā)消息的時(shí)候讀取路由信息了。那么可以采用類似數(shù)據(jù)庫的主備模型,主服務(wù)器用來寫路由信息,備服務(wù)器用于查詢路由信息。而且可以設(shè)置多臺(tái)備服務(wù)器,分擔(dān)msg server的讀壓力。其實(shí)我們也可以使用一些成熟的緩存系統(tǒng)來完成路由信息服務(wù)器的功能,比如redis. redis擁有現(xiàn)成的主備方案,只是像這種通用的緩存服務(wù)器在存儲(chǔ)數(shù)據(jù)時(shí),消耗的內(nèi)存會(huì)大些。研究過redis源碼的,大多都能理解。其key value都存儲(chǔ)在redisobject的結(jié)構(gòu)體當(dāng)中,有一些附加的信息,所以比自己寫一個(gè)這樣的服務(wù)所消耗的內(nèi)存肯定會(huì)大些。
OK,說完了路由信息服務(wù)器,我們再回到msg server上來。那么msg server在轉(zhuǎn)發(fā)消息時(shí),首先根據(jù)目的用戶的id 到路由信息服務(wù)器上查找其所在的msg server用于消息轉(zhuǎn)發(fā)。但是這也會(huì)存在一個(gè),每次轉(zhuǎn)發(fā)消息時(shí),都要查詢一次路由信息,這無疑會(huì)影響消息的轉(zhuǎn)發(fā)速度,而且也會(huì)增大路由信息服務(wù)器的訪問壓力。如果在發(fā)送消息之后,將路由信息保存到本地,那么下次發(fā)送消息,就無需再去路由信息服務(wù)器重復(fù)查詢了。但是也不能把所有的路由全部保存到本地,那樣又會(huì)嚴(yán)重消耗msg server的內(nèi)存。于是,就有我們想到一種折中的方案,使用一個(gè)lru的緩存隊(duì)列,在需要保存新的路由信息時(shí),首先查看緩存隊(duì)列是否已滿,如果未滿,直接插入到隊(duì)首,如果隊(duì)列已滿,淘汰到隊(duì)尾的數(shù)據(jù)。緩存列隊(duì)大小可根據(jù)內(nèi)存大小靈活設(shè)置。考慮到在我們平時(shí)在使用qq時(shí),大部分人都登錄著,但是發(fā)消息的人并不多。對于路由信息,在其首次轉(zhuǎn)發(fā)消息是,從路由信息服務(wù)器查詢一次路由,在其整個(gè)回話過程中,路由信息都緩存在本地。在其會(huì)話結(jié)束后,將最近最久未使用的路由數(shù)據(jù)淘汰出去,這種做法再考慮到內(nèi)存使用的同時(shí),又大大減少了服務(wù)器的訪問次數(shù),算是一種較好的折中方案. 在完成了路由信息系統(tǒng)之后,route server也可以進(jìn)行水平擴(kuò)展,route server要做的僅僅是轉(zhuǎn)發(fā)消息,并不需要存儲(chǔ)數(shù)據(jù),擴(kuò)展起來非常方便。最終的系統(tǒng)架構(gòu)如下:
總結(jié):
1. 本文所描述的即時(shí)通信服務(wù)器架構(gòu),著重討論的是消息如何路由的問題,但這并不代表一個(gè)完整的即時(shí)通信服務(wù)器系統(tǒng),諸如注冊,登錄,離線消息,文件等功能這些都未在本文的討論范圍之類。
2. 本文中所提的方案也是一種設(shè)想,并未真正進(jìn)行實(shí)現(xiàn),肯定也有很多細(xì)節(jié)問題沒有考慮到。歡迎大家留言討論。
3. 對于本文所提的系統(tǒng),可稱之為一個(gè)服務(wù)集群。而像qq這樣數(shù)量用戶的系統(tǒng),在全國分布了很多個(gè)集群。本文所討論的也僅僅局限于一個(gè)集群內(nèi)的通信設(shè)計(jì),而集群之間的通信又如何通信呢。每個(gè)集群的路由數(shù)據(jù),如果全同步到其他集群,這種做法顯然不是最優(yōu)。如果有更好的想法,也歡迎留言討論。
文章轉(zhuǎn)自()
本站文章除注明轉(zhuǎn)載外,均為本站原創(chuàng)或翻譯。歡迎任何形式的轉(zhuǎn)載,但請務(wù)必注明出處、不得修改原文相關(guān)鏈接,如果存在內(nèi)容上的異議請郵件反饋至chenjj@fc6vip.cn