端游和手游服务器的共同架构是什么?
类型1:卡牌、跑酷等弱交互服务器中的卡牌跑酷。
因为互动性弱,玩家之间不需要实时面对面的PK,只需要点击对方的离线数据,计算排行榜,买卖道具,所以实现往往使用简单的HTTP服务器:
登录时可以使用非对称加密(RSA,DH)。服务器根据客户端uid、当前时间戳和服务器私钥,计算哈希得到的加密密钥并发送给客户端。之后,双方通过HTTP进行通信,并使用该密钥进行RC4加密。收到密钥和时间戳后,客户端将其保存在内存中,以备将来通信之用。服务器不需要保存密钥,因为每次都可以根据客户端发来的uid和时间戳以及服务器自己的私钥来计算。通过模仿TLS的行为,保证多个HTTP请求之间的客户端身份,通过时间戳保证同一个人的登录密钥两次不同。
每次游戏开始,访问它,请求等级数据,游戏结束后再次提交,检查是否合法,获得什么奖励。数据库可以用单个MySQL或者MongoDB缓存,可以用后端的Redis(可选)。如果要实现通知,让客户端定时轮询服务器15秒,有消息就记下来。如果没有消息,轮询时间可以逐渐延长,比如30秒。如果有消息,把轮询时间缩短到10秒,5秒,即使两个人聊天,延迟也可以自适应。
这种服务器实现一个三国战略或者一个打卡酷跑游戏绰绰有余。因为这类游戏逻辑简单,玩家之间的互动性不强,如果用HTTP开发,开发速度快,调试只需要一个浏览器。
类型2:第一代游戏服务器1978
1978年,英国著名财经学校埃塞克斯大学的学生罗伊·特鲁布肖(Roy Trubshaw)编写了世界上第一个MUD程序MUD1,埃塞克斯大学在1980连接ARPANET后,加入了很多外部玩家,甚至是外国玩家。ARPANET***享用了MUD1的源代码后,出现了很多改编版本,随后MUD风靡全球。在不断改进MUD1的基础上,产生了开源的MudOS(1991),成为了众多网络游戏的鼻祖:
MUDOS是用C语言开发的,因为玩家之间有很强的互动性(聊天,交易,PK)。MUDOS使用单线程非阻塞socket为所有玩家服务,所有玩家的请求都发送到同一个线程进行处理。主线程每1秒更新一次所有对象(网络收发器、对象状态机更新、处理超时、地图刷新、NPC刷新)。
游戏世界以房间的形式组织,每个房间都有东南西北四个方向,可以移动到下一个房间。因为欧美最早的网游都是地牢迷宫的形式,场景的基本单位叫做“房间”。MUDOS使用一种叫做LPC的脚本语言来描述整个世界(包括房间拓扑、配置、NPC和各种情节)。游戏中的高级玩家(巫师)可以通过修改脚本不断给游戏添加房间和剧情。早些年,MUD1上线时只有17个房间。毕业后,罗伊·特鲁布肖(Roy Trubshaw)将其交给弟弟理查德·巴特尔(Richard Battle),在理查德·巴特尔的手中,他不断地给100多个房间添加各种游戏,最终让MUD发展起来。
用户使用Telnet等客户端,用Tcp协议连接MUDOS,以纯文本方式玩游戏,用回车分割每个指令。比如1995,国内第一款泥巴游戏《侠客行》,如果你输入“往东走”,游戏会提示:“后花园——这是云庄的后花园,长满了花草,几个庄丁正在浇花。这是含羞草生长的地方。这里唯一的出口是北边。这里有:华木,和两个庄丁。然后你继续用文字操作,查看阿木的信息:“看”系统提示:的弟子“花木”,奉命看管这里的含羞草。他看上去30多岁,眉清目秀,正直大方,一表人才。他的武功看起来也不是很高,出手也好像极轻。”那你可以选择打他得到含羞草,但是吃了含羞草可能会中毒而死。在网络资源匮乏的早期,这类游戏的代入感很强。
用户数据存储在文件中。每个用户登录时,所有的用户数据都是从文本文件中加载的,所有的操作都是在内存中进行的,不需要马上刷回磁盘。用户退出,或者每5分钟检查一次数据有没有变化,他们会保存磁盘。当时这样的系统每台服务器承载4000人同时玩游戏,不是特别大的问题。自从1991发布MUDOS以来,世界各地都在为它改进、扩充、退出新版本。随着Windows图形功能的增强。1997游戏《UO》在MUDOS的基础上给角色添加了X和Y坐标,给每个房间添加了地图,给每个角色添加了动画,形成了第一代图形网游。
由于游戏内容基本可以通过LPC脚本定制,MUDOS成为了第一个名副其实的服务器引擎。引擎一次性开发,然后制作不同的游戏内容。很多后续的国产游戏,比如《万王之王》,都是像《UO》一样直接在MUDOS上开发,加入了房间的地图和人物的坐标。这个框架一直为中国第一代MMORPG提供了坚实的支持。直到2003年,游戏都是基于MUDOS开发的。虽然很多东西都是以图形方式添加的,但这些MMORPG后端的本质是MUDOS。随着游戏内容越来越复杂,架构越来越不堪,各种负载问题慢慢浮出水面,于是有了我们的第二代游戏服务器。
类型3:第二代游戏服务器2003
2000年以后,网游已经脱离了最初的文字泥巴,进入了综合图形时代。首先我不能忍受的其实是很多小文件。用户上线下线,频繁读写用户数据,导致负载越来越大。随着在线人数和游戏数据的增加,服务器负担变小。同时早期的EXT磁盘分区比较脆弱,稍有停电就容易出现大规模的数据丢失。因此,第一步是分割文件并将其存储在数据库中。
此时游戏服务器已经从旧的MUDOS系统中分离出来,各公司开始参考MUDOS架构,用C重新开发自己的游戏服务器。而且脚本也抛弃了LPC,换成了扩展性更好的Python或者Lua。由于主逻辑采用单线程模式,随着游戏内容的增加,传统的单服务器架构进一步成为瓶颈。于是有人开始将游戏世界拆分成以下模式:
拆分后游戏服务器的压力有所缓解,但是两台游戏服务器同时访问数据库,使得数据库成为下一个瓶颈。这样就形成了一个数据库前端代理(DB Proxy)。游戏服务器不直接访问数据库,而是访问代理,然后代理访问数据库并提供内存级缓存。早些年,MySQL4不提供存储过程。这个前端代理通常运行在与MySQL相同的平台上。它将游戏服务器发来的高级数据操作指令进行了转化,拆分成具体的数据库操作,在一定程度上替代了存储过程:
但是这种结构并没有持续多久,因为玩家在切换场景的时候经常要切换连接,中间的状态很容易混乱。而且游戏服务器多了,相互之间的数据交互会变得更加麻烦,于是人们把网络功能拆分出来,独立创建一个网关服务闸(有的地方叫Session,有的地方叫LinkSvr,名称不同):
单独提取网络功能,让用户连接一个网关服务器,然后网关服务器将数据转发给后端游戏服务器。游戏服务器之间数据交换也连接到网络管理进行交换。这类服务器基本可以稳定的为玩家提供游戏服务。一个网关服务1-20000人,后面每个游戏服务器服务5k-1w,根据游戏类型和复杂程度而定。图中隐藏了很多不重要的服务器,比如登录和管理。这是目前应用最广泛的模型,今天许多新项目都将采用这种结构。
每个人都有惰性。根据以往的经验,似乎MUDOS越开放,性能就会越好。于是我们继续认为网关可以拆分,聊天交易等基础服务可以拆分,可以提供web接口,可以拆分数据库,于是有了以下模型:
这种模式好用吗确实有一些成功的游戏使用了这样的架构,并充分发挥其性能优势,比如一些大型MMORPG。但是,有两个挑战:服务器每增加一级,状态机的复杂度可能会翻倍,这将导致R&D和bug查找的成本增加;这对开发团队来说是一个巨大的挑战。一旦项目时间紧张,开发人员经验不足,很容易挂掉。
比如我见过上海某一线游戏公司的RPG,就想出了这样的结构。我查看了他们团队成员的体验,询问了他们的在线约会,建议他们使用稍微简单一点的模型。人们很有信心,成功的项目都是这么做的,也想这么做,也很想做到一套。于是他们义无反顾的开始编码,项目做了一年多。然后,就没有了。
现在在游戏成功率不高的情况下,投资回报一开始就需要在更复杂的框架下考虑,比如你的游戏上线后半年内PCU会去多少?如果一款APRG游戏每组服务器不能达到5000人,那么选择更贴近实际情况的架构更经济。就算你的项目真的朝着1000人的目标超过5000人,我相信那个时候你的项目已经赚了不少钱了。你数着钱加班加点一步一步迭代,一次次拆分。我相信你的内心也是幸福的。
以上类型基本都是从MUDOS的拆分开始,MUDOS中的组件一步步拆分成分布式的。虽然时至今日,很多新项目还在使用上述类似结构中的一种,或者自己拆分了其他热门模块。因为它们本质上是MUDOS的分解,所以被归类为第二代游戏服务器。
类型4:第三代游戏服务器
自2007年《魔兽世界》以来,无缝世界地图已经深入人心。相比之前的游戏,玩家还是需要几步之后切换场景,每次等待加载几十秒是一件很有破坏性的事情。所以对于2005年以后的大型MMORPG来说,无缝地图已经成为一种标准配置。与之前根据地图进行切割的游戏相比,无缝世界中没有地图,地图上的人只被一个服务器处理:
每个节点服务器用于管理一个地图区域,NodeMaster(NM)为它们提供整体管理。更高层次的世界提供内地层次的管理服务。这里省略了一些详细的服务器,如传统的数据库前端、登录服务器、日志和监控等。,全部由ADMIN汇总。在这样的结构下,玩家必须简单地处理从一个区域到另一个区域的移动:
玩家1完全由节点A控制,玩家3完全由节点B控制..玩家2,在两个节点的边缘,同时由A和B服务,在从A移动到B的过程中,玩家2会同时向A请求左情,向B请求右情。但此时,2号玩家仍然属于A管理层。直到2号玩家完全离开了AB边界,他才完全被B管理..按照这种逻辑,世界地图被划分为不同的区域,由不同的节点管理。
对于一个节点负责的区域,不需要进行地理上的连接。比如大陆的外围部分和山区人口较少,可以用一个节点来管理,但这些区块在地理上并不一定要相连。哪个块由一个节点管理?根据游戏实时运行的负载,定期维护时可以更改NodeMaster上的配置。所以遇到的第一个问题是,很多节点服务器需要和玩家进行通信,需要询问管理服务器,特定UID的玩家在哪个闸门上。以前按场景切服务器问题不大,问一次就可以缓存,但是现在服务器种类增加了很多,玩家会四处漂移,按UID找玩家比较麻烦。另一方面,GATE需要根据坐标动态计算与哪个节点进行通信,导致逻辑越来越粗,因此从负责连接管理的GATE中切掉“用户对象”势在必行,于是建立了如下模型:
网关服务器再次返回简化的网络转发功能,用户逻辑由OBJ服务器承担,除以UID。网关根据网络接入时的负载进行分配,而OBJ根据资源号(UID)进行分配,因此与用户的通信可以直接根据UID计算OBJ服务器号并发送数据。新独立的OBJ提供更高水平的服务:
对象移动:管理特定玩家在不同节点管辖区域之间的移动,并与所需节点进行通信。
数据广播:节点可以为每个用户设置多个标签,然后通知对象主根据标签进行广播。
对象消息:通用消息推送,它将数据发送给一个用户,并直接告诉OBJ,而不直接与GATE打交道。
与朋友聊天:人物之间的聊天直接进入OBJ/OBJ大师。整个服务器体分为三层后,NODE侧重于场景,OBJ侧重于玩家对象,
GATE专注于网络。该模型已广泛应用于无缝场景服务器中。但是,随着时间的推移,负荷问题越来越明显。作为一个活动,远离活跃的区域变得非常活跃,靠每周维护来调整还是比较繁琐,于是就有了动态负载均衡。动态负载平衡有两种方法。第一种方法是根据负载,节点主每隔一段时间动态移动修改每个节点的边界,不同的玩家对象按照前面的方法从一个节点迁移到另一个节点:
图11动态负载平衡
Node Master定期在地图上寻找热点,计算出新的场景切割方式,然后告诉其他服务器开始调整。具体的处理方法和上面的越界移动对象的方法一样。但上述方法的实现相对复杂,所以人们设计了一种更简单、更直接的新方法:
图12基于网格的动态负载均衡
对于网格的动态负载均衡,将地图按照标准大小均匀切割成静态网格,每个网格负责一个特定的节点,但可以根据负载情况实时迁移到其他节点。迁移分为三个阶段:准备、切换和完成。这三种状态由节点主机维护。在准备阶段,新节点开始同步旧节点上网格的数据,完成后告诉nm;NM确认OK后,通知新旧节点完成切换。切换后,如果Obj服务器仍在与旧节点通信,旧节点将对其进行纠正,纠正后的OBJ将纠正其自身状态,并与新节点通信。
很多无缝动态负载均衡服务器都声称支持无限人数,但并不意味着MMORPG游戏的最大人数可以无限扩大,因为这样的系统会受到网络带宽和客户端性能的限制。带宽决定了同一区域的最大广播限制,而客户端性能决定了同一屏幕上可以绘制多少个角色。
自从无缝地图引入分布式对象模型后,彻底脱离了MUDOS系统,成为一种新的服务器模型。因为引入了动态负载均衡,无缝服务器更加强大,容纳了比上一代游戏服务器多几倍的上限,提供了更好的游戏体验。我们称之为第三代游戏服务器架构。网游是从大型多人角色扮演开始的,RPG网游一度长期占据90%以上的份额,使得基于MMORPG的服务器架构蓬勃发展。然而,随着RPG玩家的疲劳,各种非MMORPG游戏如雨后春笋般出现在人们面前,受到市场的欢迎。
第五类:Battle.net游戏服务器
经典战役有两个区别。net服务器和RPG游戏:RPG是分区的,北京和广州的用户互不接触。而Battle.net,虽然每个游戏一般不到8个玩家,但是全国只有一个服务器,所有玩家可以一起玩,玩家和玩家用P2P连接在一起形成一个游戏:
玩家使用配对服务器通过创建、加入、自动配对和邀请来形成游戏。服务器会选择一个人做主机,其他人P2P连接主机玩家。STUN是一个帮助玩家建立P2P的牵引服务器,而且由于P2P连接性只有75%左右,实在连接不上的玩家会通过Forward来转发。
大量的连战,体育竞技游戏都采用类似的结构。P2P有网状模型(所有玩家相互连接)和星形模型(所有玩家连接到一个主玩家)。复杂的博弈状态在网状模式下很难保持一致,所以星型P2P模式经受住了历史的考验。除了游戏数据,具备语音功能的Battle.net系统还会将每个人的语音数据发送到玩家的机器上,通过混音、重编码、重编码的方式返回给所有用户。
战斗。网游主要是竞技、体育、动作等类型的游戏。慢节奏的RPG(包括ARPG)有着本质的不同,激烈的游戏过程必然会带来比RPG复杂得多的同步策略。这样的同步机制往往会带来很多由客户端直接计算的游戏结果。如何才能保证今天比赛结果的公平性?
主要方法是投票,所有客户端会独立计算,然后传给服务器。如果结果相同,记录将被更新;如果结果不一致,将通过投票决定最终结果。同时,记录游戏的所有输入,如果可能的话,再找一个空闲的游戏客户端,查看整个游戏是否是结果。并记录经常涉嫌作弊的用户,供运营商封号时参考。
类型7:休闲游戏服务器
休闲游戏类似于战斗。net服务器,而且都是区域架构。不同的是有房间服务器和特定的游戏服务器。游戏主体不再由玩家P2P玩,而是连接到专门的游戏服务器进行处理:
比如战斗。Net,用户数据不能像分区RPG一样一次性加载到内存中,然后直接在内存中修改。在地域架构下,为了应对一个用户同时玩几个游戏,用户数据需要区分基础数据和不同的游戏数据,而游戏数据需要区分积分数据和文档数据。win、flat、negative等整数可以直接提交进行增量修改,而比较常见的文档数据需要提供读写令牌,只有一个写令牌,很多读令牌。在两台电脑上同时玩同一个账号的同一个游戏,第一个游戏获得一个写令牌,可以操作任何用户数据。之后游戏不仅可以提交负积分的增量变化,还可以采用只读的方式保证游戏可以运行,但是会提示用户游戏数据被锁定。
类型8:现代动作网游
从早期的韩国动作游戏开始,传统的Battle.net动作游戏和RPG游戏开始尝试融合。简单动作游戏玩家容易疲劳,留存没有RPG高;单纯的RPG战斗缓慢枯燥,无法满足很多玩家激烈对抗的期望,于是两者开始融合成新一代:动作+城镇模式。玩家在镇上集合,然后几个人出去通过玩动作游戏来完成各种RPG任务。本质就是一套RPG服务器+副本服务器。因为每个副本可以将人物控制在8人以内,所以可以获得更实时的游戏体验,让玩家玩得更爽快。
说了这么多类型的游戏服务器,差不多就够了。其余类型其实也就这样。