【总结】服务器模式接口设计总结

1. 缓存数据是维护在服务器还是客户端?

以我游为例,因为我游有三个服务器程序,在设计接口的时候有不同的风格。有的喜欢横向扩展接口,有的喜欢纵向扩展接口。我个人之前是为了开发效率和减少客户端理解成本,一般第一时间去找到一个已存在的最接近的功能,然后copy一下整个流程做一下微调。这样的弊端是可能会复制了屎,让屎越来越多。其实设计接口时还是需要细细思考的。

请求-响应模式 和 通知模式

一个具体功能的数据维护无非就是这两种模式,请求-响应模式比较容易理解,客户端基本不做缓存,要的时候就去直接请求,玩家的显示数据由即时渲染。

请求-响应模式一般由以下接口维护(伪代码):

FuncQuery();   // 请求数据
FuncQueryRet();   // 请求数据返回

FuncOpr(eOprType);  // 其他杂项处理逻辑
FuncOprRet(eOprType);  // 其他杂项处理逻辑返回(仅返回结果状态)

客户端每次打开界面都去请求一次,所以避免了初始化数据失败的情况。即便客户端有初始化的需求(比如登录或者从单局返回时,需要所有的任务完成信息来判断主界面上的任务icon上是否要显示红点)也可以让客户端自由选择请求的时机。

当然这样设计的功能缺点也是显而易见的,就是耗流量。通知模式相比之下就相对节流的多。


通知模式一般由以下接口维护(伪代码):

FuncInit();   // 初始化数据通知(array)
FuncUpdateRet();  // 更新返回通知
FuncDelRet();  // 删除返回通知


FuncOpr(eOprType);  // 杂项处理逻辑
FuncNotice(eOprType);  // 文本通知(配合update和del处理)

此类功能数据初始化时,一般需要客户端做锁,表现也就是所谓的进度条,后续更新的时候也只发对单个元素的变更通知。

缺点也很明显:

  1. 如果网络波动导致某个通知未收到时,可能就导致界面元素异常或者逻辑错误。还有一个问题是如果初始化类数据过多会导致加载过慢

2.一般来说加载项越多bug率越高,测试过程中经常打出的pc包使游戏卡在读进度条的情况(致命bug)

  1. 接口数量占用多,一个小功能就需要占至少Init,Update,Delete三个单独的函数(因为一般要带上对应的结构体),到后面如果某两个服务器间总接口数量有限制的话人就傻了。

  2. 服务器实时性强,可以把变化即时反应到相关玩家,但是同时要考虑到的情况会变得很多很多,极容易遗漏情况。

2. 全量加载还是按需加载?

以我游为例,全量加载的数据典型的是军团(相当于帮派、公会),因为数据少,逻辑简单,有玩家请求过来就直写数据库。因为军团但是单独的一个Server所以不太容易引起其他bug,server宕掉了一般军团功能就直接挂掉,所以不太会引起其他问题。因为没有缓存,所以也不会导致数据错乱。反观如果是关系型的数据,按需加载可能一次查询里,会走很多次SQL,然后各种回调,一来请求速度其实会慢(可见的逐步渲染),二来服务器压力也大,但这其实和架构的缓存设计也有一定的关系。

(题外话:梦三国把登录作为缓存按需加载的凭据,登录队列满或者服务重启作为玩家指针移除的依据,我刚开始也觉得很奇怪。因为这样查询离线玩家的时候就没法把结果缓存起来(没有玩家实体没发存),因此msg就直接禁止掉了很多离线查询的东西,比如战绩之类的,这在别的游戏中是很奇怪的事情。在msg之前,我们作为一个普通的游戏玩家,并没有觉得其他玩家在线和离线有什么区别。现在为了服务器减压不让查,离线的玩家就和消失了一样,很膈应。)

实际上大部分的玩家数据都是按需加载的,包括好友关系,这个就需要用到一些缓存的处理方式,我游里对每一个好友实体都有一个引用计数,比如我是全服登录的第一个玩家,那我的好友实体被加载出来以后都有一个+1的引用。当好友不在引用的时候就可以释放掉。所以好友的sql表对应的c++结构可以映射出两张表:一张表示自己,一张表示其他好友,分别用在线引用和计数引用,如果有好友列表显示自己的需求,也可以把自己也放到其他好友里去。

3. 实时推送还是定时查询?

《代码大全》有一段是这么说的,确定你的项目的数据实时性,比如用户不希望看到15秒之外的数据。比如已知好友的信息有且只有打开好友界面时,一个玩家上线了,服务器需不需要实时告诉他的所有好友?(之前发生过这样的事情,因为好友上下线的排序之类的处理逻辑量其实不小。玩家在单局里被推送了好友信息,导致打团的时候有体感的卡顿,后面才定位到)。如果是打开界面再去查询,那玩家保持在界面的时候如何处理更新?这些问题都是一个一个迭代出来的,没有经历过的话很难一次想到这么多。

这是我的个人经历,之前好友可以选择自己头顶上的称号,可以选择显示天梯分,也可以显示自己的装备分,或者自己的熟练度。但是这个功能被测试抓着追责实时性,我改了称号,但是没有实时显示到好友的列表里,必须重新登录才显示。迫于排期和避免麻烦,我还是改成全时段实时通知。现在想来,一个不涉及任何利益的纯展示,且使用频率极低的功能,被用来强行套上实时功能,后悔不已,当时就应该据力争理,说服测试这个没有问题。实际上扁平化的社交实时要求其实没那么高,10s一刷已经足够满足最大多数的要求了,更不用提一些日刷或者周刷的功能。

你可能感兴趣的:(【总结】服务器模式接口设计总结)