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

发表于2020-08-03
评论0 1.14w浏览

魔兽世界和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 获得更多有趣的并行知识。

  • 允许他人重新传播作品,但他人重新传播时必须在所使用作品的正文开头的显著位置,注明用户的姓名、来源及其采用的知识共享协议,并与该作品在磨坊上的原发地址建立链接
  • 可对作品重新编排、修改、节选或者以作品为基础进行创作和发布
  • 可将作品进行商业性使用

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引