状态同步的mmo网络游戏中的帧率

疑问:

mmo网络游戏中,

玩家操作自己A角色在游戏客户端放了1个技能,

游戏服务器收到这个“A放了技能”的指令,

游戏服务器计算这个技能的结果(比如B受到了攻击掉血,A减少魔法值,A增加怒气值,等等),

游戏服务器返回前面提到的“结果”,

游戏客户端收到“结果”后,做出动画表现(比如B受到了攻击掉血,A减少魔法值,A增加怒气值,等等)。

(1)整个过程需要多久?

(2)整个过程不能超过多久,才不会让玩家觉得卡?

(3)与此对应,服务器需要多长的处理时间才能不让玩家觉得卡?服务器又该如何设计?

注意:

2.暂时不考虑 tcp(mmo网络游戏通常用这个), udp, icmp(接下来试验用了ping) 之间的消息往返差异,假设他们都是一样的平均速率(简化问题干扰因素).

3.网络环境为常用的家用移动百兆光纤.

我们需要清楚,运营商所给的100M、200M是bit(比特),而我们的下载速度是byte(字节),bit(比特)不等于byte(字节),换算公式如下(以100M为例):100bit/8=12.5byte,也就是12.5m/s。

4.不考虑射击游戏、dnf那种动作游戏;帧同步游戏本文不研究,本文只研究状态同步的游戏,类似传奇那种.

解:

(1)

从上海ping百度:

IP地址: 36.152.44.96江苏省南京市 移动

可见:

<1>百度跟游戏的不同省进入不同区做法类似,从地理上接近,降低网络延迟.(比如,上海和南京很近,就让上海用户连接南京的服务器----当然,这可能是某种路由算法自动给出的结果)

<2>常见情况下,网络消息的一次来回需要至少0.01秒,不会超过0.02秒。(这还是不考虑 游戏服务器 计算A,B玩家之间伤害计算流程占用的时间的情况下)

(2)

人体反应速度:

每秒能看清超过 300 个画面,比当前主流屏幕刷新率 60Hz (0.0166秒刷新1次)多出 4 倍画面。

也就是说,即便是显示器,也没有追求超过人体极限。而是选择了合适的频率,这个频率能让人体接受,感觉不到画面闪和卡,又能节省硬件。

(3)

纯客户端游戏的帧率

FPS是图像领域中的定义,是指画面每秒传输帧数,通俗来讲就是指动画或视频的画面数。FPS是测量用于保存、显示动态视频的信息数量。每秒钟帧数愈多,所显示的动作就会愈流畅。通常,要避免动作不流畅的最低是30

(4)

mmo网络游戏,假设按30帧率(0.033秒提供1个画面),满足“客户端要求的流畅”:

除去0.01秒-0.02秒的信息往返时间。

还剩0.01秒-0.02秒的服务器和客户端计算时间(消息解包、技能和buff计算等等)

满足上述条件,即可保证“A刚放了技能,就看到了B掉血(A掉魔法,加怒气等)”。

(5)

游戏服务器通常有个“Timer循环”

例如

引用于

深入浅出 node.js 游戏服务器开发——基于 Pomelo 的 MMO RPG 开发_IT 哈的博客-CSDN博客

(6)

其实,服务器的帧率有时会设置得更高,比如200Hz. 也就是说0.005秒就要updateArea()一次。

主要是为了“及时响应”客户端发来的消息。

具体百度搜索“令人头痛的游戏延迟,如何解决”:

一个额外疑问

短短的 0.005秒 能将所有这些逻辑 updateArea() 执行一遍么?

(再考虑很多mmo中,1个场景服务器上会有多个永久地图、多个副本地图,每个地图上有非常多的NPC,玩家,还有各种技能、buff的计算等等。尤其是移动位置信息在多个玩家之间同步。)

我认为肯定是执行不完的。执行不完又该怎么办,怎么解决? 这个问题后面再研究 。

(7)

极限情况下,服务器需要 0.005秒  计算出这个技能的结果(比如B受到了攻击掉血,A减少魔法值,A增加怒气值,等等)。才可保证“A刚放了技能,就看到了B掉血(A掉魔法,加怒气等)”。

(8)

但是,游戏客户端在放技能前,通常会先播放动画(印象中状态同步的mmo一般一个攻击动画要1秒以上),动画结束后,才会有受击方的掉血,攻击方掉魔法,攻击方加怒气的动画。

所以,实际需求的并不是0.03秒就获得反馈,而是1秒才获得反馈

除去0.02秒的网络传输时间,

服务器其实是有至少0.9秒的时间来处理整套游戏逻辑。

(9)

那么 0.9秒 就能将所有这些逻辑 updateArea() 执行一遍么?

个人认为,还是不一定。(单是数据保存,比如掉落的物品捡到身上,最后要落入数据库,就原超这个时间了;在线人数越多,执行时间越长)

所以,

updateArea() 肯定不能设置成固定帧率,而是要“设定成最高帧率200,帧率可以动态调整,同时日志记录每1帧的执行时间(每1帧所有逻辑都执行完毕后再执行下1帧)”

大致代码为:

global int lastUpdateTime = 0;

int updateArea()
{
    lastUpdateTime = now;
    一堆逻辑.
    if(now - lastUpdateTime > 0.01秒)
    {
        printf("本帧执行时间过长:%d", now - lastUpdateTime);
    }    
}

int main()
{
    while(true)
    {
        if(now - lastUpdateTime < 0.005秒)
        {
            sleep(1); // 避免cpu本来就吃不满时,while循环高频执行占用过多cpu
            continue;
        }
        updateArea();
    }
}

这里对sleep(1)的作用有更好描述:

https://www.csdn.net/tags/MtTaEg0sNjQyNzA1LWJsb2cO0O0O.html

一方面,会拆分场景服务器做横向扩展(通过压测和记录超时日志后确定单个场景服务器的人数承载上限)、拆分数据保存逻辑到另外一个进程、拆分好友关系和排行这些跟场景战斗关系不大的逻辑到另外一个进程等等。例如下面这种架构:

引用于

浅谈MMORPG服务器架构 - 知乎

另一方面,代码中会对各种逻辑设定各种update周期(比如场景对象位置管理器刷新周期也许为0.1秒1次,debuff会从设计上做成每1秒掉血100天然就是低频率计算的 但 buff管理器刷新周期可能依然设置的相对高频比如0.1秒1次,接受客户端消息也会限定时间间隔比如0.05秒1次),并不会把所有逻辑都做成需要高频检查和高频运算(这就可以节约很多计算资源,缩短每条指令的执行时间。比如,debuff掉血 和 技能指令掉血的触发时机是不同的。debuff掉血可能是1秒循环1次,技能指令是每0.005秒就会集中从tcp中取出并处理1次)。在 及时反馈 和 执行效率之间取个平衡

(10)

那么,1次技能的释放,跟update周期 之间有什么关联?

一、

首先,要明白

“A放了技能”的指令,导致B受到了攻击掉血,A减少魔法值,A增加怒气值,

实质是什么:

<1>A角色在服务器这里,就是内存中的一段数据;这块数据跟一个tcp连接之间有着映射关系。B角色也是一样。

<2>A角色的游戏客户端通过tcp连接,发来一个“A放了技能”的指令

<3>通过这个tcp连接,找到了对应的A角色的数据在服务器内存中的位置。

<4>修改A角色的数据(比如魔法值,怒气值),同时找到另外一块关联的数据(比如B的位置,血量)进行修改。

<5>将修改后的数据结果,通过tcp分别发送给 A,B的游戏客户端。

二、

服务器最快 执行updateArea()0.005秒1次(每秒200帧)。

假设每个客户端发送指令频率0.1秒1次,单个场景服务器最多500个客户端(个人工作经历中,确实遇到过生产环境400人单个场景服务器就明显卡顿的情况)。(每秒5000个指令)

单个场景服务器理想情况下,从tcp中取出需要处理的“客户端指令”为,每1次会取出25个客户端发来的指令。(平均0.005秒 内要 执行完 25条指令

这看起来还是很吃力。

三、

实际情况是,需求通常是“技能动画1秒后,才开始掉血”,可以认为战斗过程中每个客户端发送指令频率1秒1次。

则(平均0.05秒 内要 执行完 25条指令),这样看起来似乎就不那么吃力了。

四、

再通过实际压测,一般限制到单场景服务器300人左右:(平均0.05秒 内要 执行完 15条指令。平均0.003秒内要 执行完 1条指令。但这些指令不一定全是战斗相关的对cpu占用很高的指令。

服务器的计算压力会进一步减小,直到游戏客户端不会觉得卡顿。

五、

在游戏逻辑很复杂的情况下,服务器能否满足 0.003秒内要 执行完 1条指令?

这其实只能靠压力测试来判断。

如果发现仍然很吃力,

可以先做性能分析(会有各种工具做各个函数的执行时间统计,通常都是移动相关的部分占用cpu时间最长但这部分通常已经优化到了难以继续优化的地步,优化难度也很大。实际项目开发过程中,功能需求很多,不会给你足够时间做移动同步这种优化,这种优化是上线前就该做好的

最简单的方案是继续降低 单场景人数,增加物理机器(或者给多核机器增加场景服务器进程)做横向扩展

(11)

另外,还有需要考虑的地方:网络流量。

很可能 cpu 本身够用,但是 网络传输达到峰值,进而导致表现卡顿。(比如 多人同屏广播)。

这需要 了解 游戏服务器所使用的主机 提供了多少的带宽。(包括不同服务器内部信息交互时用的内网带宽、客户端和游戏网关服务器交互时用的外网带宽

同时记录各个主机每日的cpu、内存、网络上下行流量、磁盘io

根据 网络上下行流量 和 游戏服务器所使用的主机支持的带宽 做比对,进而可以得知带宽是否不足。(个人工作经历中,观察过卡顿时的cpu,内存,网络,磁盘io曲线。跟运维了解过,通常网络带宽够用。偶尔会网络波动,这受公网环境影响,游戏开发者管不了公网的状况。cpu 倒是经常出现占用过高的情况。)

备注1:

当前内网带宽通常的量级是什么

可见,可达 千兆Byte/s . 应对 内部服务器之间通讯是够用的。

备注2:

当前公网带宽通常的量级是什么:

服务器带宽以阿里云服务器带宽为例:阿里云公网带宽出网带宽方向是收费的,入网带宽也是免费的

低配的不到 1MByte/s。 一年500~2000元。(跟内网带宽量级完全不同)。

这种肯定不能用作mmo游戏服务器。

 假设1000个人1个区同时在线(分散在20个场景,每场景50人),需要多少带宽才能将移动同步的消息(不用9宫格做同步优化)全部出往发送到每个客户端?(假设每个客户但每秒发送1次移动指令)

服务器每秒需要发送出去 50*50*20 = 5万 移动结果。

1个移动结果包括(x坐标,y坐标,角色id)大约12个Byte。

即 服务器每秒需要发送出去 0.6MByte。

看起来需要的出网带宽似乎不多。

但考虑到 游戏中不仅仅有 移动信息要同步,还有血量、装备等信息,客户端但发送频率也不会只有1秒1次。场景中也不只有玩家,还有很多npc和怪物的移动信息需要同步。出网的量肯定不止 0.6MByte。

具体要根据实际测试结果来确定需要的 公网带宽。

我印象中,对1000个用户做4个网关负载均衡的情况下,每台机器的带宽通常会用10~50M。

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值