腾讯游戏服务器同步经典案例回顾:《天天酷跑》PVP同步方案及架构分析
伴随着手游浪潮,实时PK已成为很多游戏的标配。但由于网络延迟的存在,玩家本地状态、在服务器的状态和在其他玩家机器上的状态,三者不可能一致。同步问题本质上是一致性问题,游戏中不同玩家看到的状态需要是一致的。假如游戏中A、B两个玩家移动,并同时向对方发出射击的指令。如果没有合适的同步机制,那么可能出现的情况有:A屏幕显示B已经被杀死,B屏幕显示A已经被杀死。因此需要有同步机制来解决由于网络延迟和渲染延迟等造成的玩家状态不一致问题,给玩家更好的游戏体验。同步机制有许多种,根据游戏类型、技术条件甚至时代背景的不同,选择的同步机制也会不同。同步机制的选择,还可能涉及服务器架构的调整。
网络游戏同步,常用的两种方案是帧同步和状态同步。
帧同步是同步玩家的指令,服务器负责转发客户端的操作,每个客户端以固定的逻辑帧执行所有客户端的操作指令,通过在严格一致的时间轴上执行同样的命令序列获得同样的结果。
状态同步跟帧同步的最大区别是服务器不在进行切逻辑帧,而是同步玩家状态信息,比如位置、属性、跟玩法相关的数据。通常主逻辑在服务器运行,客户端只是作为一个显示。采用状态同步的游戏有CFM、LOL等。
帧同步的网络流量较小,但防外挂、断线重连的难度比较大。状态同步中服务器有所有玩家的状态,安全性较高,游戏运营更可控。是否选择状态同步,需要看同步的实体数量。在大场景中,同步的单位比较多时,往往会放弃状态同步。比如星际争霸中玩家可操作的实体多达上百个,如采用状态同步的话网络流量将非常大。
《天天酷跑》(以下简称“酷跑”)是一款横版跑酷游戏,先后推出了多种PVP玩法,包括世界对战、多人战、团队赛等等。下面介绍游戏几种典型pvp玩法在服务器端的同步方案和对应的架构调整。
一、世界对战
为了增加玩家之间的互动,酷跑上线3个月后,规划了世界对战的玩法。具体玩法是:参与游戏的玩家两两匹配进行对战,最后根据比赛分数、距离等决定胜负。
酷跑作为一个全民游戏,必须考虑玩家的网络状况。下图是酷跑世界对战推出时移动游戏接入网络的统计。2G/3G网络比例很高,网络质量不稳定,且都是按照流量收费。游戏过程中大规模的数据同步在当时还是不适合的。同时早期移动游戏的人力投入都比较小,版本迭代节奏也很快。
因此世界对战玩法提出时,酷跑选择了简单的同步方案——通过TCaplus数据库(腾讯自研NOSQL数据库)来实现玩家之间的数据同步。世界对战属于异步PVP,为了节省流量,玩家在游戏过程中没有交互,只在重要节点同步。包括匹配成功、开局、结算、领奖,同步数据量小、协议交互频率低。同时TCaplus数据库具有很高的读写性能,并且有专业的运维团队维护,使得开发团队的工作量相对较小,又能满足世界对战的同步需求。
服务器设计了TCaplus数据库表TB_PVPMATCH,用于记录玩家世界对战数据。每次参加世界对战会在TB_PVPMATCH表中增加一条记录,记录中定义了一个status字段,用于记录玩家找到对手、确认对手、付入场费、上报分数、领奖状态的变迁。
玩家匹配成功后会新增一条记录到TB_PVPMATCH表中,status状态标记为初始化。匹配成功后,客户端会固定每秒1次的频率发送对战状态协议到服务器,直到双方都扣入场费后开局。服务器收到拉取对战状态协议后,从TCaplus中获取TB_PVPMATCH表对应自己和对手的记录,根据双方的状态更新自己的记录并写入TCaplus和发送客户端。当客户端拉取的响应消息中标记入场费已扣除则开局,开始游戏。
游戏结束后,再次通过对战状态协议通知游戏已结束,服务器获取本局游戏数据并更新到TB_PVPMATCH表对应的记录中。如果对方已结束游戏,则可以直接结算。如果对方还在游戏中,玩家可以选择在结算界面等待对方或直接退出,下次再查看比赛结果。在结算的时候,或拉取对战双方在TB_PVPMATCH表中的记录,根据双方数据来判定胜负。
世界对战上线时,服务器架构比较简单。全局服务只有匹配服务,涉及的异步流程很少,其它逻辑在Gamesvr上处理即可。
二、多人战
2014年底酷跑推出了实时同屏多人对战模式的玩法。玩家要努力战胜对手,将速度最大化,用最短的时间跑完全程。多人战分经典战和道具战两种,经典战比拼速度,道具战通过道具增加或减少各种效果,玩家可以利用各种功能各异的道具保护自己,干扰对手。
多人战属于同步PVP,4个玩家匹配到一起后即可开局。由于对战中玩家数不多,同时服务器需要做一些逻辑,这里选用了状态同步的同步方案。游戏过程中玩家上报自己的操作、位置和状态给服务器,服务器做一些逻辑处理,再把该玩家上报的包广播给其他玩家,其他玩家收到包后,知道该玩家的状态,做相应的逻辑。游戏过程中,根据游戏场景,动态调节同步频率,达到节省同步包量,降低服务器负载的目的。玩家在游戏中平均每秒1次左右的同步。
版本灰度上线过程中,发现多人战服务所在机器的通讯进程进程TBusCPU占用很高。多人战服务是用来创建房间、同步包转发、对战结算的服务。需要与所有gamesvr和TConnd建立通道,单机Tbus通道达到上千个。
TBusd占CPU高,但网络流量又不大。最后发现Tbus通道达到一定数目,性能会急剧下降。Tbusd需要轮询所有通道进行收发包,通道过多时导致大量CPU空转。考虑到后续全局服务会越来越多,通道数会进一步膨胀,Tbus占用的内存、CPU会进一步上升。需要降低通道数,引入中转服务,可以使通道数收敛,同时前后端关系也解耦。
因此对架构进行了调整,逻辑层由2层变成3层,中间加了一个转发层,gamesvr与全局服务,全局服务之间不再直接通信,而是通过转发层中转,这样Tbus通道数得到了收敛,服务器之间的通信关系由网状变成了树状。
三、团队战
2017年初,为了加强玩家间的互动,设计了局内交互更频繁的团队战模式,强化玩家间配合,增加玩家对游戏的粘性。团队战是3V3对战,在比赛结束时,计算队友获得的总分,得到总分较高的团队获胜。玩家在挑战时,队友之间相互有联系。比赛中每过一段时间玩家就会进入到一个小游戏,如在极速前进中需要配合完成吃金币和空心银币的任务、在进击模式中需共同完成砍怪、在天空之城中队友之间分配合理的飞行线路可以获得较高的分数、队友通过巅峰挑战会落下高分流星雨作用于团队所有的队员等。
这是一个强交互的需求,队友间需要共享妖怪总血量、关卡中出现的金币等,给妖怪最后一击的只能是一个玩家、所有队友吃到的金币总和不能超过金币总量等。最初要求每秒15帧的数据同步,同时服务器需要做逻辑,因此团队战选择了状态同步的方案。服务器采取了简单的处理原则,先来先处理,处理时加上校验即可。同时针对不同关卡,动态调整同步频率。
团队战需要有团战服务来同步玩家数据,原有架构上下行包需要在客户端、Gamesvr和团战服务之间流转,团队战中高频的同步请求包对流量和CPU都会带来挑战。因此对架构进行了调整,将同步包独立出来,游戏过程中客户端直接与团战服务通讯。
这是目前的游戏架构,增加了客户端与团战服务直接通讯的能力。3v3匹配成功后,通知团战服务建立房间,同时下发客户端房间所在团战服务的机器ip和端口(映射到tgw的vip和端口),客户端再通过下发的地址信息连接团战服务。游戏过程中,客户端直接向团战服务发同步包,团战服务转发给队伍中的其他玩家。
总体来说,酷跑定位为轻度游戏,PVP中涉及的同步方案比较简单。在不同时期,根据游戏玩法、网络状况等选择了不同的同步机制和服务器架构,满足了设计需求。