使用redis實現5萬人同服的“相位技術”
傳統的一個地圖一個伺服器的做法。如果玩家過多就會大量消耗伺服器CPU資源。直到CPU資源耗盡達到伺服器人數上限。因為所有邏輯運算都擁擠在一個執行緒。這種多個功能間資源搶奪的現象會非常明顯。而其中玩家移動是最消耗資源的功能。在每一幀中移動的資料都需要同時廣播給其他的玩家。這樣其他的玩家才能看到這個玩家在移動。
如果螢幕內有1千個玩家,哪麼就需要廣播1千次。相當於每次移動的資料都放大了1千倍。而移動同步的頻率通常在每秒1次到60次。同步頻率越高在客戶端表現越細膩。如果每秒同步頻率是1次,哪麼每個使用者每秒鐘就要傳送一次千人的廣播。1千個使用者在伺服器一共要傳送1百萬次的同步資訊。也就是說移動同步資訊如果不加限制,哪麼將會成指數級別的增加。
每秒訊息總數量=同步頻率* (提交訊息數量+(玩家數量)2)
在實際應用中因為受到螢幕的限制,地圖遠處的玩家並不需要返回給客戶端。因為即使返回了也看不到。所以會採用9宮格的方式對返回的資料加以過濾。也就是將地圖劃分為多個正方形的格子。每次只返回包括當前格子和周圍共9個格子的玩家總數。像魔獸世界這樣的扁平地圖就可以採用這樣的方式。遊戲伺服器的地圖格子會比較大,通常在10米到50米左右。而高度不固定能達到100米甚至更高。
使用9宮格的方式可以很好的處理扁平地圖的狀況。但像eve這種空間上相對自由的遊戲也可以採取81宮的方式。就是將空間劃分為多個立方體的格子。每次返回周圍空間的81個格子中玩家的數量。
在九宮格方式中玩家的資料被分為兩部分。一個是玩家的座標資料“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就可以看做是一個每幀都向使用者返回資料的狀態機。假如有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臺伺服器。這樣才能獲得周圍全部玩家的資訊。
注意!因為我們需要在其他10臺redis提交請求獲得返回資料。哪麼相當於每次使用者的提交動作將會被放大10倍才能獲得返回資料。這樣每秒返回資料的請求就變成了600萬次。顯然每個redis無法承擔額外的60萬次返回資料的查詢請求。所以我們要為每個redis建立10個主從伺服器來分擔返回資料的查詢請求。如下圖所示master redis2對於master redis1的返回資料查詢可以通過slave1 redis1實現。這樣返回資料的查詢就被10個slave伺服器平攤,每個伺服器承擔6萬次查詢小於redis的10萬次上限的要求。
因為“相位技術”的引進產生了以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
相關文章
- Redis管道技術的使用Redis
- Redis | 第5章 Redis 中的持久化技術《Redis設計與實現》Redis持久化
- 使用 Redis 實現分散式系統輕量級協調技術Redis分散式
- 知乎問題:如何說服技術老大用 Redis ?Redis
- Spring Boot:使用Redis儲存技術Spring BootRedis
- Redis 技術整理Redis
- Redis叢集技術及Codis實踐Redis
- 學技術的同學不要盲目
- 基於Netty實現海量接入的推送服務技術要點Netty
- 極驗高併發驗證服務背後的技術實現
- 如何使用 redis 實現限流Redis
- Java多執行緒技術:實現多使用者服務端Socket通訊Java執行緒服務端
- Apache中URLRewrite技術的實現Apache
- 【主流技術】Redis 在 Spring 框架中的實踐RedisSpring框架
- 【雲棲大會】Redis技術的實踐與探索Redis
- 虛擬現實技術
- Java Redis系列2 (redis的安裝與使用+redis持久化的實現))JavaRedis持久化
- 協同軟體的實際應用和技術發展
- 在 Java 中利用 redis 實現 LBS 服務JavaRedis
- Cocos 技術派:實時競技小遊戲技術實現分享遊戲
- PHP 使用 Redis 實現分頁PHPRedis
- 使用redis實現互粉功能Redis
- 使用 Redis 實現分散式鎖Redis分散式
- Redis 中的原子操作(3)-使用Redis實現分散式鎖Redis分散式
- web前端技術分享:使用react實現簡易路由Web前端React路由
- 實現VR直播的關鍵技術VR
- 快速理解容器技術的實現原理
- Delphi中停靠技術的實現 (轉)
- Golang 實現 Redis(5): 使用跳錶實現 SortedSetGolangRedis
- react同構實踐——實現自己的同構模板React
- 一臺伺服器實現nginx代理負載均衡同時使用web服務伺服器Nginx負載Web
- Knative 實戰:基於 Knative Serverless 技術實現天氣服務-下篇Server
- Redis分散式鎖的使用與實現原理Redis分散式
- 【區塊鏈技術實現】區塊鏈
- 數字展館中虛擬現實技術的使用優勢
- VR虛擬現實技術在展館中使用的意義VR
- 【TAF】使用Oracle RAC的TAF技術實現不間斷查詢Oracle
- 使用 SOA 技術實現既有資產的開發和重組(上)