最近几天在技术交流群里讨论到游戏服务端的一些技术细节,小说君发现有些做服务端的同学因为没有接触过游戏服务端,所以对游戏服务端产生了一些误解。因此今天的文章就从web服务端和游戏服务端的区别说起,简单介绍下游戏服务端。
首先下个定义,我们讨论的「服务端」是什么?引用一下wiki对Server的定义:
In computing, a server is a computer program or a device that provides functionality for other programs or devices, called "clients". This architecture is called the client–server model, and a single overall computation is distributed across multiple processes or devices.
说得比较笼统,client-server模型,分布式提供服务等等,这点对于服务端程序员来说就是日常工作。
然后是wiki对Server的分类:
Typical servers are database servers, file servers, mail servers, print servers, web servers, game servers, and application servers.
其他几种Server我们都比较清楚了,跟unix差不多同时诞生。另外三种,则是程序员日常开发所接触的Server类型游戏图片,为了确定下文章接下来的讨论范围,我们不妨先给三种Server划定下范围。
Web Server,典型例子是淘宝。
特点:所有流程均由客户端发起,客户端发个请求,服务端返回个响应。而且,根据客户端访问的服务不同,客户端可以向不同的具体服务端节点发起请求。
Game Server,典型例子是魔兽世界。
特点:有一个肉眼能感觉到的连接握手的过程,建立连接后游戏开发服务器 协议,流程有可能是服务端发起(比如给你展示周边玩家),也有可能是客户端发起(比如你移动了一下)。
同时,如果你手边有抓包工具,可以看到,如果你选中了某个玩家,在该玩家的头像框消失之前,一直是同一个场景服务器在跟你通信。
Application Server,典型例子是QQ。
特点:介于Web Server和Game Server之间,看着像一个web服务器,但是又有游戏服务器的特点。
接下来正文的对比部分,Web Server就特指第一类,Game Server就特指第二类,App Server不再拿来参与对比。
对比之前,小说君先概述下服务端在client-server模型中的扮演角色。
服务端,在物理上表现为一或多台主机,在逻辑上向客户端暴露一组host:port二元组,接受客户端连接,为每个客户端连接维持连接会话(Session)。客户端与服务端借助连接会话传递消息,消息按一定的协议序列化与反序列化,客户端与服务端的逻辑模块由消息的内容驱动运转。
不论是Web Server,还是Game Server,在运作流程上都大体相同。而在流程中的细节上,有共同点,也有不同点。下面就分开说道说道。
首先是共同点。
共同点1:都是为客户端提供多种服务。
比如淘宝既提供搜索服务,又提供商品页查询服务。
魔兽世界既提供登录服务,又提供让你在场景里战斗、走跑跳的服务。
共同点2:都需要连接会话的概念。
会话是建立在连接之上的概念,其实本质上是服务端为某个特定客户端维持的数据结构与状态信息。
游戏自不必说,玩家登录之后,服务端需要有一个专门的全局服务器维护玩家状态与玩家的部分较热的存档信息游戏运营,玩家进入到某个场景,场景服务器还需要专门维护一份玩家的场景相关的状态信息。
而对于Web Server,连接会话同样存在,最直观的理解是淘宝登录之后服务端会为客户端保持一个会话上下文。
共同点3:服务端的每台物理机服务多个客户端。
这是服务器的诞生基础,发展到现在,已经没人再讨论是异步IO还是多路复用,现在成熟的解决方案已经不存在孰优孰劣的问题,完全是哪个网络库用的顺手就默认接受这个网络库底层的IO模型。
共同点4:都具有分布式结构。
架构的演化总是相似的,Web服务端与游戏服务端在发展过程中相互学习相互演进,目前形成的主流架构基本都了解至少应该将专门管连接的、专门管逻辑、专门管存储的做一定程度的物理隔绝。
可以像skynet一样,利用luaState做隔绝;可以像Erlang一样游戏开发服务器 协议,利用actor做隔绝;也可以最简单的,按进程隔绝。只要能保证其中之一挂掉不会产生连锁反应导致其他都挂掉就可以了。
共同点5:开发语言。
实际上也是近几年手游开发火起来之后开发语言才趋于统一的。web开发一直是百家争鸣,而游戏开发在以前是C++一家独大。
但是现在,客户端的逻辑层已经基本见不到C++的影子了,服务端纯用C++的也越来越少了。lua、python、java、C#、Erlang、js甚至ruby的工业级游戏服务端框架都有出现,web服务端和游戏服务端的开发语言已经趋同。
然后是不同点。
不同点1:会话的存在形式。
这一点是web服务端与游戏服务端最本质的区别。
web服务端的客户端与客户端之间交互非常有限,因此,服务端可以将会话保存在外部存储服务,比如一些缓存中间件、文件系统中间件,然后等再用到的时候再拿出来就可以了。
而游戏服务端的客户端与客户端之间交互非常频繁,比如,同场景的其他玩家会不停做不规律移动,战斗时一个技能就会对复数个玩家造成影响。
这时如果将会话状态保存在外部,会造成频繁的状态存取,严重影响服务器吞吐量。因此对于游戏服务端来说,会话通常保存在进程内。
不同点2:交互频率与数据流向。
web服务端的频率低,而且数据的流动是由客户端驱动的,流向通常是客户端请求了,服务端才返回。
而游戏服务端的频率高,数据的流动一部分由客户端驱动,一部分由服务端驱动。流向除了服务端对客户端请求的响应,还有服务端的主动推送。
不同点3:通信协议基础。
通信协议基础就是客户端和服务端通信的协议所依赖的协议基础。
按常识理解的话,web通信的基础在应用层是http协议。由于小说君对web开发并不太熟悉,所以不太清楚目前私有协议在web开发中的应用,但是想必即使是私有协议,也一定是套在http协议的某些字段里面的,这跟游戏的客户端服务端通信有本质区别。
游戏通常会实现私有的序列化协议,可以简单理解为应用层定义协议包结构平铺成字节流或者是串行序列化字节流。如果要支持一定程度的协议版本兼容,会用二进制json或者protobuf来实现协议序列化,但是通信协议本身是没有「基础」可言的,纯私有化协议,不具普适性,也没有必要定义成一种专门的协议。
不同点4:对第三方组件的依赖程度。
web服务端发展速度快,从业者多,同技术栈的从业者交流更深入更频繁。因此,web服务端出现、并且还会出现越来越多的第三方独立组件。web服务端的从业者甚至只需要在自己的技术栈不同层次上选择不同的第三方组件,黏合起来,就能形成一整套的解决方案,非常方便。
游戏服务端正相反,比较封闭,基本上每个项目组要么是从头到尾重写,要么是从其他项目组拿来整套技术栈直接改改。基本不存在第三方独立组件的情况,在技术开放氛围好些的公司还好,毕竟大家可以复用同一套框架,否则的话,公司内的框架多种多样,各种造轮子出来的,各种空降团队从原来公司带过来的,技术无法复用,团队成员流动更是一大难题。