使用redis實現5萬人同服的“相位技術”

孫碩發表於2020-08-13
魔獸世界和EVE伺服器能夠同時支援5萬人線上的技術肯定讓很多人流口水吧。今天我用redis來模擬實現“相位技術”。所謂“相位技術”就是將伺服器分為多個並行的空間。是對傳統分割成多個地圖場景技術的升級。這個技術通過建立多個並行時空的概念。將多個時空分配到不同的伺服器。在客戶端請求資料時再將多個時空的資料整合在一起。這樣理論上就可以將地圖場景再次無限分割。所以理論上使用“相位技術”的伺服器承載人數可以達到非常恐怖的5萬人。

傳統的一個地圖一個伺服器的做法。如果玩家過多就會大量消耗伺服器CPU資源。直到CPU資源耗盡達到伺服器人數上限。因為所有邏輯運算都擁擠在一個執行緒。這種多個功能間資源搶奪的現象會非常明顯。而其中玩家移動是最消耗資源的功能。在每一幀中移動的資料都需要同時廣播給其他的玩家。這樣其他的玩家才能看到這個玩家在移動。

如果螢幕內有1千個玩家,哪麼就需要廣播1千次。相當於每次移動的資料都放大了1千倍。而移動同步的頻率通常在每秒1次到60次。同步頻率越高在客戶端表現越細膩。如果每秒同步頻率是1次,哪麼每個使用者每秒鐘就要傳送一次千人的廣播。1千個使用者在伺服器一共要傳送1百萬次的同步資訊。也就是說移動同步資訊如果不加限制,哪麼將會成指數級別的增加。

每秒訊息總數量=同步頻率* (提交訊息數量+(玩家數量)2)

在實際應用中因為受到螢幕的限制,地圖遠處的玩家並不需要返回給客戶端。因為即使返回了也看不到。所以會採用9宮格的方式對返回的資料加以過濾。也就是將地圖劃分為多個正方形的格子。每次只返回包括當前格子和周圍共9個格子的玩家總數。像魔獸世界這樣的扁平地圖就可以採用這樣的方式。遊戲伺服器的地圖格子會比較大,通常在10米到50米左右。而高度不固定能達到100米甚至更高。

使用redis實現5萬人同服的“相位技術”

使用9宮格的方式可以很好的處理扁平地圖的狀況。但像eve這種空間上相對自由的遊戲也可以採取81宮的方式。就是將空間劃分為多個立方體的格子。每次返回周圍空間的81個格子中玩家的數量。

使用redis實現5萬人同服的“相位技術”

在九宮格方式中玩家的資料被分為兩部分。一個是玩家的座標資料“key:玩家id,value:x和y”。一個是所在格子的中玩家的列表,例如1*1格子中的玩家列表“key:1*1,value:id1, id2,id3...”。

在每一幀中客戶端都會向伺服器提交玩家的移動資料。伺服器會記錄玩家的座標,並根據座標修改玩家所在的格子資訊。例如某一幀中提交玩家座標“x為2, y為1.8”。伺服器查詢原來玩家的座標是“x為1.9, y為1.8”。哪麼伺服器就要將“玩家1”從“1*1”的格子移動“2*1”使用redis命令如下“SMOV 1*1 2*1 "玩家1"”。

在提交資料後還要取回周圍玩家的資訊,因為玩家被移動到了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中所有玩家的資料。

使用redis實現5萬人同服的“相位技術”

這時redis就可以看做是一個每幀都向使用者返回資料的狀態機。假如有100個使用者在每幀提交資料並返回資料。因為使用了九宮格作為資料的過濾系統。假設使用者以比較平均的狀態分佈在九宮格中。每次都返回10個左右的周圍使用者。哪麼這臺狀態機就是每幀輸入100個使用者資訊,並返回1000個使用者資訊。九宮格的所要處理的訊息數量就為:

每秒訊息總數量=同步頻率*玩家總數*(提交訊息數量+九宮格返回玩家數量)

我們知道redis處理能力是每秒鐘10萬次,如果每秒鐘60幀,100個使用者每秒鐘需要的處理量是6千次。遠遠小於redis的處理能力的上限。對於redis來說非常的輕鬆。

既然100人非常的輕鬆,哪麼1萬人同時線上呢?

突然跨越到這麼大的難度可能會讓人有點不適應。

1萬人以每秒60幀的速度向redis提交資料。每秒鐘將會達到60萬次提交,遠遠大於redis的承受能力。這時我們就要使用殺手鐗“相位技術”了。我們將1萬人平均分配到10臺伺服器。每臺伺服器將處理1千人。這樣每臺伺服器每秒將處理6萬條資料,在redis的10萬條資料處理能力範圍內。但我們不但要寫入資料還要獲取周圍玩家的資料。因為現在玩家被隨機分配到了10臺伺服器。這10臺伺服器就相當於10個獨立的平行空間。這樣每次我們獲取資料就要依次讀取10臺伺服器。這樣才能獲得周圍全部玩家的資訊。

使用redis實現5萬人同服的“相位技術”

注意!因為我們需要在其他10臺redis提交請求獲得返回資料。哪麼相當於每次使用者的提交動作將會被放大10倍才能獲得返回資料。這樣每秒返回資料的請求就變成了600萬次。顯然每個redis無法承擔額外的60萬次返回資料的查詢請求。所以我們要為每個redis建立10個主從伺服器來分擔返回資料的查詢請求。如下圖所示master redis2對於master redis1的返回資料查詢可以通過slave1 redis1實現。這樣返回資料的查詢就被10個slave伺服器平攤,每個伺服器承擔6萬次查詢小於redis的10萬次上限的要求。

使用redis實現5萬人同服的“相位技術”

因為“相位技術”的引進產生了以10臺redis為基礎的平行空間伺服器。以及平行空間伺服器的從伺服器組成的返回資料伺服器組。哪麼可以知為了支援每秒60幀,1萬人線上,需要的伺服器總數為110臺伺服器,其公式如下:

伺服器總數=主伺服器數量+主伺服器數量 * 主伺服器數量

而主伺服器數量的公式為:

主伺服器數量=需求線上人數*每秒幀數/redis上限人數

哪麼由上述兩個公式可以知,線上5萬人的伺服器需求為,5萬*60/10萬=30臺主伺服器。哪麼所需伺服器總數為30+900=930臺redis伺服器。因為redis是單核伺服器,所以對於硬體來說就是需要930核。就需要標準64核伺服器15臺。

本來想用golang實現一個演示版本,感覺配置幾十個redis還是很麻煩。以後有時間再寫程式碼吧。關注 surparallel.org 獲得更多有趣的並行知識。


來源:騰訊遊戲學院
原文:https://gameinstitute.qq.com/community/detail/133489

相關文章