一网络游戏架构的前世今生

Posted 王元恺David

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一网络游戏架构的前世今生相关的知识,希望对你有一定的参考价值。

本文中的部分资料内容源于前aws的同事。

第一章将按下述顺序进行展开

  1. 网络游戏架构的基本理解
  2. 网络演进
  3. 计算演进
  4. 数据库演进
  5. 存储演进
  6. 实际案例
  7. 总结

网络游戏架构的前世今生

1. 网络游戏架构与游戏引擎

网络游戏架构(简称游戏架构)是一个听上去既高大上又“原始”的话题,业内其实谈及的场景非常非常非常有限。之所以说它高大上,是因为大家谈论的很少,思考的也相对较少;说它“原始”是因为,大部分谈论的架构、解决方案、场景,通常都是Web应用,与前沿且成熟的Web架构相对比,会产生游戏架构“原始”的感觉。我一直认为这里的“原始”是一定要加上引号的,因为我并不认为游戏架构真的粗糙而简陋,因为技术方向的差异,游戏更多的关注点在于一致且高效的性能——同样一个人能忍受不到半秒的下单延迟,却很难忍受哪怕稍微一停顿的切换装备(专业点这里的例子应该用存档来表述)。玩家希望游戏是极度流畅(这里的极度相比于一般Web应用)、稳定且能提供7*24小时不间断服务的,而游戏架构正是设计为这样的用户需求服务。

这里有必要区分一下“游戏引擎”和“游戏架构”这两个概念。在单机游戏中这两者没有太大区别,但在网络游戏中,我所认为的游戏架构的概念是一个更广的概念。提及游戏架构,往往会想到——客户端使用xxx游戏引擎,网络通信使用xxx网络连接,服务器使用xxx架构;游戏引擎一般指游戏客户端的可视化开发工具和可重用组件,与开发环境高度集成。我接触过白鹭、cocos2dx、Unity、CryEngine、Unreal Engine、Lumberyard,它们中的有一些已经扩展了不少服务器相关的功能组件,例如 Unity 的服务器方案,UE4 的 Dedicated Sever,大部分引擎也拥有自定义的组件市场,里面的功能保罗万象。但游戏引擎不是游戏架构,因为游戏架构不存在固定数量的最优解,而在这些组件包装好的同时,也失去了灵活性,所以这些组件通常只为对性能、对用户体量预期较低的小型游戏服务。游戏架构就像一个一眼看不到边界的大舞台,每个游戏开发者都能在这个舞台上大展拳脚,去实现自己独一无二的游戏。

游戏架构的演进很多时候是出于完全自发的状态,对于游戏本身的追求,部分时候甚至会高过把它当作一个用来赚钱的商品,这是一种强大的自驱力。 当我们做一个第一人称射击游戏,刚开始我们能对一个靶子开枪从而获得分数,自然而然的,我们想和身边的朋友比比谁更准,所以我们需要一个网络联机方案,把朋友们拉入一局对战。而当朋友没空时,我们需要一个机制让陌生人也能一起对战,所以我们需要一个匹配方案。而当我们的枪法水平在短时间得不到明显提升,需要一个成长机制持续不断的感受到正反馈,所以我们需要一个成长方案,例如更好的装备、更好的属性。游戏架构正是在一个又一个想法的产生与实践下不断演进。

大部分游戏都需要持续不断且“短期”的正反馈,这也是游戏区别于其他应用的地方,这也是游戏如此令人着迷的地方。为了提供更持续更高效的正反馈,必须把用户体验做到更好。有些硬核游戏的正反馈流程较长,有些甚至需要几十、上百小时的游戏游玩时间,但这也远比生活中的一般项目获得正反馈的时间成本要低了,也更强烈。

2. 网络方案演进

2.1 网络同步方案

回到网络游戏的早期,MUD、MUX游戏兴起,部分单机游戏提供局域网联机对战的功能,我们在仅由文字、字符画、简单贴图描述的世界中自由探险。在游戏中,我们需要近实时的和其他玩家交互,聊天、合作或对战。游戏把我们连接到一个世界中,进行网络同步,这是最早期的P2P(peer-to-peer)架构。

每个玩家在本地主机上所执行的指令快速同步到其他主机上,让所有主机计算出相同的战局信息,通过程序渲染展示给每位玩家看到,这种同步方案也被称为帧同步。这种帧同步带来了三个最明显的问题:1、逻辑不同步导致对局信息混乱;2、外挂(例全图挂,对于所有指令的本地直接解析显示)3、单局能承载的人数少,更多帧同步相关细节在这里不做展开。

一种思路是,我们可以从这些玩家中选举出一个主机,由它来进行一些仲裁。被选为主机的玩家被赋予了更多的权力,而它的机器性能和网络环境也成为一个重要的影响因素,主机的提前退出、网络中断都会导致游戏的结束,而主机糟糕的网络会严重影响其他玩家的游戏体验。当今,有一些支持自定义地图编辑器的游戏,使用这种方式进行网络联机。

第二种思路是,我们可以部署一系列独立的服务器,由他来作为主机,负责帧信号的同步、少量仲裁。游戏公司承担了服务器部署、维护的职责,游戏公司一般会选择网络条件较好的机房、采购昂贵的大带宽,由于早期网络环境比较复杂,还需要分别使用三大运营商所接入的机房,到后面开始有BGP接入的机房才能削减机房接入数量。这种架构也被成为 c/s (client/server) 架构。

第三种思路也是 C/S 架构,只不过我们换了一种同步方案。我们希望更多的人在同一个游戏世界进行交互,希望百人、千人、万人在同一个世界同时游玩;我们希望解决逻辑不同步导致的灾难性后果。由此我们设计了状态同步的架构,即服务器负责计算不同人物、物体的状态属性变化,并将这种状态属性的变化告知客户端,由客户端进行渲染展示,从而代替了同步逻辑帧(玩家指令)这种做法。这种方案被广泛应用在MMORPG、SLG等游戏中,部分MOBA类游戏在重要对局(例如电竞比赛)时,也会由帧同步切换为状态同步,当然也有全部状态同步的MOBA游戏。

网络同步方案各有优劣,目前不存在完美的网络同步方案适合所有的游戏场景,根据游戏类型和玩法需求选择一种或几种相结合是目前的主流。

未完待续……

网络游戏架构的前世今生——网关

上文: 网络游戏架构的前世今生——非会话游戏

3.5 网关

2018年,我在上海游戏圈推行网关 Gate 这个概念,也是我第一次从一个架构的学习者,逐步转变成一个架构的实践者的过程。其实现在网关这个概念早已走进民众视野,打开购物网站 app 搜索网关,能搜出一系列的产品,通常是指家用物联网网关。网关在我的理解中,既是对外实现广域互联的统一入口,也是对内实现局域互联的中转站,能解决设备或应用变多而导致的组网问题。简单来理解,就是一个网络流量的统一入口,转发到其他实际工作的服务器上。

在游戏中,网关是对外面向客户端的统一入口。在玩家完成登录等前置操作后,网关开始发挥作用,理论上网关不执行任何业务逻辑,只做筛选和转发。

如果没有网关,逻辑服直接暴露给玩家,会产生如下几个问题:

  1. 逻辑服实例越多,管理越麻烦,切换也麻烦
  2. 无法做到无缝切服换服,有等待时间
  3. 权限和审查下移,安全风险大大增加

一条一条来看,如果是小体量的游戏,所有逻辑服业务逻辑写成一个单体应用,那对于第一条不会有太大感触。随着业务量的提升,不管是出于功能的分类还是水平的扩展角度,逻辑服实际包含的服务器实例的数量会变多。客户端需要写入更多的服务器地址,或者使用其他地址获取方案。而如果使用网关,客户端只需要记录网关服的服务器地址即可,不管之后游戏功能如何变迁,永远只需要和网关对接,客户端不需要受后端架构影响。

第二条是最容易体会的。传统的切服换服是需要断开长连接返回“登陆后尚未建立长连接”的状态,由派发服 Dispatch (注:这里的“派发服”是我自己取的名,仅供参考)列出当前可以选择的所有区服,择一获取区服连接地址建立连接(有些游戏的区服选择不在UI进行展示,玩家感知较弱,但其本质相同)。这个过程涉及到断开长连接与再建立的过程,不管切换这个过程的UI交互如何设计,必然会面临切换连接的网络卡顿问题,无非是UI交互上如何优雅的提升用户体验。而如果最前面是一层网关层,玩家客户端是与网关建立的长连接,切服换服只是把网关背后的逻辑服实例更换了一下,并不会直接影响到客户端与网关直接的连接,所以可以做到无缝切服换服。

第三条是隐性且容易被忽视的,一个游戏在被 DDos 攻击后,被其他各种各样的手段入侵后,才会去考虑这一系列的问题。这时候游戏架构已经成型,无法大改,只能选择接入一些安全产品,能提升多大的防护力不得而知。如果我们将逻辑服的业务逻辑直接暴露在公网之上,想要做安全策略需要在每一个服务上编写,例如审计、IP黑白名单、用户权限、异常记录、封禁等。这样不仅工作量大,也很难从工程上确保每个服务都保质保量的做好安全策略,即攻击面分散,易被各个击破。我们只需要缩小直接面对敌人的接入面,就能将防守的精力集中,才有可能做好这件事,即最小化攻击面。回头再看看上面网关的架构,网关作为对外的统一入口,其实也承担了安全防护的职责。我们只需要在网关上编写我们的安全策略即可,当然也可以在网关上集成第三方的安全服务,事半功倍。

我一直认为网络安全是一场攻防战,不存在最锋利的矛,也不存在最坚固的盾。最小化攻击面实则为工程实现提供了一种可能——只需要在一处地方编写安全策略,从而防护所有服务的可能,这并不意味着不去编写安全策略就能防护,更不意味着编写了安全策略就能防住。需要有正确合适的心理预期在这件事上。

由上面几点引申而来,分出网关服这一方案有一个突出的优点,这个方案实则是从强有状态的逻辑服中剥离出一块无状态的部分。为了追求接口的处理速度和返回效率,在游戏工程项目上逻辑服都是有状态的,每个用户的状态信息被储存在内存中,且优先被读取使用。而网关服要做的事和游戏业务逻辑无关——筛选和转发,是很容易写成无状态的。这里的无状态不是严格意义上的无状态,而是网关服不存游戏玩家信息,可以轻易切换、关闭而不用担心会丢失信息。这一特性决定了,网关服能直接水平扩展,即可以开任意多个,可以自由的在高峰期扩展数量、在低谷期收缩数量,可以在 DDoS来临时快速启动更多的实例扛住并筛选掉攻击流量,保证后方业务逻辑正常运转。当然这是建立在物理机或虚拟机资源无限的情况下,实战中还需考虑成本。

网关中唯一的“状态”是用户的长连接信息,网关1保存的客户端连接和网关2中保存的客户端连接完全不同。但这个信息是可被丢弃的,客户端只需要和其他网关重新建立长连接即可。

在游戏中,网关也是对内实现局域互联的中转站。游戏通讯是全双工的,逻辑服某一块业务例如邮件系统,有主动发送内容给客户端的需求,而不是请求-响应(request & response)模型。逻辑服中这样的系统有很多,如果逻辑服实例各自为战,每一块代码都是自行通知客户端,则整个网络拓扑复杂。我们可以通过网关来实现一个中转,从而实现逻辑服业务层隐藏在接入层之下,应对策划等需求方不断的业务调整。

当然,网关也可以作为逻辑服内实例的中转站、逻辑服与战斗服的中转站。逻辑服与战斗服的交互可以很好的借助网关来完成,同时能利用上述的鉴权等安全措施防止伪造战斗服。同时也进一步解耦战斗服和逻辑服,中间由无状态的网关隐去双方的业务实现。至于逻辑服内部的中转,实用性不大,有更好的服务发现方案运转这个体系,后文会有详细介绍。

下期预告:
3.6 停服与热更
3.7 微服务

以上是关于一网络游戏架构的前世今生的主要内容,如果未能解决你的问题,请参考以下文章

智云星空一步一图,带你了解分布式架构的前世今生

微服务架构的前世今生:技术架构演变

了解微前端,深入前端架构的前世今生

了解微前端,深入前端架构的前世今生

了解微前端,深入前端架构的前世今生

了解微前端,深入前端架构的前世今生