使用redis实现5万人同服的“相位技术”
魔獸世界和EVE服務(wù)器能夠同時支持5萬人在線的技術(shù)肯定讓很多人流口水吧。今天我用redis來模擬實現(xiàn)“相位技術(shù)”。所謂“相位技術(shù)”就是將服務(wù)器分為多個并行的空間。是對傳統(tǒng)分割成多個地圖場景技術(shù)的升級。這個技術(shù)通過創(chuàng)建多個并行時空的概念。將多個時空分配到不同的服務(wù)器。在客戶端請求數(shù)據(jù)時再將多個時空的數(shù)據(jù)整合在一起。這樣理論上就可以將地圖場景再次無限分割。所以理論上使用“相位技術(shù)”的服務(wù)器承載人數(shù)可以達到非常恐怖的5萬人。
傳統(tǒng)的一個地圖一個服務(wù)器的做法。如果玩家過多就會大量消耗服務(wù)器CPU資源。直到CPU資源耗盡達到服務(wù)器人數(shù)上限。因為所有邏輯運算都擁擠在一個線程。這種多個功能間資源搶奪的現(xiàn)象會非常明顯。而其中玩家移動是最消耗資源的功能。在每一幀中移動的數(shù)據(jù)都需要同時廣播給其他的玩家。這樣其他的玩家才能看到這個玩家在移動。
如果屏幕內(nèi)有1千個玩家,哪么就需要廣播1千次。相當于每次移動的數(shù)據(jù)都放大了1千倍。而移動同步的頻率通常在每秒1次到60次。同步頻率越高在客戶端表現(xiàn)越細膩。如果每秒同步頻率是1次,哪么每個用戶每秒鐘就要發(fā)送一次千人的廣播。1千個用戶在服務(wù)器一共要發(fā)送1百萬次的同步信息。也就是說移動同步信息如果不加限制,哪么將會成指數(shù)級別的增加。
每秒消息總數(shù)量=同步頻率* (提交消息數(shù)量+(玩家數(shù)量)2)
在實際應(yīng)用中因為受到屏幕的限制,地圖遠處的玩家并不需要返回給客戶端。因為即使返回了也看不到。所以會采用9宮格的方式對返回的數(shù)據(jù)加以過濾。也就是將地圖劃分為多個正方形的格子。每次只返回包括當前格子和周圍共9個格子的玩家總數(shù)。像魔獸世界這樣的扁平地圖就可以采用這樣的方式。游戲服務(wù)器的地圖格子會比較大,通常在10米到50米左右。而高度不固定能達到100米甚至更高。
?
使用9宮格的方式可以很好的處理扁平地圖的狀況。但像eve這種空間上相對自由的游戲也可以采取81宮的方式。就是將空間劃分為多個立方體的格子。每次返回周圍空間的81個格子中玩家的數(shù)量。
?
在九宮格方式中玩家的數(shù)據(jù)被分為兩部分。一個是玩家的坐標數(shù)據(jù)“key:玩家id,value:x和y”。一個是所在格子的中玩家的列表,例如1*1格子中的玩家列表“key:1*1,value:id1, id2,id3...”。
在每一幀中客戶端都會向服務(wù)器提交玩家的移動數(shù)據(jù)。服務(wù)器會記錄玩家的坐標,并根據(jù)坐標修改玩家所在的格子信息。例如某一幀中提交玩家坐標“x為2, y為1.8”。服務(wù)器查詢原來玩家的坐標是“x為1.9, y為1.8”。哪么服務(wù)器就要將“玩家1”從“1*1”的格子移動“2*1”使用redis命令如下“SMOV 1*1 2*1 "玩家1"”。
在提交數(shù)據(jù)后還要取回周圍玩家的信息,因為玩家被移動到了2*1,我們使用“SMEMBERS 3*1 3*2 2*1 2*2 1*1 1*2”將返回周圍格子3*1,3*2,2*1,2*2,1*1,1*2中所有玩家的數(shù)據(jù)。
?
這時redis就可以看做是一個每幀都向用戶返回數(shù)據(jù)的狀態(tài)機。假如有100個用戶在每幀提交數(shù)據(jù)并返回數(shù)據(jù)。因為使用了九宮格作為數(shù)據(jù)的過濾系統(tǒng)。假設(shè)用戶以比較平均的狀態(tài)分布在九宮格中。每次都返回10個左右的周圍用戶。哪么這臺狀態(tài)機就是每幀輸入100個用戶信息,并返回1000個用戶信息。九宮格的所要處理的消息數(shù)量就為:
每秒消息總數(shù)量=同步頻率*玩家總數(shù)*(提交消息數(shù)量+九宮格返回玩家數(shù)量)
我們知道redis處理能力是每秒鐘10萬次,如果QQ靚號購買每秒鐘60幀,100個用戶每秒鐘需要的處理量是6千次。遠遠小于redis的處理能力的上限。對于redis來說非常的輕松。
既然100人非常的輕松,哪么1萬人同時在線呢?
突然跨越到這么大的難度可能會讓人有點不適應(yīng)。
1萬人以每秒60幀的速度向redis提交數(shù)據(jù)。每秒鐘將會達到60萬次提交,遠遠大于redis的承受能力。這時我們就要使用殺手锏“相位技術(shù)”了。我們將1萬人平均分配到10臺服務(wù)器。每臺服務(wù)器將處理1千人。這樣每臺服務(wù)器每秒將處理6萬條數(shù)據(jù),在redis的10萬條數(shù)據(jù)處理能力范圍內(nèi)。但我們不但要寫入數(shù)據(jù)還要獲取周圍玩家的數(shù)據(jù)。因為現(xiàn)在玩家被隨機分配到了10臺服務(wù)器。這10臺服務(wù)器就相當于10個獨立的平行空間。這樣每次我們獲取數(shù)據(jù)就要依次讀取10臺服務(wù)器。這樣才能獲得周圍全部玩家的信息。
注意!因為我們需要在其他10臺redis提交請求獲得返回數(shù)據(jù)。哪么相當于每次用戶的提交動作將會被放大10倍才能獲得返回數(shù)據(jù)。這樣每秒返回數(shù)據(jù)的請求就變成了600萬次。顯然每個redis無法承擔額外的60萬次返回數(shù)據(jù)的查詢請求。所以我們要為每個redis建立10個主從服務(wù)器來分擔返回數(shù)據(jù)的查詢請求。如下圖所示master redis2對于master redis1的返回數(shù)據(jù)查詢可以通過slave1 redis1實現(xiàn)。這樣返回數(shù)據(jù)的查詢就被10個slave服務(wù)器平攤,每個服務(wù)器承擔6萬次查詢小于redis的10萬次上限的要求。
?
因為“相位技術(shù)”的引進產(chǎn)生了以10臺redis為基礎(chǔ)的平行空間服務(wù)器。以及平行空間服務(wù)器的從服務(wù)器組成的返回數(shù)據(jù)服務(wù)器組。哪么可以知為了支持每秒60幀,1萬人在線,需要的服務(wù)器總數(shù)為110臺服務(wù)器,其公式如下:
服務(wù)器總數(shù)=主服務(wù)器數(shù)量+主服務(wù)器數(shù)量 * 主服務(wù)器數(shù)量
而主服務(wù)器數(shù)量的公式為:
主服務(wù)器數(shù)量=需求在線人數(shù)*每秒幀數(shù)/redis上限人數(shù)
哪么由上述兩個公式可以知,在線5萬人的服務(wù)器需求為,5萬*60/10萬=30臺主服務(wù)器。哪么所需服務(wù)器總數(shù)為30+900=930臺redis服務(wù)器。因為redis是單核服務(wù)器,所以對于硬件來說就是需要930核。就需要標準64核服務(wù)器15臺。
本來想用golang實現(xiàn)一個演示版本,感覺配置幾十個redis還是很麻煩。以后有時間再寫代碼吧。關(guān)注 surparallel.org 獲得更多有趣的并行知識。
總結(jié)
以上是生活随笔為你收集整理的使用redis实现5万人同服的“相位技术”的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Unity 分离贴图 alpha 通道实
- 下一篇: Unity 高清渲染管线 ShaderG