游戏服务器框架简述

框架

目前游戏类型千差万别(卡牌,arpg,mmo,moba等),每种类型游戏设计的侧重点不相同导致框架上的差异,不过即使相同类型游戏,不同设计师实现的框架也不经相同。这里我们不会针对各种纷杂的框架一一介绍,本着求同存异的态度,只是从分层架构设计的角度来阐述这些零零种种框架的本质。

依据业务上的差异,基本上可以把游戏服务器框架映射到一个四层架构模型上,如图:

游戏服务器分层模型

  • Gateway Service

    负责客户端网络接入,收敛网络入口。gateway的业务逻辑相对比较简单,主要处理网路消息的转化(客户端发送到后端服务器,后端服务器发送到客户端)与过滤。从它负责的业务角度上可以看出一个好的gateway service其实就是一个高性能的网络服务。针对高性能网络服务的实现有很多方式,常见模型有:

    • 多线程模型,如果对网络编程不熟悉,可以选择开源实现,比如muduo, asio,netty等。
    • 纤程,这一类的开源实现也有很多,语言级别的golang,erlang,单独库形式的libco,skynet。

    在我们游戏里面使用的方案是基于linux系统下的多线程模型。具体的实现是,one loop per thread,loop是基于反应器的设计模式实现。系统层面也会做相应的优化,比如cpu绑定,网卡的硬中断,软中断的优化。在这些完成之后,一个高性能的网络服务器基本上就成型了。在我们实际运行过程,单Gateway最高同时在线达到15w,机器整体的负载也不高。

  • Logic Service

    游戏逻辑主要在这个服务上处理。常见的实现,多IO线程加单独的业务线程。线程之间通过消息队列进行通信,消息队列简单可以用一个加锁的队列实现,也可以选择无锁队列(建议使用成熟的开源方案)。网络消息汇总到同一个线程中处理,也就是说游戏业务处理是单线程的,这种设计的优势在于避免业务开发中数据竞争。如果单线程实在不能满足性能要求,比如一些mmo游戏中,可以采用多进程的模式,也就是有多个logic service,配合可能也需要一些协调logic service的服务。

  • Record Service

    数据库的代理层,负责与数据库交互,解耦业务层的数据处理,适应数据库的改变,业务逻辑也相对简单。实现类似于Logic Service,它也可以合并到logic service里,但是独立开来,整体框架更加清晰。

  • Database

    顾名思义,保存玩家数据的地方。常见的游戏数据库包括: mysql,redis,mongodb等。我们游戏数据库选择是RedisLV,它解决了redis备份时候可能导致内存使用过高的问题。它使用的方法是为redis引入基于leveldb的数据落地方案。leveldb是google开源的kv数据库,使用lsm tree算法,数据写入的性能比较高。修改redis的源码,在redis中与写入操作相关的命令处理中,将改变同时写入leveldb,数据库的备份只针对leveldb做备份。

服务驱动

这一节主要针对Logic Service,也就是游戏核心业务的驱动。游戏的业务主要是响应外部请求和处理内部状态改变,包括以下两种驱动方式:

  • 消息驱动,针对各种网络消息做出响应。比如,玩家的点击反馈等。常见实现方式是通过命令模式,也就是消息封装成一个对象,不同的消息参数化。
  • 时间驱动,一些业务需要基于时间而做出改变。比如,定时活动的开启,玩家数据定时的保存等。常见的实现方案是定时器,定时器采用的算法可以是时间轮,红黑树等。

实现这两种驱动之后,游戏服务器可以响应外部和内部的改变,基本上服务就可以正常的运转。游戏业务与其他所有后端业务都一样,本身就是数据结构的组织。下面介绍一些常用的设计模式和算法帮助游戏业务的实现。

常用设计模式

  • 单例模式
  • 工厂模式
  • 命令模式
  • 订阅者模式
  • 状态模式
  • 策略模式

常用算法

  • 二分查找
  • 快排
  • 红黑树
  • 跳表
  • 优先级队列
  • A*
  • 行为树