Skip to content

Latest commit

 

History

History
318 lines (205 loc) · 25.2 KB

File metadata and controls

318 lines (205 loc) · 25.2 KB

模块零 概论

第1章 游戏服务器架构总体设计

  1. 游戏服务器架构设计的意义

    • 良好的架构设计有助于团队协作开发
    • 良好的架构设计有助于避免bug 的产生
    • 良好的架构设计有助于制定合理的项目开发周期计划
    • 良好的架构设计有利于测试
  2. 游戏服务器架构分类

    • 单体游戏服务器架构

    • 分布式游戏服务器架构

  3. 游戏服务器架构基本模块

    • 网络通信长连接与短连接

      • 长连接是指,客户端与服务器一旦建立好连接之后,就维护这个连接,并保证这个连接不断开。长连接的优点是客户端每次发送请求都不用重新建立连接,有请求可以立即发送,从而节省消息发送的时间。而且长连接通信是双向的,服务器也可以主动给客户端发送消息,比如向其他客户端转发另一个客户端发送的聊天消息,或主动告知客广端一些数据状态的变化。而长连接的缺点是会一直占用计算杌资源(内存、文件句柄、网络VO);代表就是Socket
      • 短连接是指客户端与服务器建立好连接,一次请求返回之后,这个连接就会断开,不需要维持连接。短连接的优点是连接断开之后资源就会释放,不再占用服务器资源,可以为更多的客户端提供服务。短连接的缺点是每次请求都需要等待建立新的连接,请求发送会慢一些,HTTP 就是常用的短连接协议之一
    • 网关

      网关就是网络通信的第一关,是服务器上所有服务的大门。它负责与外界联系,并且可以“辨正邪,识真伪,保证内部服务收到的都是合法消息,限制请求流量,防止请求超载。

    • 服务消息交互——消息中间件

      消息中间件是一类成熟的网络通信组件,它很好地屏蔽了网络的底层通信细节,比如网络连接建立、消息编码解码、消息发布与监听等。它具有高性能、低禺合、发布/ 订阅异步性、流量控制、最终一致性等一系列功能,既支持单点部署,又支持集群部署。也有一些 RPC,以它为通信基础,实现业务服务之间异步调用,使用起来非常方便。

    • 业务处理框架

      业务处理框架是为了便于业务功能开发,对影响业务功能开发的公共部分进行架构规划,尽量让开发人员专心于功能设计与开发,并提供底层的基础支持。一般有3个模块。

      • 消息管理 游戏用户操作的过程,对服务器来讲就是修改游戏数据。在服务器架构中,网络层的数据接收和请求的业务处理会在不同的线程中,一个游戏用户的数据只有一份,用户有可能同时修改这份数据,这就有可能出现多线程操作共享数据的问题。解快这个问题的一种方式是对数据修改进行加锁。但是由于游戏用户数据很多,导致需要对服务器发送大量并发请求,多线程执行加锁代码时,为了获取执行权和保存线程执行状态,会导致 CPU 大量的上下文切换(指CPU 从正在执行的线程切换执行另一个线程),反而减少了服务器的消息处理的吞吐量,使性能下降。而且如果控制不好加锁,也容易出现死锁的现象。另一种方式是不加锁,让同一个用户的数据按顺序处理。一种实现方法是把同一个用户的请求先放到一个队列中,不同的用户的请求可以分到不同的队列中,再对每个队列固定启动一个对应的线程处理队列中的消息。这样可以避免加锁引1起 CPU 产生大量的上下文切换,也保证同一个用户的数据,都在同一个线程中处理,避免并发修改共享数据。
      • 线程管理 在游戏服务器中,线程是一种非常珍贵且重要的资源,也是处理并发的唯一手段。但并不是说线程越多越好,线程太多,也会使 CPU 产生大量的上下文切换,使线程处理业务的能力下降。要合理地规划线程的使用,才能使线程的利用率最大化。对线程的合理分配,可以更好地优化服务器的性能。比如分配专门的线程池处理游戏业务,另外分配专门的线程池负 责数据的操作,把耗时操作隔离到固定的线程中,减少对业务线程的卡顿,增加业务消息的吞吐量。因此在游戏服务开发中,不能随意地创建线程,定要有规则和标准。
      • 数据缓存与持久化 在业务服务中,所有的操作都是依赖于数据。数据存储于数据库,但是把数据缓存在内存之中,可以避免操作数据时查询数据库而浪费时间。因此游戏数据什么时候加载到内存,如何将内存中的数据更新到数据库之中,也是架构要解决的问题。这样可以把数据的管理统一化,业务开发中只需要操作内存的数据即可,即使不了解数据库相关的知识也能很快开发业务。
    • 测试模块

      测试模块主要包括单元测试和系统集成测试,单元测试可以使用目前流行的测试架构,比如 TestNG、JUnit 4 等。

第2章 服务器项目管理—Maven

Apache Maven 是最常用的 Java 项目管理工具之一。它制定了标准的 Java 项目结构,方便于依赖和引1用其他的 Jar 包,管理单元测试、打包流程、版本发布,也提供了各种开源的功能插件,提高项目的开发和管理效率。

第3章 数据库选择与安装

  1. 数据持久化——MongoDB

    MonsoDB 是目前游戏服务器开发中常用的数据库之一。它是文档型数据库,直接存储 JSON 串,插人和选择速度也相对较快,可以满足数据库的快速开发与管理。

  2. 内存型数据库——Redis

    目前Redis 已经是游戏服务器架构中不可缺少的一个组件了。它是一种内存型数据库,所有存储在 Redis 中的数据在 Redis 启动之后会全部加载到内存中,所以从 Redis 中查询数据和存储数据的操作速度非常快,可以作为缓存和共享内存使用。

模块二 游戏服务中心架构设计

此设计针对HTTP/HTTPS短连接

第4章 游戏服务中心开发

  1. 游戏服务中心的作用

    • 游戏服务中心提供游戏外围服务

      一切和游戏性无关的功能,都可以称之为游戏外国服务。比如用户注册、登录、公告、获取服务器列表、角色创建、角色数据预加载等,这些都是在用户进人游戏之前的功能,在进人游戏之后,不会再被请求。这些功能本身和游戏操作没有什么关系,和游戏数据也没有什么关联,所以把这此功能集中在游戏服务中心统一管理和维护。

    • 游戏服务中心方便动态扩展 

      一台服务器的资源是有限的。随着游戏用户的增多,并发请求会越来越多,服务器的压力会越来越大,导致CPU 处于长时间的忙碌状态,对客户端的响应越来越慢。此时服务的动态扩展是必不可少的。web 服务有非常成熟的扩展框架,比如使用 Nginx 或 Web服务器网关只需要添加少量的配置,即可实现 Web 服务的负载均衡,快速提升服务器的服务能力。

  2. 游戏服务中心开发准备

    • 根据需求设计架构

      • 可以动态伸缩 一台服务器的资源毕竟是有限的,所以它提供的服务也是有限的。随着公司的发展,用户越来越多,单台服务器的压力越来越大,逐渐不能满足服务的需要。这个时候,就要添加新的服务器,分担服务压力,增加并发量,以提高服务能力。这样的话架构就必须支持负载均衡,根据负载均衡的算法,将客户端的请求分发到不同的服务器上处理
      • Web 服务器网关 Web 服务器网关的一个主要作用是转发客户端的请求,实现服务器的负载均衡、集群部署。如果处理同一接口请求的服务有多个,根据接口的参数,把某个指定的相同参数的请求转发到指定的同一个服务上面。比如为了防止同一个客户端连续请求并发修改用户数据的行为,可把同一个用户的请求都转发指定的相同的服务上面,在一个进程中保证请求的顺序处理,而且这个用户的数据还可以缓存在这个服务器上面,成为有状态的服务,提高数据处理效率。这就需要 Web 服务器网关的支持。在网关那里进行请求转发。网关也可以统一进行权限验证,请求流量限制,后面再添加新的 Web 服务就不需要开发这些功能了,可以减少重复开发
      • 可以使服务高可用 服务高可用是指尽量避免服务停止,保证7×24 小时提供服务,这就需要相同的服务器至少要部署两台,也叫服务多实例部署。一台服务器出现问题了,会将这台服务器的服务自动转移到另外的服务器上面,另外的服务器可以正常提供服务。这样即使这台服务器出间题,在一定时问内,也只会影响一小部分用户,服务转移成功之后,就可以正常为所有用户提供服务了,期间不需要人为的干涉。
      • 注册中心服务 在分布式架构中,服务治理是一个重要的功能。当新的服务启动时,需要被其他的服务感知到,这样其他的服务就可以向这个新的服务发送请求。当有服务被关闭时,也需委被其他的服务感知到,这样其他的服务就不会再向这个关闭的服务发送请求了。这样就需要一个注册中心服务:当业务服务启动时,向这个服务注册此业务服务的信息;当业务服务关闭时,注册中心服务检测到业务服务不可访问时,从注册中心服务中移除此业务服务信息。

      根据以上需求,对游戏服务中心架构进行设计,如图 所示。

      客户端通过域名,向DNS 负载获取某一个服务的网关的 卫P地址,然后再向这个发送请求。网关通过注册中心服务,知道当前有哪些服务可以使用,根据转发匹配规从请求的 URL 中获取匹配的参数,然后将请求转发到匹配成功的服务上面处理。

    • Spring Cloud

      Spring Cloud 为微服务开发提供了一些现成的服务组件,让开发人员能够快速地搭建一套微服务开发环境,主要的组件如下。

      • Spring Cloud Consul 这个组件将服务注册中心----Consul 集成到 Spring Cloud 之中。通过简单的注解配置就可以实现服务的注册中心

      • Spring Cloud Gateway 这个组件在 Spring MvC 的基础之上,为构建web服务器网关提供了丰富的 API,它实现了对客户端请求的路由转发、安全验证、状态监控、服务发现、负载均衡、请求速率限制等功能。可以快速方便地构建 web 服务器网关。

      • Spring Cloud Bus 这是一个消息总线服务,它基于消息队列实现,利用消息队列的发布订单功能,给各个服务节点发送事件,修改服务的一些状态。在业务中,也可以利用它实现不同节点之间的通信,比如内部RPC 的实现等。

      • Spring Cloud Config 这是一个配置中心管理组件,它可以管理分布式系统中的配置信息。比如在application yml 或 application.properties 中的一些公共配置,只需要在 Spring Cloud Conig配置一份文件,就可以在所有的服务节点引用。它还可以对配置数据加密和解密,动态更新配置内容等。

  3. 用户登录注册功能开发 创建游戏服务中心项目、网络通信数据格式定义、添加数据库操作、实现登录注册、全局异常捕获处理、登录注册测试、实现角色创建、角色创建测试 

第5章 Web服务器网关开发

  1. Consul 服务注册中心 Consul 有多个组件,但总体而言,它是基础架构中的一款服务发现和配置的工具。它是一个分布式、高可用的系统,主要用于管理其他服务向它注册的服务信息。使用Consul可以在业务服务启动的时候,通过 HTTP 接口,向 Consul 服务发送一些服务的基本信息,比如IP地址、端口、服务名称、服务ID等。业务服务也可以通过 HTTP 接口,从 Consul 中获取其他服务的基本信息。

  2. Web 服务器网关功能开发 Spring Cloud Gateway

  3. 统一验证请求权限 网关全局过滤组件——GlobalFilter

  4. 请求负载均衡 负载均衡组件——Spring Cloud Ribbon

  5. 网关流量限制 常见的限流算法

    • 计数器算法 计数器是一种简单的基本算法,一般是限制在一段时间内,允许多少个请求通过。
    • 漏桶算法 漏桶算法用来消除 “突刺现象”。漏桶算法是一个生产者一消费者模式,请求过来时先放人级存队列,另外启动一个定时线程(ScheduicdExecutorservice)以一定的时閒隔从队列中获取请求,可以一次性获取多个并发执行,如果队列满了就拒绝接收请求。这类似于一个漏斗,上面不停地倒水,下面以一定的速度出水。但是它也有一个问题无法应对短时间内的突发流量。比如一次来 100 个请求和一次来10个请求的处理速度是一样的,即无法自适应并发量。
    • 令牌桶算法 令牌桶算法是对漏桶算法的一种升级。漏桶中存放的不再是请求消息,而是存放牌。有一个机制,以一定的速度往漏桶中存放令牌,如果桶中令牌数达到上限,就丟弃牌。每次请求过来需要先获取令牌,只有拿到令牌,才有机会继续执行,否则选择等待用的令牌或者直接拒绝。
  6. HTTPS 请求配置

    简单讲是 HTTP 的安全版。即 HTTP 下加人安全套接层 ( Secure Sockets Layer, SSL ), HTTPS 的安全基础是 SSL,因此加密的详细内容就需要 SSL。SSL 及其“继任者”传输层安全 ( Transport Layer Security,TLS)是为网络通信提供安全及数据完整性的一种安全协议。

  7. 服务错误异常全局捕获

    在web服务器网关转发的过程中,业务服务可能会因为某些原因发生异常,默认情况下,返回的错误信息都是以 HTML 的格式返回给客户端。但是用户中心是作为 Restful服务的,返回的消息统一是 JSON 格式,如果以 HITML 格式返回,通信协议就不统一了,客户端也解析不了。因此当有异常的时候,应该重新组织返回的错误信息,以JSON 的格式返回。这样就可以统一与客户端通信的协议格式,服务器也方便记录日志。

模块三 游戏网关架构设计

此设计针对Socket长连接

第6章 游戏服务器网关开发

  1. 游戏服务器网关管理 游戏服务器网关必须支持动态伸缩 游戏服务器网关信息缓存管理 游戏服务器网关负载均衡策略

  2. 客户端与游戏服务器网关通信开发

    • 网络通信数据粘包与断包原因:Nagle算法、MSS/MTU算法、socket缓冲区和滑动窗口

    • 网络通信协议制定:根据需要添加需要的字段

      • 消息总长度:用于记录每个数据包的大小,方便从TCP 数据流中截取完整的数据包
      • 客户端消息序列号:用于消息的幂等处理,每个消息都有一个唯一的递增的序ID,同一个消息序列号只会被服务器处理一次。
      • 消息请求ID:用于区分每个请求对应的业务处理。比如 1001 表示登录.1002示创建角色等。
      • 服务ID:消息所要到达的服务ID。这个主要用于消息分发和负载均衡
      • 客广端发送时间:与本地时间结合,可以检测数据包 在网络中的耗时。
      • 服务器返回时间:游戏服务器处理完客户端请求,返回给客户端的发送时间。
      • 协议版本:用于功能升级时对老版本的客户端兼容。比如某个功能,在A版本与B版本,需要的参数可能不一样,需要分开处理。也用于客户端版本的强制升级,比如可以强制指定只接收某个版本客户端的请求,如果不是这个版本,将强制客户端升级到这个版本。
      • 是否压缩包体:标记包体是否压缩了。当包体达到了一定大小,为了节省带宽,可以对此包体进行压缩。相应的接收端接收之后需要解压
      • 错误码:主要是服务器返回给客户端,如果错误码不为 0,则包体的内容为空。
      • 消息内容:发送的业务数据,用于对业务的处理。
    • 客户端消息与游戏服务器网关的编码与解码开发

  3. 请求消息参数与响应消息参数对象化

  4. 消息体对象序列化与反序列化

    • 消息体使用JSON 序列化与反序列化
    • 消息体使用Protocol Buffers 序列化与反序列化
  5. 消息自动分发处理

  6. 网络通信安全

    • 连接认证
    • 通信协议加密和解密
    • 游戏服务器网关流量限制
  7. 网络连接管理

    • 连接管理
    • 连接心跳检测
    • 消息幂等处理

模块四 业务服务架构设计

第7章 游戏服务器网关与游戏业务服务数据通信

  1. 游戏服务器网关与游戏业务服务通信定义

    • 游戏服务器网关消息转发

      对于游戏服务器网关转发消息时的负载均衡,在架构设计 上和 Spring Cloud Gateway本质上是相通的,可以参考 Spring Cloud Gateway 的设计实现,只不过需要把短连接修政为长连接,自定义实现消息的序列化和反序列化。

    • 定义消息通信模型

      IMG_9742
    • Spring Cloud Bus 消息总线 消息总线通信层——Kafka

  2. 游戏服务器网关与游戏业务服务通信实现

    • 消息序列化与反序列化实现
    • 游戏服务器网关消息负载均衡
    • 游戏服务器网关消息转发实现
    • 游戏服务器网关监听接收响应消息
    • 添加游戏业务服务项目
    • 游戏服务接收并响应网关消息

第8章 游戏业务处理框架开发

  1. 游戏服务器中的多线程管理

    在多核处理器上,充分利用每个 CPU 的处理能力,可以提高服务器的并发处理效率,而要充分利用多个 CPU,就需要在游戏服务中使用多线程。理论上,为了提高游戏服务的并发处理能力,每收到一个消息,就创建一个线程去处理这个消息,这就可以并发地处理N个消息。但是,在一台物理服务器上面,创建更多的线程就能提升服务器的并发性能吗?答案是不能。相反,创建过多的线程反而会降低服务器的处理能力。

  2. Netty 线程池模型

    Netty是一个异步网络通信框架,为了管理好线程池的应用,它在 Java 的线程模型上做了一些优化和封装,更加适用于事件异步处理。

  3. 客户端消息处理管理 借鉴Netty 的消息处理机制实现客户端消息事件处理框架模型

    IMG_9743

  4. 不同游戏用户之间的数据交互

    • 多线程并发操作数据导致的错误或异常
    • 在功能设计上避免用户数据之间的直接交互
    • 在架构设计上解决用户数据之间的直接交互

第9章 游戏用户数据管理

  1. 游戏用户数据异步加载 加载游戏数据的时机
    • 启动加载
    • 登录加载
    • 异步加载
  2. 游戏数据持久化到数据库
    • 游戏数据持久化方式
      • 第一种是实时更新,只要用广修改了数据,就同时将被修改的数据更新到数据库中更新成功之后再返回。这种方式的优点是,即使服务器突然宕机了,游戏用户修改的效格也不会天失,下次进入游戏的时候,所有的数据都会从数据库中加载。但是它的缺点也很明显,就是会产生大量的数据操作。
      • 第二种方式是定时将缓存数据整体更新到数据库一次,这里说的数据库包括内存型数据库 Redis 和文档型数据库 MongoDB。定时更新的好处是可以减少操作数据库的次数。
      • 于定时持久化数据的方式,还有一种中间方案,即先将数据实时更新到 Redis中(或者更短的定时间隔,比如每 1min 就更新一次数据到Redis 中),再定时更新到 MongODB中。因为 Redis 的操作速度要比 MongoDB 快得多,支持更高的 QPS。即使服务器容机了,等服务器重新启动之后,活跃的游戏用户进人游戏,会先从 Redis 获取最新的数据。过段时间之后,就会将最新的数据持久化到 MongODB 中,数据几乎没有损失或损失很小。既然是定时持久化数据,那么就需要有一个定时器来触发持久化游戏数据操作。定时器也有两种,一种是全局定时器,每隔固定的时间间隔触发一次持久化数据操作,定时触发的时候,就会遍历全部的游戏缓存数据,进行持久化操作。这种方式的缺点是会瞬间增加数据库的压力,定时触发的时候,数据库的压力是最高的;而在定时没有触发的时候,数据库的压力又是最低的。这样就出现了两个极限,不能最大化利用资源。另一种方式就是一个用户自己维护一个属于自己的定时器,从用户第一次进人游戏开始计时,每隔固定的间隔持久化一次数据,这样就不会导致瞬间发生-全服数据更新了,把每个用户持久化操作分散开来,增加数据库资源的利用率。
    • 异步方式持久化数据的并发问题
      • 一种方式是在数据持久化的时候,把原来的Player对象复制一份,这样业务逻辑和特久化的时候操作的都是独立的Player对象,不会出现并发操作共享数据的问题。这种方式的缺点是,在开发的时候,需要业务人员单独手动实现对象的复制,降低了开发效率。其优点是创建新对象效率高。
      • 另一种方式是先把业务操作的 Plaver 对象在业务线程中序列化为 JSON 字符串,然后将JSON 字符串传到数据持久化任务事件中执行。这种方式的缺点就是牺牲了效率,对象在序列化的时候,可能由于数据量比较大而执行得比较慢。其优点是开发人员不用关注集合并发性的问题,可以提高开发效率。
      • 还有一种方式是在Player 中所有的集合使用线程安全的集合,比如 ConcurrentHashVap,LinkedBlockingQueue。这种方式的缺点是在开发过程中,需要明确约定好。开发人员在使用到集合的时候,一定要声明为线程安全类型的集合,不能声明为接口类型。

模块五 RPC通信架构设计

第10章 RPC 通信设计与实现 

分布式架构永远绕不过的问题就是不同进程间的数据通信,即远程过程调用 (Remote Procedure Call, RPC)现在被统一称为内部RPC。现在有很多开源的RPC 库,比如gRPC, Dubbo, Hessian,Thrift 等。毋庸置疑,这些都是非常优秀的 RPC 框架,但是它们大部分都用于 Web 服务,且为短连接,满足不了游戏对高性能的需要。 虽然 Thrift 支持长连接双向通信,但是要把亡融人自己的架构系统,不得不做很多妥协。就像练习别人的武功,永远达不到最高境界,只有融人适合自己的元素,才能完全发挥它的威力。

第11章 事件系统的设计与实现

  1. 事件系统在服务器开发中的重要性
    • 事件系统可以解耦模块依赖
    • 事件系统使代码更容易维护

第12章 游戏服务器自动化测试

  1. 游戏服务器自动化测试的重要性

    • 单元测试使代码更简洁
    • 单元测试保证方法的代码正确性
    • 自动化测试保证代码重构的安全性
  2. 游戏服务器自动化测试的实现

    TosNG是一款应用于 Java 开发的优秀的测试框架,它以 Junit 上借监了很多特性,号称“第二代单元测试框架”。相比Junit来说,它加人了一些新的功能,更加强大,使用更加方便,正所谓青出于蓝而胜于蓝。TestNG 的特点如下。

    • 基于注解。
    • 在具有各种可用策略的任意大线程池中运行测试(比如一个方法一个线程或一个 测试类一个线程等)。
    • 运行的测试行为都是线程安全的。
    • 灵活的测试配置,可以通过 xml 配置文件制订不同的测试策略。
    • 支持数据驱动测试(使用 @DataProvider)。
    • 支持给测试方法传递参数。
    • 强大的执行模型。
    • 被很多工具和插件支持,比如 Eclipse、IDEA、 Maven 等。
    • 集成 BeanShell ( BeanShell 是一个小型联人式 Java 源码解释器,具有对象脚本语言特性,能够动态地执行标准 Java 语法),扩展性强。
    • 默认自带运行时和日志的JDK 功能。

模块六 实例

第13章 服务器开发实例——世界聊天系统

  1. 单服世界聊天系统实现 添加客户端命令 服务器实现消息转发 单服世界聊天测试
  2. 分布式世界聊天系统实现 分布式世界聊天系统设计 创建单独的聊天项目  实现聊天消息的发布与转发 分布式世界聊天服务测试