分享

Node.js之网游服务器实践

 _src_ 2022-12-30 发布于四川

此文已由作者尧飘海授权网易云社区发布。

欢迎访问网易云社区,了解更多网易技术产品运营经验。

随着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的应用,由于性能较好并且使用简单,成为大部分应用采用的网络库来实现高性能websocket服务。在移动互联网应用中,由于协议较复杂与通信数据等问题,需要一定的裁减。下面示例中,就是最简单的单进程服务的原型:

  1. var socketio =
  2. require('');
  3. var io =
  4. socketio.listen(8080);
  5. io.sockets.on('connection',function(socket){
  6.      socket.on('disconnect',function(){
  7.      //user leave
  8.      });
  9.  socket.on('message',function(msg){
  10.      if (getLoginStatus(socket)) {
  11.     game[data.action].apply(null,[socket,msg]); 
  12.      } else {
  13.      game['login'].apply(null,[socket,msg]); 
  14.      }
  15.  });
  16. });

多进程服务架构

图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之网游服务器实践的更多相关文章

  1. 十个书写Node.js REST API的最佳实践(上)

    收录待用,修改转载已取得腾讯云授权 原文:10 Best Practices for Writing Node.js REST APIs 我们会通过本文介绍下书写Node.js REST API的最佳 ...

  2. 使用Node.js搭建静态资源服务器

    对于Node.js新手,搭建一个静态资源服务器是个不错的锻炼,从最简单的返回文件或错误开始,渐进增强,还可以逐步加深对http的理解.那就开始吧,让我们的双手沾满网络请求! Note: 当然在项目中如 ...

  3. 使用Node.js简单创建一个服务器

    首先,我们要了解Node.js不是一种语言,它只是一个除了浏览器之外的,可以运行js的环境. 其次,Node能做些什么 ? web服务器.  命令行工具.   网络爬虫. 桌面应用程序开发等 3.接下 ...

  4. node.js作为“简单HTTP服务器”

    场景 当我学习一个JavaScript库的时候,需要一个非常简单的HTTP服务器把当前工作路径变为网站根目录,由此来访问网页的静态信息.现在,除了下边的脚本server.js,假设你已经拥有: 一个工 ...

  5. node.js和express创建服务器

    创建web服务器 一. 使用node.js创建服务器. 使用express创建http服务. 监控服务器的变化. 二. 初始化配置文件:npm init -y 使用typescript编写,导入nod ...

  6. Node.js 薄荷网爬取

    Node.js:是一个基于前端的服务器,主要的特点:单线程,异步I/O(对这个没有了解,开发起来真的会踩很多坑),事件驱动 前言:本人主要是一个以使用.Net平台下的语言,进行开发的一个菜鸡,之前面试 ...

  7. Node.js学习(11)----HTTP服务器与客户端

    Node.js 标准库提供了 http 模块,其中封装了一个高效的 HTTP 服务器和一个简易的HTTP 客户端.http.Server 是一个基于事件的 HTTP 服务器,它的核心由 Node.js ...

  8. node.js基础:HTTP服务器

    一个HTTP服务器响应 var http = require('http'); http.createServer(function(request,response){ response.end(' ...

  9. 使用Node.js搭建一个本地服务器

    let http = require('http'); //创建一个http let server = http.createServer((request,response)=>{ //创建一 ...

随机推荐

  1. 正則表達式--js使用案例

    前言:在前端页面使用中.遇到日期格式的验证.開始使用了一款表单控件验证.可是不兼容!!并且使用起来还受到非常大约束.所以就决定自己写原生js. 为了完毕日期格式的验证.第一步,当然是学会使用正則表達式 ...

  2. Android锁屏或灭屏状态下,高速按两次音量下键实现抓拍功能(1.2Framework层使用startService形式实现)

        如前一篇博文所分析.我们能够使用广播的形式在高速按下两次音量下键的时候发出广播,以方便client进行捕捉. 既然有两种方式能够实现该Issue那么哪种方式是首选呢?     我个人推荐使用启 ...

  3. sql 导入数据库 出现乱码问题 解决办法 设置 --default-character-set=utf8

    mysql -u root -p --default-character-set=utf8 use dbname source /root/newsdata.sql

  4. IOS UIPickView+sqlite 选择中国全部城市案例

    1.案例简单介绍 通过读取文件.将中国全部城市写入sqlite数据库中,现通过UIPickView实现中国全部城市的选择,效果图例如以下所看到的 2.城市对象模型 中国全部城市数据请看http://b ...

  5. 关于 redux-saga 中 take 使用方法详解

    本文介绍了关于redux-saga中take使用方法详解,分享给大家,具体如下: 带来一个自己研究好久的API使用方法. redux-saga中effect中take这个API使用方式,用的多的是ca ...

  6. 线程池实例:使用Executors和ThreadPoolExecutor

    线程池负责管理工作线程,包含一个等待执行的任务队列.线程池的任务队列是一个Runnable集合,工作线程负责从任务队列中取出并执行Runnable对象. java.util.concurrent.ex ...

  7. Access 执行查询时,抛出“标准表达式中数据类型不匹配”的错误

    Access根据时间查询时应在查询条件前后加# SELECT COUNT(*) FROM [User] WHERE [CreateTime] > #{0}#

  8. 阿里云 ubuntu 14.04 模板上安装 docker

    ubuntu 14.04 的内核是 3.13 ,所以内核不用升级. 安装过程例如以下: # apt-get update # apt-get install apt-transport-https # ...

  9. php 0、null、empty和false之间的关系

    // 判断 0 与 ''.null.empty.false 之间的关系 $a = 0; echo "0 与 ''. empty.null.false 之间的关系:"; if($a ...

  10. Redis HyperLogLog及应用

    参考:http://www.runoob.com/redis/redis-hyperloglog.html Redis 在 2.8.9 之后的版本中,添加了 HyperLogLog 结构,用来做基数统 ...

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多