有些对游戏服务器的介绍可能会说,游戏服务器是一个需要长期运行的程序,然后怎么怎么样。我个人认为Web服务器一样的需要长期运行,也需要响应不定点不定时来自用户的请求。两者从宏观上来看其实没有本质的区别。同时Web服务器也会对于稳定性和性能有要求,游戏服一般分为大小服,我们这里都按照小服举例子。
1 状态
首先要提到的就是状态。可能你会听说过一个概念,游戏服务器是有状态的,而Web服务器是无状态的。什么意思呢?Web服务器的数据流大多直接会到数据库中。而游戏服务器的数据流首先会到内存中,然后定期的写入数据库(落地)。
换句话说,游戏服务器本身的数据与数据库中的数据在运行期间会存在一个数据不一致的窗口。如果此时游戏服务器宕机了,那么就会造成数据首先到的内存数据与数据库存的数据不一致。
而Web服务器则不会有这样的问题,Web所有的数据状态都会落地,而且可以针对操作加上事务,不用担心因为操作失败而引入脏数据。正因为有了状态的约束,游戏服务器就会很慎重的使用内存、CPU。以求在资源有限的情况下,最大化的提高的承载量,并且降低服务延迟。当然,Web服务器会为了降低某个接口的响应时间而去做对应的优化。
2 扩容
在Web服务器中,如果你不能评估一个服务所面临的压力,又不想因为瞬时的热点访问导致服务直接不可用的话,完全可以设置成自动扩容,因为每个服务只是单纯的接收请求,然后处理请求、返回结果,不会将数据保存在服务器的内存中。要有数据存到内存,那也是在Redis中。而Redis数据丢失对数据的一致性基本没有影响。
但是在游戏服务器这边很难做到像Web那样灵活。首先,数据的流向不是数据库,而是内存。
举个很简单的例子,玩家的主城被攻打着火了,如果有了自动扩容,很有可能在落地的窗口内,玩家再请求一次,请求到了另一个实例。主城又没有着火了。因为数据都会先存在内存中。
再举一个例子,玩家氪金买了一个礼包。然后退出游戏,落地窗口内再次上线没了。这就不是单纯的数据问题了,玩家这是花了真金白银买的道具,突然就没了,一两个还好处理,如果多个玩家都出现这样的问题,那这就属于严重的线上事故了。修复数据的工作量十分的大。
所以,对于一个游戏服务器,所能使用的内存和CPU的资源是非常有限的,不像Web服务器可以不用花很大的代价做到横向扩展。这也就是为什么游戏服务器会十分十分的注重代码的性能以及稳定性。
3 稳定
就像上面说的例子,如果游戏服务器运行中出了BUG,导致服务直接不可用,或者说通过这个BUG刷到了大量的道具,将是一个非常严重的线上事故。
而对于Web服务器来说,如果是管理系统之类的,有可能会有脏数据值得一提的是,脏数据对于Web来说,排查起来也是一件很头疼的事情。如果没有脏数据,只是服务暂且不可用,而且如果用的是微服务架构,重启服务的代价是相对来说比较小的,只有正在重启的服务的业务是不可用的,其余的部分则可以正常的访问。
而对于游戏服务器来说,服务器重启影响的是全服的玩家。玩家在停服期间,甚至连游戏都进不了,特别的影响玩家体验。而且,如果停服之前服务器的数据落地出现了问题,服务重启之后会将数据从数据库load到内存中,此时同样会造成数据不一致的问题。
4 性能
从我的经验来看,在做Web服务器的时候,没有为了减少GC的压力,为了少占用内存去做过多的优化。当然这是因为项目本身的体量不大,如果QPS很高的话,Web服务器同样很需要注重性能,只不过游戏服务器需要一直特别注意这个方面。
不过在Web,如果访问量很大的话导致单个服务不能扛住压力,大部分人首先想到的解决方案应该就是搞多个实例,毕竟可以做到很轻松的横向扩展。
在游戏服务器里,会把服务器的资源看的相当的宝贵。例如,能不落地的字段就绝对不要落地,某个字段的值可以通过已知的条件算出来的,就尽量不要定义在代码里。不过这也要看具体情况权衡运算量和调用的频率。因为上线之后,如果遇到了数据不一致,维护的数据越少,修复数据的难度就越小。
5 严谨
这一点上来说,我认为是两者都很关注的一个重点。只不过,在游戏服务器的某些情况中,如果服务器抛出异常或者panic。其造成的后果会被游戏特殊的环境放大。
例如,召回你的在外部队失败了,那么部队就会一直在外面且不可用。这跟在浏览器中点一个按钮没有反应比起来,影响相对较小。而且使用微服务架构,在修复问题之后可以以很低的成本来重启对应的服务,而游戏服务器中还要修复一次数据。
再举一个很极端的例子,点击商店,玩家要准备氪金了。但是却发现进不了商店,也可能不能获取商品列表。这些会直接影响到游戏的体验,甚至收入。
而对于Web来说,服务器的稳定性同样很重要。不然根据业务的不同,造成后果的严重性也有可能不同。影响了用户体验,就会直接影响到产品的口碑。
6 数据传输格式
熟悉Web的都知道,数据传输格式是JSON。而在游戏服务器中是Protobuf,是由Google开发的数据传输格式,与JSON类似。Protobuf是二进制的,二进制数据量会比JSON更小一点。而且,如果传输的字段是空值,就不会被传输。而JSON如果是空值,一样的也会被传输。
无论是在什么样的环境中,举个例子,Node.js和Java中,Protobuf的性能表现都比JSON好。在Java中,Protobuf甚至要比JSON快了接近80%。如果Java的服务之间通信有了性能瓶颈, 可以考虑服务之间使用RPC来通信。
但是凡事都具有两面性。Protobuf的缺点仍然存在:
文档较少 社区与JSON的对比起来 可读性没有JSON好 4 总结
以上就是这两个月以来,总结的两者的区别。只是从大体上做了一个对比,并没有具体深入细节。细节的话有可能会在以后单独的来介绍。