这一年来可以明显看到一个变化:网页游戏分线从标配逐渐变成了可选,越来越多的游戏开始不分线;当初为什么要分线?现在为什么又不分线?技术上面临着什么挑战?仅仅是技术问题么?
术语解释
不同的技术实现"一条线"的概念也不尽相同,我们使用的Erlang实现,这里的一条线对应Erlang的一个VM.
为什么要分线?
可以通过比较来回答这个问题:所有玩家都在同一条线上 VS 同样数量的玩家被分配在多条线;如果所有玩家(假定1000人)都在一条线上首先同一场景的玩家数就会比较高,特别是一些游戏的热点区域比如副本入口,主城中心,传送门等等,当然同屏人数也会高;服务器端对应相关场景的广播压力,和业务逻辑的运算压力都集中在一条线上。而进行了分线之后,相当于把玩家做了分流,同一场景以及同屏的人数都会减少,一方面服务器端单条线的运算压力下降了,另一方面客户端的同屏人数也降了下来;
分线实际上帮服务器端和客户端都减轻了压力,特别是很长一段时间内Flash客户端的同屏人数一直有人数限制,多数游戏能做到100多人,不会超过200人;这实际上是木桶理论中的短板,即使服务器端能做到不分线,客户端也支撑不了那么高的同屏;(当然现在这个问题已经有了突破)
总结一下,为什么分线:分担运算压力 同屏人数限制
分线对设计的影响
分线实际上是突破技术瓶颈支撑更多玩家的方案,一旦分线自然就会带来"换线"和"跨线"的问题;所谓换线,就是玩家显示的从一条线路切换到另一条线路;不在同一条线的玩家就属于"跨线";玩家一个在1线,一个在2线,他们要交易怎么办?组队呢?聊天呢?战斗呢?即使是忽略掉交互的因素,只看一个玩家,这一个玩家上线应该选择哪条线?如果玩家在战斗,交易,挂机等状态下能够换线么?在这些状态下下线然后上线怎么处理?
本质上换线实际上是玩家数据从一个Erlang节点迁移到另一个Erlang节点,有一个销毁和重建的过程;而跨线是两个玩家的数据在不同的Erlang节点内。
一部分解决方案是来自于策划,会有一些游戏状态的互斥,比如不允许跨线交易,不允许在修炼状态换线,等等;另外一方面就要在做设计的时候充分考虑分线了:
玩家不在一条线怎么办?玩家当前能不能换线?玩家在当前这个状态换线了怎么办?玩家下线之后再上线怎么办?我这个服务是全局的应该怎么办?......
具体技术实现上,Erlang做这个有先天优势,启动多个节点,设计一个网关节点做负载均衡;做水平扩展是很容易的。
分线血泪
可以发现分线的设计需要在完成某一个功能的同时考虑到多条线的情况,会增加问题的复杂度;我不知道有多少采取分线策略的游戏曾经因为分线栽过跟头,我们就差点因为分线的一个bug把游戏经济系统搞死;事情大概经过:
某周日23点左右 运营的同事告诉我游戏内有玩家金币异常
23:30左右到公司 封号,分析日志,发现金币来源应该是玩家交易,排除服务器被攻击可能
0点左右 封锁了交易的所有协议,停服更新
1点左右 发现还有一处可能出现问题的地方 再次更新
2点 从玩家日志库抓取异常玩家的数据做分析 发现玩家金币成倍增长2 4 8 16 32 64 也就是说,金币被”复制了“,但是玩家怎么做到的?是自己和自己交易么?分析代码虽然缺少这个防护,但是交易使用的SQL也保证了他得不到收益。
3:00 ~5:00 在本地测试环境,反复模拟各种情况下的交易,答案:当时游戏存在一个分线选择的bug导致玩家可以同时登陆两条线,玩家使用两个账号反复登陆换线,然后进行交易就可以把金币通过交易复制;
6点左右补丁做好热更新第一个版本
7点左右客户端补丁也做了分发
第二天运营提交了相关账号的修复规则,一个游戏的充值有一个前提保证就是游戏内的经济系统稳定,一旦出现刷金币之类的事情搞乱了经济系统,这个游戏服也就死掉了;
为什么不分线了?
首先分线的种种限制,比如跨线不能交易等等增加了玩家操作步骤,需要玩家先选择换线;另外,分线分流玩家分散了压力也分散了人气,显得游戏不热闹;
其次在Flash同屏问题已经有了优化方案,可以看一下现在非常火爆的神魔遮天,它的同屏人数远远超出了100的限制;观察一下神魔遮天的处理,当一个区域聚集了很多人的时候,它并不是一下全部渲染出来,而是一个一个渲染出来的;还有一些客户端的优化策略,这些方案的组合结果就是同屏人数可以更多;
怎么实现?
有的不分线是通过拆分游戏的功能模块实现的,比如把场景运算放在单独的erlang节点,以功能为单位拆分成多个节点分担压力;一旦压力上去就可以通过增加对应的功能节点来缓解压力;实际上是换了一种分担压力的方式,对于客户端和玩家这些都是透明的。
我们从分线到不分线更困难一些,之前所有的逻辑都是在一个节点内完成,很难按照功能拆分游戏,那将是颠覆性的。咨询立涛,他给我们的建议是只开一条线,开启SMP,单线支撑2000~3000人应该没有问题。
Erlang SMP VM比普通Erlang VM要慢那么一点点,但是可以充分发挥多核优势 摘录一点资料:
从OTP R12B开始,如果操作系统报告有多于1个的CPU(或者核心)VM的SMP版本会自动启动,并且根据CPU或者核心的数量启动同样数量的调度器。
没有SMP支持的Erlang VM只有1个运行在主处理线程中的调度器。该调度器从运行队列(run-queue)中取出可以运行的Erlang进程以及IO任务,而且因为只有一个线程访问他们所以无须锁定任何数据。而带有SMP支持的Erlang VM可以有一个或多个调度器,每个运行在一个线程中。调度器从同一个公共运行队列中取出可运行的Erlang进程和IO任务。在SMP VM中所有的共享数据结构都会由锁进行保护,运行队列就是这样一个由锁保护的数据结构。
详情看这里:http://shiningray.cn/some-facts-about-erlang-and-smp.html
实践过程中,我们还是采取了一个折中的方案,只要玩家在一条线上不超过阈值,就只开启这一条线,客户端也没有线路选择的功能,如果超过阈值,就开启新线路,并通知客户端显示选线功能;
仅仅是技术问题么?
从分线到不分线不仅仅是技术问题,策划同样要做调整,比如游戏内的一些容易堆积玩家的区域要想办法分散压力,比如增加入口,修改NPC位置等等;还有一些数值限制也需要重新考虑,比如一个活动分线模式最多只允许30个玩家参与,不分线了这个限制就要改掉否则大部分玩家都参与不了这个活动。
单服最高在线超过3000人怎么办?首先现在游戏平台能推到这个在线的情况都很少了;其次如果超过这个值,一般都是开启新服,也就是通过运营手段而非技术手段解决这个问题。
从分线到不分线,下一站是什么?一个世界?
对于开发者,下一战又是什么?
2012-09-06 更新
坚强2002 22:38:52
有一个问题: 就现在开服导量的情况以及一机多服的开服模式 是不是可以不用考虑分线,直接在一个Erlang节点内搞定所有逻辑就OK 如果特别火爆,也不是从技术的角度去解决问题,而是开新服?
现在海贼那边在设计新项目架构 遇到这个问题
chenglitao 22:40:12
嗯,都是不分线了。峰值通过高配置机器解决。
不要考虑任何分布式,代码就是简单,便于维护,模块化就好。
坚强2002 22:42:08
而且我觉得这方面神魔做出了好的榜样 客户端同屏现在也不是问题了 束缚更少了
chenglitao 22:42:25
嗯,是的,现在都问题不大了。
坚强2002 22:42:56
ok 明白了