| 本文从当前游戏市场发展的背景出发,实现了一套用于跨服通信的高吞吐的RPC通信框架,先后体验了被动拉取模式带来的坑,以及主动推送模式带来的便利。并且,对该架构设计在消息组播,通信量,消息序列化/反序列化等进行了多方面机制的分析及深度优化。 虽然游戏市场竞争激烈,产品格局变动较大,但游戏产业一直处于稳步增长阶段,无论是在端游,页游,手游还是已经初露端倪的HTML5游戏。可以预见,游戏类型中,MMOARPG游戏仍然会是引领市场的主流趋势,贡献着大部分流水,市场上也仍然在不断涌现精品。研发团队对MMO游戏的探索从来未间断过,从付费模式的改变,到题材多元化,次时代的视觉效果,更成熟的玩法及数值体系,本文主要针对跨服玩法上的探索和实现做一些思考和分析。 根据2016年《中国游戏产业报告》数据显示,随着游戏人口红利逐渐消失,获取用户的成本居高不下,几年来至少翻了十倍以上,目前平均导量成本页游为10~15元/人,手游在15~20元/人,其中IOS上成本30~50元/人,“洗”用户模式的效果正在变得微弱,用户流失严重。让我们先来看看滚服玩法的局限性,滚服洗量模式下存在着如下的弊端: ![]() 在上述背景下,一款长留存,低流失的精品游戏就成了平台方,渠道商,研发方追捧的目标,设想一下,如果让所有服务器玩家通过“跨域体系”实现自由畅通交互,在此基础上,玩家可以体验到前所未有的“国战系统”——7×24小时昼夜不停服的国家战争,随时开战;突破单地图承载容量极限的国战对决,带来真正万人国战的刺激体验,形成全区玩家能够互动的游戏社交环境。依托平台运营来打造一款真正意义上摆脱传统游戏运营模式的全新产品,为平台吸纳足够的市场份额,大幅降低流失率。 我们的蓝图是开创“1=1000” 模式,让所有玩家,身处一个服务器却如同同时存在于所有服务器,这种打破服务器屏障的设定,杜绝了游戏出现“被迫滚服”现象出现,玩家不用再担心鬼服人烟稀少,不用担心交易所一无所有,所有的数据共享,让玩家轻松Hold住全世界。 ![]() 项目组当时面临的现状是游戏各种档期计划、宣传推广安排都已经就绪,两个月后该独代项目要在腾讯平台按时上线,开发不能因引入跨服机制而导致所有完成度100%的功能都要去分别去增加跨服的支持,而技术人员在跨服功能开发这块经验的积累上也不充分。 技术小组分析了时下项目的现状,跨服业务需求及现有的框架结构,明确了几点原则: 为了实现跨服,游戏代码从底层架构到上层业务逻辑的代码改动成本尽量降低 业务逻辑里尽量少关心或者不用关心是否在本服或者跨服,降低开发人员的跨服功能开发复杂度,提高开发的效率,缩短开发周期。那么,我们需要解决哪些技术疑点呢? 客户端直连还是服务器转发 方案A,直连。如果直连,那么,跨服玩法时客户端要维持两个连接,在跨服里,要模拟玩家登陆,绑定session的过程,游戏服和跨服两边要同时维护两份玩家数据,如何做到数据的同步?跨服要暴露给玩家,需要有公网访问IP和端口。对客户端连接管理来说较复杂。 方案B,转发。如果通过大区服务器消息转发,那么,服务器之间做RPC通信,连接管理,消息需额外做一步跳转,性能能否满足?跨不跨服,对于客户端来说透明,跨服隐藏在大区之后,更加安全,不需再浪费公网IP和端口。 综合考虑了下,采用了B方案。 1. RPC框架设计需求 那么,我们需要先准备一套高性能轻量级的RPC框架。业界有很多典型的RPC框架,比如Motan、Thrift、gRPC、Hessian、Hprose、Wildfly、Dubbo、DubboX,为什么我们还要重复造轮子呢?综合考虑了下,框架要满足以下几点业务需求: 该框架要简单、易用、支持高并发的跨服请求; 根据现有的游戏服务器框架,会有很多定制化的场景; 通过NIO TCP长连接获取服务,但无需跨语言的需求; 支持同步请求,异步请求,异步回调CallBack; 要有服务发现的功能,要有Failfast能力; 具备负载均衡,分组等路由策略; 基于有以上的诉求,结合团队以前的开发经验,于是就决定自主研发。我们选用的技术栈有 Netty、Apache Commons Pool、[color=rgb(68, 68, 68) !important]Redis等。 框架分为服务提供方(RPC Server)、服务调用方(RPC Client)、注册中心(Registry)三个角色,基于Redis为服务注册中心,通过其Pub/Sub实现服务动态的注册和发现。Server 端会在服务初始化时向Registry 注册声明所提供的服务;Client 向 Registry 订阅到具体提供服务的 Server 列表,根据需要与相关的 Server 建立连接,进行 RPC 服务调用。同时,Client 通过 Registry 感知 Server 的状态变更。三者的交互关系如图: ![]() 通过Global server提供路由策略,负载均衡策略,分组策略。具备 Failfast 能力,保障RPC服务一定程度的高可用。 2. RPC请求的有序性 连接池在设计过程中,比较重要的是要考虑请求的顺序性,也就是先请求的先完成。如果玩家的跨服请求通过不同的RPC连接并发执行,就有可能单个玩家请求因错序而导致逻辑矛盾,比如玩家移动,见图2: ![]() 玩家移动是很频繁的,如果A请求让玩家从位置1移动到位置2,B请求从位置2移动到位置3,有可能B请求先被跨服接收处理,这就会产生逻辑问题。 那么,如何做到请求的有序性呢?其本质是让同一份数据的访问能串行化,方法就是让同一个玩家的跨服请求通过同一条RPC连接执行,加上逻辑上的有效性验证,如图3所示: ![]() 3. 同步RPC实现细节 限于篇幅,这里只讲同步请求的RPC连接池实现。同步请求的时序图如图所示: ![]() 上图为进入跨服战场的一次同步请求,场景切换控制器StageControllAction发起进入跨服战场的请求applyChangeByBattlefield(),场景管理器StageControllManager首先要调用登录跨服的RPC请求GameRpcClient.loginCrossServer(LoginCrossServerReq),跨服RPC请求的工作流是这样的: ![]() 该请求第一步先从连接池里获取一个连接RpcClient rpcClient = rpcClientPool.getResource(roleId),然后发起一个同步请求RpcClient.sendWithReturn(),等待直到结果返回,然后把资源归还连接池。 我们重点来看看sendWithReturn代码实现: ![]() ![]() 测试场景为分别在连接数在1,8,并发数1,8,数据大小在22byte,94byte,2504byte情况下,做测试,消息同步传输,原样返回,以下是针对同步请求压力测试的结果(取均值): ![]() |


雷达卡



































京公网安备 11010802022788号







