写点什么

深入浅出 node.js 游戏服务器开发——Pomelo 框架的设计动机与架构介绍

  • 2013-06-14
  • 本文字数:5417 字

    阅读完需:约 18 分钟

一、Pomelo 的定义和组成

以下是 Pomelo 官网给出的最初定义:Pomelo 是基于 node.js 的高性能, 分布式游戏服务器框架。它包括基础的开发框架和相关的扩展组件(库和工具包),可以帮助你省去游戏开发枯燥中的重复劳动和底层逻辑的开发。

Pomelo 最初的设计初衷是为了游戏服务器, 不过我们在设计、开发完成后发现 pomelo 是个通用的分布式实时应用开发框架。它的灵活性和可扩展性使 pomelo 框架有了更广阔的应用范围。 由于强大的可能伸缩性和灵活性,pomelo 在很多方面甚至超越了现有的开源实时应用框架。

如果你浏览一下网易的github ,会发现pomelo 远远不止是一个repository, 它是由一系列松耦合的组件组合在一起的,包括了各类demo, 各类客户端,各种库和工具。

下图是pomelo 最初的组成图:

pomelo 包括以下几部分:

  • 框架, 框架是 pomelo 最核心的部分。
  • 库,pomelo 提供了很多库,有些是跟游戏逻辑完全相关的,如 AI AOI 寻路等;也有与游戏逻辑无关的,如定时任务执行数据同步
  • 工具,pomelo 提供了管理控制台、命令行工具、压力测试工具等一系列工具。
  • 各类客户端, pomelo 提供了各类平台的客户端,包括 js, C, android, iOS, unity3d 等,这些都可以从 pomelo 的官方主页查到。
  • Demo, 一个框架需要强大的 demo 来展示功能,pomelo 提供了全平台的聊天 demo 和基于HTML5 的捡宝Demo ,系统还提供了一个强大的基于HTML5 开发的强大的MMO 游戏demo Lord Of Pomelo

而最妙的地方在于所有这些组件都是松耦合的,所有这些组件都可以独立使用。这使 pomelo 框架异常灵活,可 由于篇幅有限,本篇文章只讨论 pomelo 框架。

二、游戏服务器开发架构分析

2.1 游戏服务器运行架构

从单进程到多进程

最初的网络服务器是单进程的架构,所有的逻辑都在单台服务器内完成, 这对于同时在线要求不高的游戏是可以这么做的。由于同时在线人数的上升, 单服务器的可伸缩性必然受到挑战。

随着网络游戏对可伸缩性要求的增加,分布式是必然的趋势的。

游戏服务器与 web 应用的不同

游戏服务器的分布式架构与 Web 服务器是不同的, 以下是 web 服务器与游戏服务器架构的区别:

  • 长连接与短连接。web 应用使用基于 http 的短连接以达到最大的可扩展性,游戏应用采用基于 socket(websocket) 的长连接,以达到最大的实时性。
  • 分区策略不同。web 应用的分区可以根据负载均衡自由决定, 而游戏则是基于场景 (area) 的分区模式, 这使同场景的玩家跑在一个进程内, 以达到最少的跨进程调用。
  • 有状态和无状态。web 应用是无状态的, 可以达到无限的扩展。 而游戏应用则是有状态的, 由于基于场景的分区策略,它的请求必须路由到指定的服务器, 这也使游戏达不到 web 应用同样的可扩展性。
  • 广播模式和 request/response 模式。web 应用采用了基于 request/response 的请求响应模式。而游戏应用则更频繁地使用广播, 由于玩家在游戏里的行动要实时地通知场景中的其它玩家, 必须通过广播的模式实时发送。这也使游戏在网络通信上的要求高于 web 应用。

因此,同样是多进程架构,Web 应用与游戏应用的运行架构也完全不同, 下图是通常 web 应用与游戏应用的不同运行架构:

以上的游戏服务器运行架构中只是个示意图, 现在实情况比这复杂很多。

走向分布式开发

可以看到由于 web 服务器的无状态性,只需要通过前端的负载均衡器可以导向任意一个进程,因此运行架构相对简单, 而且很少需要分布式开发。

而游戏服务器是蜘蛛网式的架构,每个进程都有各自的职责,这些进程的交织在一起共同完成一件任务。

因此游戏服务器是一个标准的分布式开发架构。

2.2 分布式开发与难点

几乎在很多书、演讲和文章中都可以看到这样的观点: 分布式开发是很难的。 如果把所有这些难点都合起来也许有好几本书,我们今天着重看来一下游戏服务器开发的难点吧。

多进程(服务器)的管理,重量级的架构影响开发效率

通常的游戏服务器要由很多进程共同去完成任务。当这些进程交织在一起的时候,多进程的管理并不那么容易。

  • 如果没有统一的抽象与管理,光把这些开发环境的进程启动起来就是非常复杂的工作, 进程的启动与重启就将严重影响开发效率。
  • 重量级的进程消耗大量的机器资源,普通的开发机支撑不了那么多进程,可能一个人的开发环境就需要多台机器。
  • 多进程间的调试并不容易, 我们发现一个 bug 就要跨好几个进程。

rpc 调用

rpc 调用的解决方案已经有 n 多年的历史了,但 rpc 在分布式开发效率上仍然没有明显提升。

以当前最流行的开发框架 thrift 为例,它在调用代码前需要经过以下步骤:

  • Writing a .thrift file

  • Generate Thrift file to source code

    thrift --gen (language) (Thrift filename)

  • Copy the source to application

如果发生接口改动,我们又需要重新修改描述文件,重新生成 stub 接口。对于接口不稳定的开发环境, 这种方式对开发效率影响较大。

要想让 rpc 调用的开发达到最简,不需生成 stub 接口, 无需描述文件, 我们需要一种很巧妙的方法。

分布式事务、异步化操作

尽管我们尽量把逻辑放在一个进程里处理,但分布式事务仍然是不可避免的。两阶段提交的代码,异步化的操作在普通的开发语言里并不是容易的事。

但我们会发现用了 node.js 之后,它的编程模式里天生就是这种模式, 两阶段提交、异步化操作这些看似复杂的工作里在 node.js 只是一个正常的异步执行流程。

负载均衡,高可用

由于游戏服务器的有状态性,很多请求需要通过特定的路由规则导到某台服务器;对于有些无状态的服务器,我们则可以把请求路由到负载最低的服务器。

通常对于无状态的服务器, 高可用是比较好做的。对于有状态的服务器,要做高可用会非常困难, 但也不是完全没有办法,常见的两招:

  • 将状态引出到外存,例如 redis, 这样进程本身就可以无状态了。但由于所有的操作都通过 redis 可能带来性能损耗,有些场景是不能应会这些损耗的。
  • 通过进程互备, 将状态通过日志等方式同步到另一进程, 但这可能存在着瞬间数据丢失的问题,这种数据丢失在一些应用场景可能毫无问题, 但在另外一些应用场景可能引起严重的数据不一致。

有状态的高可用并不是那么好实现的,pomelo 将在 0.5 版本提供高可用的实现机制,引入 zookeeper 和 redis 可以解决一些进程(如 master)的高可用问题,但真正复杂的应用场景的逻辑只能由应用自己处理。

2.3 Node.js 的引入

为什么会在这里谈 node.js 的引入? 因为在讲了这么多分布式开发的难点之后,引入 node.js 实在是太自然了。它解决了分布式开发的很多问题。

  • 天生的分布式, node.js 之所以叫 node 就是因为它天生就是做多进程开发的, 多个节点 (node) 互相通讯交织在一起组成的分布式系统是 node 天生就应该这么干的。例如前面提到的分布式事务、异步化操作在 node.js 里只是个正常的流程。
  • 网络 io 与可伸缩性的优势。游戏是非常 io 密集型的应用, 采用 node.js 是最合适的, 可达到最好的可伸缩性。
  • 轻量级, 轻量级的进程带来的开发效率的优势在开发的时候异常明显。
  • 语言优势。使用 javascript 开发可以实现快速迭代,客户端 html 5 使用 javascript,甚至在 unity3d,cocos2d-x 这样的游戏平台上也可以使用 javascript, 可实现最大限度的代码共用。

三、pomelo 架构分析

pomelo 框架在最初设计的时候只为了一个目标:为基于长连接的分布式游戏服务器架构提供基础设施。框架的内容在逐渐扩展,但最核心的框架只为了干以下三件事:

  • 服务器(进程)的抽象与扩展

在 web 应用中, 每个服务器是无状态、对等的, 开发者无需通过框架或容器来管理服务器。 但游戏应用不同, 游戏可能需要包含多种不同类型的服务器,每类服务器在数量上也可能有不同的需求。这就需要框架对服务器进行抽象和解耦,支持服务器类型和数量上的扩展。

  • 客户端的请求、响应、广播

客户端的请求、响应与 web 应用是类似的, 但框架是基于长连接的, 实现模式与 http 请求有一定差别。 广播是游戏服务器最频繁的操作, 需要方便的 API, 并且在性能上达到极致。

  • 服务器间的通讯、调用

尽管框架尽量避免跨进程调用,但进程间的通讯是不可避免的, 因此需要一个方便好用的 RPC 框架来支撑。

下面分别对这三个目标进行详细的分析:

服务器(进程)的抽象与扩展介绍

服务器的抽象与分类

该架构把游戏服务器做了抽象, 抽象成为两类:前端服务器和后端服务器, 如图:

前端服务器 (frontend) 的职责:

  • 负责承载客户端请求的连接
  • 维护 session 信息
  • 把请求转发到后端
  • 把后端需要广播的消息发到前端

后端服务器 (backend) 的职责:

  • 处理业务逻辑, 包括 RPC 和前端请求的逻辑
  • 把消息推送回前端

服务器的鸭子类型

动态语言的面向对象有个基本概念叫鸭子类型 服务器的抽象也同样可以比喻为鸭子, 服务器的对外接口只有两类, 一类是接收客户端的请求, 叫做 handler, 一类是接收 RPC 请求, 叫做 remote, handler 和 remote 的行为决定了服务器长什么样子。 因此我们只要定义好 handler 和 remote 两类的行为, 就可以确定这个服务器的类型。

服务器抽象的实现

利用目录结构与服务器对应的形式, 可以快速实现服务器的抽象。

以下是示例图:

图中的 connector, connector, gate 三个目录代表三类服务器类型, 每个目录下的 handler 与 remote 决定了这个服务器的行为(对外接口)。 开发者只要往 handler 与 remote 目录填代码, 就可以实现某一类的服务器。这让服务器实现起来非常方便。 让服务器动起来, 只要填一份配置文件 servers.json 就可以让服务器快速动起来。 配置文件和对应的进行架构如下所示:

客户端请求与响应、广播的抽象介绍

所有的 web 应用框架都实现了请求与响应的抽象。尽管游戏应用是基于长连接的, 但请求与响应的抽象跟 web 应用很类似。 下图的代码是一个 request 请求示例:

请求的 api 与 web 应用的 ajax 请求很象,基于 Convention over configuration 的原则, 请求不需要任何配置。 如下图所示,请求的 route 字符串:chat.chatHandler.send, 它可以将请求分发到 chat 服务器上 chatHandler 文件定义的 send 方法。

Pomelo 的框架里还实现了 request 的 filter 机制,广播 / 组播机制,详细介绍见 pomelo 框架参考

服务器间 RPC 调用的抽象介绍

架构中各服务器之间的通讯主要是通过底层 RPC 框架来完成的,该 RPC 框架主要解决了进程间消息的路由和 RPC 底层通讯协议的选择两个问题。 服务器间的 RPC 调用也实现了零配置。实例如下图所示:

rpc 调用

上图的 remote 目录里定义了一个 RPC 接口: chatRemote.js,它的接口定义如下:

复制代码
chatRemote.kick = function(uid, player, cb) {
}

其它服务器(RPC 客户端)只要通过以下接口就可以实现 RPC 调用:

复制代码
app.rpc.chat.chatRemote.kick(session, uid, player, function(data){
});

这个调用会根据特定的路由规则转发到特定的服务器。(如场景服务的请求会根据玩家在哪个场景直接转发到对应的 server)。

rpc 的使用远比其它 rpc 框架简单好多,因为我们无需写任何配置文件,也无需生成 stub。因为我们服务器抽象的实现的方式,使得 rpc 客户端可以在应用启动时扫描服务器目录自动生成 stub 对象。

完成了以上三个目标, 一个实时的分布式应用框架的轮廓就搭出来了,剩下的工作是往上添肉,这是我们后续文章里的内容。

四、从游戏框架到实时应用框架

当我们分析完 pomelo 框架的设计目标时, 我们发现核心框架的这件事情竟然与游戏没有任何关系。这是一个通用的实时分布式应用开发框架。官网上的聊天服务器 demo 就是一个实时应用。

事实上 pomelo 已经被应用在很多非游戏领域。 网易的消息推送平台是基于 pomelo 开发的,它承担了网易移动端和 web 端的消息推送, 目前已经上线使用。

整个开源社区没有与 pomelo 定位相同的实时应用框架。目前在开源社区最流行的实时应用框架当数 meteor,它与 pomelo 有着截然不同的设计目标。我们来比较一下这两个框架的区别。

以下是 meteor 给出的定义:

Meteor is an open-source platform for building top-quality web apps in a fraction of the time, whether you’re an expert developer or just getting started.

可以用以下两点概括:

  • meteor 是只能面向 web 的实时应用
  • meteor 最关注的是开发效率

但是我们的问题是:

  • 现在的实时应用有多少是只面向 web 端的?
  • 规模稍大的实时应用,瓶颈是在可伸缩性、性能还是在开发效率?

我们给出的答案是:

  • 同时支持移动端、web 端、PC 端的实时应用已经是主流
  • 相比开发效率,可伸缩性、性能是规模较大的实时应用更有可能出现的瓶颈

而 pomelo 在这两方面具有明显的优势:

  • pomelo 支持动态 connector 协议机制,使它同时支持 web、移动、PC、untiy3d 等各类客户端。开发无缝衍接各类客户端的高时应用在 pomelo 里面只是个配置问题
  • pomelo 在可伸缩性和扩展上具有很强的优势,这也是 pomelo 设计的最根本目标

以上的比较并不说明 pomelo 比 meteor 优秀, 它们是完全定位不同的两个实时应用框架。相信用户会根据自己的需求做出选择。

五、未来与展望

pomelo 在开社区才刚刚起步, 仅仅不到半年时间 pomelo 已经在 github 和各类社区上积累了强大的人气,1700 多的 watcher 在 github 已经是相当不错的战绩。但这仅仅只是个起步,pomelo 的真正的暴发期还未到来。

pomelo 将会在分布式开发方面下更大的功夫,在加强高可用、负载均衡、过载保护、运维机制等方面做得更好.

pomelo 也逐渐在世界的开源社区推广。LXJS 2013 的组织者邀请了笔者于 2013 年 10 月去葡萄牙里斯本做英文演讲,可见 pomelo 已经逐渐受到了国际 node 社区的牛人关注。当然这还只是个开始。

2013-06-14 07:5616016

评论

发布
暂无评论
发现更多内容

ARM和X86云服务器的算力对比

Python研究所

签约计划

百余大企业共赴新文明之约:2021 DEMO WORLD 世界创新峰会拉开帷幕

创业邦

创新

面阿里P7,竟问这么简单的题目?

Java架构师迁哥

MPP大规模并行处理架构详解

五分钟学大数据

大数据 MPP 5月日更

TcaplusDB :承诺戒烟,从你我做起!

TcaplusDB

数据库 nosql 后端 TcaplusDB

列举出常见的Java面试题,我靠这个在春招拿到了阿里的offer

???

面试 Java面经 java真题分享

🔎【Java 源码探索】深入浅出的分析ThreadLocal

洛神灬殇

Java 多线程 ThreadLocal 5月日更 ThreadLocalMap

5分钟速读之Rust权威指南(十二)

wzx

rust

脉脉3小时转发65w次!这份Java面试宝典发生了什么?

Java架构师迁哥

100W点击 10w人获取,阿里Java高级面试题及答案 到底有多强

???

面试 java真题分享

云原生加速落地,金融行业应用上云来打样儿

BoCloud博云

云原生

极光开发者周刊【No.0528】

极光JIGUANG

程序员 开发者 开发者工具

🔎【Java源码探索】深入浅出的分析HashMap(JDK8)

洛神灬殇

Java 源码 源码分析 hashmap 5月日更

公安局重点人员研判分析系统解决方案

Fabric | 自动化神器

Python研究所

签约计划

TcaplusDB君 · 行业新闻汇编(5月25日)

TcaplusDB

数据库 nosql 分布式 后端 TcaplusDB

牛x运维常用的工具系列-1

运维研习社

运维 工具分享 5月日更

获5项大奖,发布《云计算开放应用架构标准》,阿里云持续领航云原生

阿里巴巴中间件

云计算 最佳实践 云原生 案例 白皮书

OKR 八问 —— 关于 OKR 的常见问题与思考

CODING DevOps

团队管理 DevOps OKR

使用Docker运行DataX定时全量备份关键数据表

白粥

DataX 数据表备份

python脚本编写——自动剪切移动文件夹

YUKI0506

盘点golang中的开发神器

捉虫大师

Go 语言

如何评估 Serverless 服务能力?这份报告给出了 40 条标准

Serverless Devs

云计算 云原生 Forrester Wave #Serverless

论证:iOS安全性,为什么需要审核?

37手游iOS技术运营团队

ios SIP Sandbox iOS Developer ios安全

Vue-1-初识

Python研究所

签约计划

MeterSphere | 超好用的开源测试平台

Python研究所

签约计划

AI年中钜惠来袭—全场低至6折 企业新客1元优享福利翻倍

百度大脑

福利 Iphone12

【得物技术】得物App分发平台的探索建设历程

得物技术

效率 平台 实践 心路历程 迭代

深入浅出node.js游戏服务器开发——Pomelo框架的设计动机与架构介绍_Web框架_谢骋超_InfoQ精选文章