Node.js之网游服务器实践
此文已由作者尧飘海授权网易云社区发布。
欢迎访问网易云社区,了解更多网易技术产品运营经验。
随着Node.js的不断发展与壮大,应用范围也越来越广泛,从传统的企业应用,到互联网使用,再到云计算的发展,它的身影也是随处可见。当然,它的受欢迎程度能在短时间内得到这么快的发展,除却与其本身的事件模型及V8的性能优化等一系列特性有关之外,还和国内外很多互联网公司的攻城师的大量应用和参与到开源项目中有密切关系,如网易的游戏开发,淘宝的数据之美等等。随着HTML5应用和移动互联网平台的指数增长,越来越多的用户使用了移动平台的休闲服务,采用 Node.js 实现高性能和可扩展性的游戏服务将是一件有意义的工作。
在互联网上,目前有一些采用 Node.js 实现的开源游戏服务框架,如 Mozilla的 Browser Quest , Google的 Grits ,Chilly等。但是无一例外,这些框架不但与游戏逻辑联系紧密,而且几乎没有可扩展性和性能数据,同时也不提供任何游戏开发的管理工具,除了采用 JavaScript 编写外,很难体现出采用 Node.js 实现游戏开发的优越性。
概念
通常游戏分为角色扮演类和策略类及混合类等几种游戏类型。那么在网页游戏类型中,根据游戏的类型,开发者可能采用不同的架构实现方式,如策略类游戏可能更偏重于游戏的策略性和逻辑性,也就是考验游戏玩家的各种组合或搭配之类的游戏,对实时性的要求不会很高,在用户的可接受范围之内即可,因此也可以采用常用的Web应用开发模式来实现,而客户端采用轮询或长连接等方式来实现,这些应用模式也有很多的相关经验可以参考,因此能做到具有较好的可扩展性及伸缩性;此外,应用服务器和服务框架等也可以采用现存的技术实现,但是这只能满足对游戏实时性要求不高的场景服务,由于此类的应用方案非常成熟,在下文的讨论中,将不再详述。
角色扮演类游戏根据策划的要求可以实现各种各样的功能,如聊天,打斗,自动刷怪等各种复杂的功能,但是开发者基本可以把这些功能抽象地划分为二大类,即服务端的网络传输与逻辑运算能力,这样游戏服务的开发和实现会稍微简单些。现在,网络的实时传输基本上是采用Socket服务器来实现的,逻辑运算这个就不需要再述了,因此,游戏服务器就可以粗略的归纳为Socket的服务器综合游戏业务逻辑的实现。
与Web应用区别
从上面游戏服务的概念简单介绍中可以得知,实时游戏服务器的开发与传统的Web开发还是具有一些不同点,这些不同点着重体现在以下几个方面:
大部分的Web应用还是短连接的方式去实现,而游戏的实时性需要采用长连接的方式进行。
Web应用的场景一般是读多写少的应用,热点数据基本可以缓存;游戏服务的数据经常发生变动,如移动中的路径,打怪掉血等,缓存基本很快就失效,属于写多读少的应用场景。
广播特性,即Web应用行为上基本只需要用户与服务器交互,其他用户要实现共享他人信息的时候,会采用类似拉的方式如长轮询来实现数据交互,即使在没有数据更新的状态时也需要消耗一定的服务端资源,造成一定的浪费;游戏里面的交互方式需要实时进行,对影响三方的数据,必须采用广播的方法进行消息推送,即推的模式。
目前的Web应用开发一般采用无状态性的方式来实现,因此可以实现较好的可扩展性,很多Web服务会采用绑定会话或集中会话等方式工作,当后面的某台服务器出现宕机时,服务也可以很快的切换;但是游戏服务器和用户之间的连接是有状态的,在断开时需要进行相关的通知和数据持久化,在重连时需要进行状态恢复等手段来维护游戏世界的运行。
除以上几点不同之外,还有负载均衡的策略,服务驱动方式,系统判定,系统安全如外挂作弊等相关问题,文章中不再对他们进行对比说明。一般来讲,根据游戏的规模与需求,通常游戏服务器的实现的模式会使用如下的三种架构方式来实现。
单进程服务架构
图1 单进程服务架构
图1是目前互联网上的很多游戏服务器使用的架构,比如商用的SmartFoxServer游戏服务器,开源的有Google的 Grits, Mozilla的 Browser Quest等框架。所有的程序在同一个进程里面运行,架构简单,开发人员上手快,开发和调试非常方便又快速,成本较低,后期的维护成本可能随着游戏项目的大小而不同,但是整体应该不会太高。很明显,游戏的世界是在同一个进程里运行,在单个场景都有不少在线用户的时候,如果采用单进程的 Node.js 实现的话,每个用户的操作可能会有一定的延迟,特别是在大量用户同时做大量操作与AI运算时,如服务端寻路和自动杀怪,延迟会更加严重;同时单进程对计算机资源使用有限。因此只适合游戏的原型制作或小型的游戏开发。另外,由于游戏的状态与复杂性,也无法较好的实现游戏的可扩展性,基本只能通过添加游戏服务器的方式来实现,即所谓的开新服,而这些用户之间是无法在同一个世界里通信会话和交互的。尽管Node.js支持原生的TCP服务,使用简单;但是目前大部分网络应用中,尤其是支持HTML5的应用,socket.io由于性能较好并且使用简单,成为大部分应用采用的网络库来实现高性能websocket服务。在移动互联网应用中,由于协议较复杂与通信数据等问题,需要一定的裁减。下面示例中,就是最简单的单进程服务的原型:
var socketio =
require('socket.io');
var io =
socketio.listen(8080);
io.sockets.on('connection',function(socket){
socket.on('disconnect',function(){
//user leave
});
socket.on('message',function(msg){
if (getLoginStatus(socket)) {
game[data.action].apply(null,[socket,msg]);
} else {
game['login'].apply(null,[socket,msg]);
}
});
});
多进程服务架构
图2 多进程服务架构
在上图2中,我们可以看出,每个进程负责采用单一职责,各进程间通过一定的规则(如RPC远程过程调用)来进行通信,游戏中的各场景服务使用一个进程来服务,实现各场景游戏运行的分离。但是在开发过程中,不需要考虑每个场景具体的信息,全部采用统一的代码来实现,开发方便,通过添加适当的参数来实现较易的调试,每个进程分别运行在服务器的多核上,即可以充分使用计算机的资源,也由于职责单一,由于每个进程都专职做自己的事,因此,在压力大的时候,可以很明显的查出问题所在,并可以较好的实现对相应的服务进行调优,可以达到较好的性能和一定的可伸缩性。但是,在各游戏的世界里,无法准确的知道游戏的状态如在线人数之类的,会存在热点数据和服务过载等一些问题,造成部分服务堵死等现象,也无法达到在不停服务的情况下进行服务器扩容与自动切换等问题,同时会给游戏运营带来一定的问题,不能充分的对玩家数据进行分析与挖掘,因此,这种实现方式可以满足中小型的游戏开发。这种架构目前很多的游戏服务器中还在使用,技术发展也较成熟,如传奇服务端架构等。
分布式服务架构
图3 分布式的服务架构
同样,分布式的服务架构与多进程的架构具有很多相同点,如进程服务单一职责,较好的性能调优,同时采用集中式的方式对游戏服务器进行管理,各游戏服务器可以通过自定义的方式即DSL进行游戏业务的路由与分发,通过主备服务器的状态可以很清楚的知道每个服务的状态及运行情况,这样可通过动态添加服务来到达负载均衡,具备较好的性能和可扩展性,能满足大型游戏的开发。当然,采用这样方式,会具有一定的复杂性,同时各服务之间可能是不在同一台服务器上的,因此会带来一定的网络开销,在大量广播的场景中,网络IO压力大,需要通过定时批量或AOI服务等方式来进行广播通信,同时,游戏的通信协议需要经过特别的设计,尽量避免数据序列化上的CPU重复开销,采用胖客户端的方式去分担游戏服务器的序列化与反序列化;另外还有可能引入分布式事务等相关问题,需要在一个集中点进行处理。当然,在游戏设计中,策划开发人员需要尽量避免这种跨场景跨进程的游戏逻辑需求。
在分布式架构实现中,目前商业上较成功的案例是BigWorld游戏服务框架,国内外很多大型的游戏开发商都在使用。而在开源部分,目前还没有较稳定成熟的方案,我们团队采用Node.js正在开发的Pomelo游戏服务框架正在努力实现这一目标,现已进入最后的文档整理阶段,预计将在十月份进行开源与线上示例演示。
总结
<span style="display: inline !important; float: none; background-color: transparent; color: rgb(51,
相关文章:
【推荐】 一招搞定短信验证码服务不稳定
Node.js之网游服务器实践的更多相关文章
- 十个书写Node.js REST API的最佳实践(上)
收录待用,修改转载已取得腾讯云授权 原文:10 Best Practices for Writing Node.js REST APIs 我们会通过本文介绍下书写Node.js REST API的最佳 ...
- 使用Node.js搭建静态资源服务器
对于Node.js新手,搭建一个静态资源服务器是个不错的锻炼,从最简单的返回文件或错误开始,渐进增强,还可以逐步加深对http的理解.那就开始吧,让我们的双手沾满网络请求! Note: 当然在项目中如 ...
- 使用Node.js简单创建一个服务器
首先,我们要了解Node.js不是一种语言,它只是一个除了浏览器之外的,可以运行js的环境. 其次,Node能做些什么 ? web服务器. 命令行工具. 网络爬虫. 桌面应用程序开发等 3.接下 ...
- node.js作为“简单HTTP服务器”
场景 当我学习一个JavaScript库的时候,需要一个非常简单的HTTP服务器把当前工作路径变为网站根目录,由此来访问网页的静态信息.现在,除了下边的脚本server.js,假设你已经拥有: 一个工 ...
- node.js和express创建服务器
创建web服务器 一. 使用node.js创建服务器. 使用express创建http服务. 监控服务器的变化. 二. 初始化配置文件:npm init -y 使用typescript编写,导入nod ...
- Node.js 薄荷网爬取
Node.js:是一个基于前端的服务器,主要的特点:单线程,异步I/O(对这个没有了解,开发起来真的会踩很多坑),事件驱动 前言:本人主要是一个以使用.Net平台下的语言,进行开发的一个菜鸡,之前面试 ...
- Node.js学习(11)----HTTP服务器与客户端
Node.js 标准库提供了 http 模块,其中封装了一个高效的 HTTP 服务器和一个简易的HTTP 客户端.http.Server 是一个基于事件的 HTTP 服务器,它的核心由 Node.js ...
- node.js基础:HTTP服务器
一个HTTP服务器响应 var http = require('http'); http.createServer(function(request,response){ response.end(' ...
- 使用Node.js搭建一个本地服务器
let http = require('http'); //创建一个http let server = http.createServer((request,response)=>{ //创建一 ...
随机推荐
- 怎样改动X-code中的字体大小、颜色
- STL 笔记(二) 关联容器 map、set、multimap 和 multimap
STL 关联容器简单介绍 关联容器即 key-value 键值对容器,依靠 key 来存储和读取元素. 在 STL 中,有四种关联容器,各自是: map 键值对 key-value 存储,key 不可 ...
- 【转载】TCP的三次握手(建立连接)和四次挥手(关闭连接)
建立连接: 理解:窗口和滑动窗口TCP的流量控制 TCP使用窗口机制进行流量控制 什么是窗口? 连接建立时,各端分配一块缓冲区用来存储接收的数据,并将缓冲区的尺寸发送给另一端 接收方发送的确认信息中包 ...
- MySQL优化之——触发器
转载请注明出处:http://blog.csdn.net/l1028386804/article/details/46763665 触发器是一个特殊的存储过程,不同的是存储过程要用CALL来调用,而触 ...
- CString转换成char *字符串问题
buf = (LPSTR)(LPCTSTR)str; ==> buf 显示的是第一个字符 strcpy(pNumber,strNumber); ==> e ...
- 电脑突然死机,编译报错dll缺少依赖项
由于ASP.NET缓存没更新的问题(我的就是这个问题.电脑突然死机导致的). 把这个文件夹下的文件所有删除C:\Windows\Microsoft.NET\Framework\v2.0.50727\T ...
- 2017 Multi-University Training Contest - Team 1 (5/12)
官方题解 1001. Add More Zero #pragma comment(linker, "/STACK:1024000000,1024000000") #include& ...
- linux下的文件和文件夹的权限问题
1 文件和文件夹的权限 文件和文件夹的权限设置的根本目的是控制人对它们的访问. 2 用户分类 本文件的拥有者.本文件所属的grou.其它用户. 3 也就是说 在读写文件或者文件夹时,要看看自己是属于哪 ...
- UDP 端到端
创建发送端 1.建立DatagramSocket对象,该端点建立,系统会随机分配一个端口,如果不想随机分配,可手动指定. 2.将数据进行packet封装,必须指定目的地址和端口. 3.通过socket ...
- 牛客练习赛42 E.热爆了
这可能是全场最长的一份代码 问的其实是对于关键点的斯坦纳树大小 考虑补集转化,不合法的点就是它的子树中没有关键点的点和斯坦纳树根的祖先 树根不难求,关键点中dfs序最大最小点的LCA就是了 问题在前者 ...