8

使用redis实现5万人同服的“相位技术”

 3 years ago
source link: https://gameinstitute.qq.com/community/detail/133489
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

使用redis实现5万人同服的“相位技术”

发表于2020-08-03
评论0 2.7k浏览

想免费获取内部独家PPT资料库?观看行业大牛直播?点击加入腾讯游戏学院游戏程序行业精英群

711501594

魔兽世界和EVE服务器能够同时支持5万人在线的技术肯定让很多人流口水吧。今天我用redis来模拟实现“相位技术”。所谓“相位技术”就是将服务器分为多个并行的空间。是对传统分割成多个地图场景技术的升级。这个技术通过创建多个并行时空的概念。将多个时空分配到不同的服务器。在客户端请求数据时再将多个时空的数据整合在一起。这样理论上就可以将地图场景再次无限分割。所以理论上使用“相位技术”的服务器承载人数可以达到非常恐怖的5万人。

传统的一个地图一个服务器的做法。如果玩家过多就会大量消耗服务器CPU资源。直到CPU资源耗尽达到服务器人数上限。因为所有逻辑运算都拥挤在一个线程。这种多个功能间资源抢夺的现象会非常明显。而其中玩家移动是最消耗资源的功能。在每一帧中移动的数据都需要同时广播给其他的玩家。这样其他的玩家才能看到这个玩家在移动。

如果屏幕内有1千个玩家,哪么就需要广播1千次。相当于每次移动的数据都放大了1千倍。而移动同步的频率通常在每秒1次到60次。同步频率越高在客户端表现越细腻。如果每秒同步频率是1次,哪么每个用户每秒钟就要发送一次千人的广播。1千个用户在服务器一共要发送1百万次的同步信息。也就是说移动同步信息如果不加限制,哪么将会成指数级别的增加。

每秒消息总数量=同步频率* (提交消息数量+(玩家数量)2)

在实际应用中因为受到屏幕的限制,地图远处的玩家并不需要返回给客户端。因为即使返回了也看不到。所以会采用9宫格的方式对返回的数据加以过滤。也就是将地图划分为多个正方形的格子。每次只返回包括当前格子和周围共9个格子的玩家总数。像魔兽世界这样的扁平地图就可以采用这样的方式。游戏服务器的地图格子会比较大,通常在10米到50米左右。而高度不固定能达到100米甚至更高。

9DWTlbuS9fQTHUAGXuvK.jpg

使用9宫格的方式可以很好的处理扁平地图的状况。但像eve这种空间上相对自由的游戏也可以采取81宫的方式。就是将空间划分为多个立方体的格子。每次返回周围空间的81个格子中玩家的数量。

39OMn8O46ZqZSJqKi9Hx.jpg

在九宫格方式中玩家的数据被分为两部分。一个是玩家的坐标数据“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中所有玩家的数据。

vfgQ6ZELWT1Y9AqZfuLN.png

这时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台服务器。这样才能获得周围全部玩家的信息。

5IZJi4pENfccjXWrVeUl.png

注意!因为我们需要在其他10台redis提交请求获得返回数据。哪么相当于每次用户的提交动作将会被放大10倍才能获得返回数据。这样每秒返回数据的请求就变成了600万次。显然每个redis无法承担额外的60万次返回数据的查询请求。所以我们要为每个redis建立10个主从服务器来分担返回数据的查询请求。如下图所示master redis2对于master redis1的返回数据查询可以通过slave1 redis1实现。这样返回数据的查询就被10个slave服务器平摊,每个服务器承担6万次查询小于redis的10万次上限的要求。

XpFQs2ImbnntNmEAljyR.png

因为“相位技术”的引进产生了以10台redis为基础的平行空间服务器。以及平行空间服务器的从服务器组成的返回数据服务器组。哪么可以知为了支持每秒60帧,1万人在线,需要的服务器总数为110台服务器,其公式如下:

服务器总数=主服务器数量+主服务器数量 * 主服务器数量

而主服务器数量的公式为:

主服务器数量=需求在线人数*每秒帧数/redis上限人数

哪么由上述两个公式可以知,在线5万人的服务器需求为,5万*60/10万=30台主服务器。哪么所需服务器总数为30+900=930台redis服务器。因为redis是单核服务器,所以对于硬件来说就是需要930核。就需要标准64核服务器15台。

本来想用golang实现一个演示版本,感觉配置几十个redis还是很麻烦。以后有时间再写代码吧。关注 surparallel.org 获得更多有趣的并行知识。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK