五星宏辉游戏项目小结
web服务端和game服务端的区别
Server的定义和分类
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.
**分类:Typical servers are **
- Database Server
- File Server
- Mail Server
- Print Server
- Web Server
- Game Server
- Application Server
异同
Web Server,典型例子是淘宝。
特点:
- 所有流程均由客户端发起,客户端发个请求,服务端返回个响应——请求响应模式
- 根据客户端访问的服务不同,客户端可以向不同的具体服务端节点发起请求
Game Server,典型例子是魔兽世界。
特点:
- 有一个肉眼能感觉到的连接握手的过程,建立连接后,流程有可能是服务端发起(比如给你展示周边玩家),也有可能是客户端发起(比如你移动了一下)——交互性
- 同时,如果你手边有抓包工具,可以看到,如果你选中了某个玩家,在该玩家的头像框消失之前,一直是同一个场景服务器在跟你通信。——常连接
Application Server,典型例子是QQ。
特点:
- 介于Web Server和Game Server之间,看着像一个web服务器,但是又有游戏服务器的特点。
服务端在client-server模型中的扮演角色:
服务端,在物理上表现为一或多台主机,在逻辑上向客户端暴露一组host:port二元组,接受客户端连接,为每个客户端连接维持连接会话(Session)。客户端与服务端借助连接会话传递消息,消息按一定的协议序列化与反序列化,客户端与服务端的逻辑模块由消息的内容驱动运转。
不论是Web Server,还是Game Server,在运作流程上都大体相同。而在流程中的细节上,有共同点,也有不同点。下面就分开说道说道。
共同点:
-
都是为客户端提供多种服务
-
比如淘宝既提供搜索服务,又提供商品页查询服务。
魔兽世界既提供登录服务,又提供让你在场景里战斗、走跑跳的服务。
-
-
都需要连接会话概念
-
会话是建立在连接之上的概念,其实本质上是服务端为某个特定客户端维持的数据结构与状态信息。
Game Server自不必说,玩家登录之后,服务端需要有一个专门的全局服务器维护玩家状态与玩家的部分较热的存档信息,玩家进入到某个场景,场景服务器还需要专门维护一份玩家的场景相关的状态信息。
Web Server,连接会话同样存在,最直观的理解是淘宝登录之后服务端会为客户端保持一个会话上下文。
-
-
服务端的每台物理机服务多个客户端
- 这是服务器的诞生基础,发展到现在,已经没人再讨论是异步IO还是多路复用,现在成熟的解决方案已经不存在孰优孰劣的问题,完全是哪个网络库用的顺手就默认接受这个网络库底层的IO模型。
-
都具有分布式结构
-
架构的演化总是相似的,Web服务端与游戏服务端在发展过程中相互学习相互演进,目前形成的主流架构基本都至少应该将专门管连接的、专门管逻辑、专门管存储的做一定程度的物理隔绝。
可以像skynet一样,利用luaState做隔绝;可以像Erlang一样,利用actor做隔绝;也可以最简单的,按进程隔绝。只要能保证其中之一挂掉不会产生连锁反应导致其他都挂掉就可以了。
-
-
开发语言
-
实际上也是近几年手游开发火起来之后开发语言才趋于统一的。web开发一直是百家争鸣,而游戏开发在以前是C++一家独大。
但是现在,客户端的逻辑层已经基本见不到C++的影子了,服务端纯用C++的也越来越少了。lua、python、java、C#、Erlang、js甚至ruby的工业级游戏服务端框架都有出现,web服务端和游戏服务端的开发语言已经趋同。
-
不同点:
-
会话的存在形式(本质区别)
-
这一点是web服务端与游戏服务端最本质的区别
web服务端的客户端与客户端之间交互非常有限,因此,服务端可以将会话状态保存在外部存储服务,比如一些缓存中间件、文件系统中间件,然后等再用到的时候再拿出来就可以了。
而游戏服务端的客户端与客户端之间交互非常频繁,比如,同场景的其他玩家会不停做不规律移动,战斗时一个技能就会对复数个玩家造成影响。
这时如果将会话状态保存在外部,会造成频繁的状态存取,严重影响服务器吞吐量。因此对于游戏服务端来说,会话通常保存在进程内。
-
-
交互频率与数据流向
-
Web Server的频率低,而且数据的流动是由客户端驱动的,流向通常是客户端请求了,服务端才返回。
Game Server的频率高,数据的流动一部分由客户端驱动,一部分由服务端驱动。流向除了服务端对客户端请求的响应,还有服务端的主动推送。
-
-
通信协议基础
-
通信协议基础就是客户端和服务端通信的协议所依赖的协议基础。
按常识理解的话,web通信的基础在应用层是http协议。由于小说君对web开发并不太熟悉,所以不太清楚目前私有协议在web开发中的应用,但是想必即使是私有协议,也一定是套在http协议的某些字段里面的,这跟游戏的客户端服务端通信有本质区别。
游戏通常会实现私有的序列化协议,可以简单理解为应用层定义协议包结构平铺成字节流或者是串行序列化字节流。如果要支持一定程度的协议版本兼容,会用二进制json或者protobuf来实现协议序列化,但是通信协议本身是没有「基础」可言的,纯私有化协议,不具普适性,也没有必要定义成一种专门的协议。
-
-
对第三方组件的依赖程度
-
web服务端发展速度快,从业者多,同技术栈的从业者交流更深入更频繁。因此,web服务端出现、并且还会出现越来越多的第三方独立组件。web服务端的从业者甚至只需要在自己的技术栈不同层次上选择不同的第三方组件,黏合起来,就能形成一整套的解决方案,非常方便。
游戏服务端正相反,比较封闭,基本上每个项目组要么是从头到尾重写,要么是从其他项目组拿来整套技术栈直接改改。基本不存在第三方独立组件的情况,在技术开放氛围好些的公司还好,毕竟大家可以复用同一套框架,否则的话,公司内的框架多种多样,各种造轮子出来的,各种空降团队从原来公司带过来的,技术无法复用,团队成员流动更是一大难题。
-
Firefly框架
在游戏服务器端,往往需要处理大量的各种各样的任务,每一项任务所需的系统资源也可能不同。而这些复杂的任务只用一个单独的服务器进程是很难支撑和管理起来的。所以,游戏服务器端的开发者往往需要花费大量的时间精力在诸如服务器类型的划分,进程数量的分配,以及这些进程的维护,进程间的通讯,请求的路由等等这些底层的问题上。而Firefly完全可以完成这些重复而繁琐的工作,从而将上层的游戏开发者解放出来,把精力更多的放在游戏逻辑的实现上面。
Firefly是免费、开源、稳定、快速扩展、能“热更新”的分布式游戏服务器端框架,采用Python编写,基于Twisted框架开发。
Firefly特性
- 采用单线程多进程架构,支持自定义的分布式架构
- 方便的服务器扩展机制,可快速扩展服务器类型和数量
- 与客户端采用TCP长连接,无需考虑粘包等问题
Firefly思路
一个最基本的服务器就是一个在不停运行着的应用程序。
在分布式游戏服务器中,我们需要的服务器具有的功能有:
- 监听客户端的连接
- 监听其它服务进程的消息
- 连接其它服务进程
- 数据库连接和缓存服务
Net connect 做客户端连接
Root监听其他服务进程消息
Node连接其他服务进程,db数据库,cache缓存
是否需要监听客户端连接,是否监听其他服务进程消息等这是都是可以在config.json中进行配置。包括各个服务器的名称以及各个服务器之间的连接关系。这样就可以自定义出自己的分布式架构。
Firefly结构
从功能职责上来看,Firefly框架结构如下图所示:
- management:Firefly 是个多进程、分布式的游戏服务器。因此各游戏server(进程)的管理和扩展是firefly很重要的部分,框架通过抽象使服务器的扩展非常容易。
- Network:客户端连接通信、server进程间的通信等构成了整个游戏框架的脉络,所有游戏流程都构建在这个脉络上。与客户端的通信采用的是请求/响应式的,所有收到的客户端的请求,服务端都会给出相应的回应,服务端也能主动的推送,广播给客户端消息。这些请求是基于指令号的请求(例如定义101为登陆指令)。server进程之间的通信时采用的异步回调的方式,这样就减少了的进程间通过网络通信中的时间消耗。
- Data: 数据处理是网游的重要部分。在网游有大量的数据需要存储,需要更新,这使得数据库的读写效率成为服务器的最大的性能瓶颈。Firefly的db处理能够将数据库表中的数据缓存到memcache中并能以对象的形式进行调用相应的对象方法对数据进行操作。可以在不同的进程中通过实例化相同的名称的缓存实例,得到同步的数据。并能将缓存对象中的数据写回数据库中。
Firefly流程
- 从config.json中读取配置数据
- 根据配置中定义的服务端的架构,启动相应的服务进程。并建立节点之间的连接。有配置数据库的,实例化数据库连接池。有配置memcached的,建立memcached的连接。
- 根据配置相应的的进程启动的入口模块。
Python游戏后端架构
设计方案
- 性能卓越和高可用性
- 分布式架构(客户端到服务端所有环节避免单点问题、有效负载均衡)
- 支持高并发写(db缓存,部分模块改为批量操作,减缓DB压力)
- 游戏推送机制可靠快速,无延迟
- 分布式代理,故障发生时自动切换
- 游戏服务热更新
- DDos防护
- 监控运维
- 用户行为模拟(开发实现模拟大量真实用户行为机器人程序)
- 通知模块(独立语音、短信、邮件通知服务模块)
- 游戏异常监控系统(异常出现时实时通知相关人员)
- Linux上线操作脚本自动化,远程部署
- ELK体系(引入kafka、elasticsearch、kibana,记录分析游戏日志信息)
总体架构
Web服务代码架构
预警系统体系
Client端(各待预警的子项目)数据上报(只需1步):
- 在用户操作的前后调用已经封装好的日志agent上报原始操作的信息(信息格式参考后续的接口文档);
Server端(分析预警系统):
- 收到client发送过来的请求后,首先进行鉴权验证;
- 验证通过后,根据类型(异常错误类和信息记录类)分类存储到不同的消息队列;
异常错误类:上报过来的信息一般为需要进行预警通知,错误的验证逻辑由上报者自己内部判断;
信息记录类:上报者只是上报原始记录信息,具体是否触发预警的逻辑验证由预警后台程序验证;
- 不同类型的worker持续从对应的消息队列中获取最新消息,产生分析结果;
- 根据分析结果决定是否调用Notice服务通知产品开发、运营人员;
周期性任务:
该部分主要指预警后台周期性(天/小时/分钟)执行各种统计分析任务,对可能出现异常的分析结果进行预警;某种程度上可以很好的起到数据埋点实时预警的第二道保障作用;
预警系统主体表结构设计: