当前位置: 永利棋牌 > 小说 > 正文

浅析分布式系统,经典游戏服务器端架构概述

时间:2019-11-26 17:03来源:小说
全服分线模型 一. 模型描述 架构的分析模型 一. 讨论的背景 现代电子游戏,基本上都会使用一定的网络功能。从验证正版,到多人交互等等,都需要架设一些专用的服务器,以及编写

全服分线模型
一. 模型描述

架构的分析模型
一. 讨论的背景
现代电子游戏,基本上都会使用一定的网络功能。从验证正版,到多人交互等等,都需要架设一些专用的服务器,以及编写在服务器上的程序。因此,游戏服务器端软件的架构,本质上也是游戏服务器这个特定领域的软件架构。
软件架构的分析,可以通过不同的层面入手。比较经典的软件架构描述,包含了以下几种架构:
运行时架构——这种架构关心如何解决运行效率问题,通常以程序进程图、数据流图为表达方式。在大多数开发团队的架构设计文档中,都会包含运行时架构,说明这是一种非常重要的设计方面。这种架构也会显著的影响软件代码的开发效率和部署效率。本文主要讨论的是这种架构。

以下内容都是腾讯WeTest《浅析分布式系统》博文的摘抄,说是摘抄其实跟原文照搬差不了多少,原文地址腾讯WeTest浅析分布式系统

由于多进程服务器模型的发展,游戏开发者们首先发现,由于游戏业务的特点,那些需要持久化的数据,一般都是玩家的存档,以及一些游戏本身需要用的,在运行期只读的数据。这对于存储进程的分布,提供了非常有利的条件。于是玩家数据可以存放于同一个集群中,可以不再和游戏服务器绑定在一起,因为登录的时候便可根据玩家的ID去存储集群中定位想要存取的存储进程。

逻辑架构——这种架构关心软件代码之间的关系,主要目的是为了提高软件应对需求变更的便利性。人们往往会以类图、模块图来表达这种架构。这种架构设计在需要长期运营和重用性高的项目中,有至关重要的作用。因为软件的可扩展性和可重用度基本是由这个方面的设计决定的。特别是在游戏领域,需求变更的频繁程度,在多个互联网产业领域里可以说是最高的。本文会涉及一部分这种架构的内容,但不是本文的讨论重点。

1. 什么是分布式系统

要理解这个问题可以从它的适用场景入手,一个非常适用于高承载量互联网业务的系统。什么叫高承载量,简单地可以理解为就是业务有非常高的被访问频率,如一个网站或者一个APP或者一网游或视频直播等每天有百万千万甚至亿级别用户访问。
当一个互联网业务架构不能够满足高承载量的需求时,对于用户的感受就是:网页打开慢,游戏或者视频卡顿。

图片 1

物理架构——关心软件如何部署,以机房、服务器、网络设备为主要描述对象。

2. 分布式系统的特性

一个分布式系统应该具备以下几点特性:
高吞吐、高并发、低延迟和负载均衡。

  • 高吞吐
    高吞吐指的是业务系统可以同时承载大量的用户,关注的是整个系统能同时服务的用户数,它们由多台服务器协作一起完成。

  • 高并发
    高并发指的是业务系统在承载海量用户的时候,每台服务器程序都能够尽量多的同时处理多个任务。

  • 低延迟
    低延迟指的是业务系统在面对海量用户时仍能够很快的返回计算结果。
    如果业务系统架构不合理,当有大量用户同时访问系统时很可能造成请求排队,当排队长度过长,还会导致系统内存耗尽、带宽被占满等问题。如果因为排队失败在采取重试的策略,则会进一步增加延迟。
    一个合理的分布式系统会采用将用户请求进行分拣和分发的做法,尽快的让更多的服务器来处理用户的请求,但如果分发的层次过多又会增加系统的延迟。

  • 负载均衡
    互联网业务面向整个互联网的用户,他们位于不同时区,不同地理位置,所使用的网络线路也不一样,考虑到这种情况,分布式系统就需要在不同的地理位置和网络线路中部署服务器。这些不同位置的服务器依然属于一个分布式系统,他们同时处理不同用户相同的业务请求,这即实现了负载均衡。

[图-全区分线模型]
二. 存储的挑战

数据架构——关心软件涉及的数据结构的设计,对于数据分析挖掘,多系统协作有较大的意义。

3. 分布式系统如何承载海量业务

  • 网站业务利用DNS多个IP的A记录提高业务承载量
    这里不谈DNS整个分布式系统的工作方式,只说下DNS配置A记录时指定多个IP地址,当用户请求某网站的IP地址时,随机解析一个IP给他,另一用户在去解析这一网站,DNS随机解析另外的IP给这一用户,这样具备不同IP地址的服务器就可以共同承载同一网站的业务。
    但是上面这种方式,在很多互联网业务中并不可行。如需要用户进行登录的业务,用户在登录某一服务器后发起多个请求,如果把这些请求随机转发到不同的服务器上,那用户的登录状态会丢失,造成一些请求处理失败。这时就要考虑将用户的cookie或者登录凭据转发给其它服务器,以实现会话保持效果。

  • 分布式系统逻辑
    典型的三层式分布式系统逻辑包括:接入层、逻辑层、数据层。

图片 2

分布式系统逻辑图

  • 分布式业务架构示意图

图片 3

分布式业务架构

在实际的业务架构中,分布式系统会设计成多个层次的,为了把请求交给正确的进程处理,需要设计很多专门用于转发请求的进程和服务器,这些进程常以Proxy或者Router命名。这些代理很多时候是通过TCP来连接前端和后端,但是tcp有故障后不容易恢复的问题且其网络编程复杂,所以有了更好的进程间通讯机制----消息队列。

为了让分层模式(代理、路由)变得高效简单,又采用了很多相关技术。如:

  • 并发模型
    计算机中大部分的程序都会处理同时到达的多个请求。程序会同时获得多个输入,需要返回多个输出。在这个处理过程中,还会碰到等待和阻塞的情况,如程序要等待数据库处理完成,等待向另一个进程请求结果等。如果把这些请求一个挨着一个地处理,这些空闲的等待时间将白白浪费,造成用户的响应延迟增加,系统的吞吐量极度下降。所以计算机程序会使用并发模型,同时处理多个请求,常用的并发模型技术有2种。

    • 多线程
      多线程的代码,每个线程中的代码是按先后顺序执行的,但由于同时运行着多个线程,需要给很多数据加锁,避免对同一个数据的处理逻辑出错。但这些锁又可能导致线程出现死锁。

      多线程的不足:在多线程模型中,线程反复切换会导致不必要的开销,每个线程都需要一个独立的栈空间,在多线程并行运行的时候,这些栈的数据可能需要来回拷贝,需要额外消耗CPU,同时线程越多占用的内存空间也越多。异步回调模型可以解决这些问题。

    • 异步回调模型
      异步回调基于非阻塞的I/O操作实现,在代码中就表现为在调用读写函数的时候不会卡在那一句函数调用而是立即返回有无数据的结果。Linux系统中的epoll技术,就是利用底层内核的机制,可以快速查找到有数据可以读写的连接、文件。由于每个操作都是非阻塞的,所以一个进程就可以处理大量并发的请求。也正因为只有一个进程,所以不会出现多线程中两个函数的语句交错执行需要数据锁以保证执行不会出错。
      异步非阻塞技术,没有了数据锁,也没有多线程间频繁切换的额外开销,所以它很适合对吞吐量和并发数有较高要求的系统。

  • 缓冲技术
    缓冲技术可以降低业务延迟。

  • 适用场景
    如一个网站如果每个HTTP请求都需要去读写mysql数据库,数据库很快就会回为连接数占满而出现停止响应,网站就会出现人一多就卡死的情况。一般情况下数据库允许的最大连接数要远小于web应用的并发连接数的。为了减少对数据库的连接和访问,可以将数据库中查询的结果存放到更快的设备上,如果没有相关联的修改,就可以直接用缓存去响应客户端请求。

  • 最典型的缓冲系统
    Memcache是最典型的web应用缓冲系统。当用户请求过来时,先检查Memcache中是否有缓存,如果有则用缓存去响应请求,如果没有则去后续查询然后回应请求并会写入Memcache中,下次有同样的请求过来时就直接使用Memcache中的缓存响应请求。

图片 4

Memcache缓冲系统示意图

Memcache不能直接组建一个集群系统,如果一个Memcache不够用,就要手工用代码去分配,哪些数据应该去哪个Memcache进程。

Memcache的每笔请求,都要经过网络传输,才能去拉取内存中的数据,而没有将请求者本身的内存利用起来。为了解决这个问题就可以利用LRU算法,把数据放在一个哈希表结构的堆内存中。

因为Memcache不支持集群,为了又能将缓存分布到不同的机器上,因此出现了读写分离技术,即缓存每次写都写到多个缓冲进程中去,但是读的时候可以读取任何一个进程。读写分离的方案很适用于有明显读写不平衡的业务数据。

对于读写没有明显不平衡的业务系统如:社区、游戏,读写分离就不在适用于它们。在这些系统中要同时将请求方本地内存和远端进程的内存缓存结合起来使用,就需要使用到“一致性哈希算法”,以实现一个数据不在同时写往多个缓存进程上,而是按一定规律分布在多个进程上。这样做的好处是当某一个进程失效时,不会影响整个集群中所有的缓存数据,其它缓存进程不用修改缓存记录。

  • 存储技术
    分布式系统有一个著名的CAP原则:

CAP原则又称CAP定理,指的是在一个分布式系统中, Consistency(一致性)、 Availability(可用性)、Partition tolerance(分区容错性),三者不可得兼。---------百度百科

图片 5

分布式系统CAP理论示意图

在很多互联网业务中并不需要很复杂的关系型数据库,数据表来存储数据,对于索引也只是需要能够根据主索引搜索即可, 所以就产生了NoSQL数据库,早期的有MangoDB,现在比较流行的是Redis。

NoSQL相较于SQL型数据库具有更快、承载量更大的优势。它们只需要按照一条索引来检索和写入数据,利用分布式进行部署,在部署时我们可以按这条主索引来定义数据存放的进程(服务器)。这样就可以很方便的将数据存放在不同的服务器上,形成分布式部署。

需求:扩容和容灾在全区分线模型下,游戏玩家可以随便选择任何一个服务器登录,自己的帐号数据都可以提取出来玩。这种显然比每个服务器重新“练”一个号要省事的多。而且这样也可以和朋友们约定去一个负载较低的服务器一起玩,而不用苦苦等待某一个特定的服务器变得空闲。然而,这些好处所需要付出的代价,是在存储层的分布式设计。这种设计有一个最需要解决的问题,就是游戏服务器系统的扩容和容灾。
从模型上说,扩容是加入新的服务器,容灾是减掉失效的服务器。这两个操作在无状态的服务器进程上操作,都只是更新一下连接配置表,然后重启一下即可。但是,由于游戏存在大量的状态,包括运行时内存中的状态,以及持久化的存储状态,这就让扩容和容灾需要更多的处理才能成功。
最普通的情况下,在扩容和容灾的时候,首先需要通知所有玩家下线,把内存中的状态数据写入持久化数据进程;然后根据需要的配置,把持久化数据重新“搬迁”到新的变化后的服务器上。——如果一个游戏有几千万用户,这样的数据搬迁将会耗时非常长,玩家也被迫等待很长的时间才能重新登录游戏。所以在这种模型下,对于数据存储的设计是最关键的地方。

开发架构——关心软件开发库之间的关系,以及版本管理、开发工具、编译构建的设计,主要为了提高多人协作开发,以及复杂软件库引用的开发效率。现在流行的集成构建系统就是一种开发架构的理论。

4. 分布式系统在管理上存在的问题

  • 硬件故障率
    拥有众多机器的分布式系统比只有一台或者少量机器的系统,出现硬件故障的机率要高得多。所以分布式系统软件在架构时要考虑到硬件故障的情况,在故障发生时,不要出现一台服务器硬件故障导致事个服务器集群工作不正常。

分布式系统中网络线路出现故障的机率也很高,这时要让系统软件具备自我维护和冗余的功能。

  • 资源利用率
    分布式系统中如果硬件资源不够用了,可以对硬件进行扩容,增加更多的服务器,但软件层面的扩容要复杂得多,可能需要停掉整个集群,然后修改各种配置才能重新启动集群。

对于线上业务进行扩容,有可能会造成用户数据丢失或者错误。所以线上扩容适用于无状态的服务上,我们都知道HTTP就是属于无状态的连接,所以web服务一般可以进行在线扩容。但对于类似游戏这种有状态的服务几乎是不可能进行在线扩容的。

当硬件资源处于闲置状态时,分布式系统还应该对硬件资源进行缩容,将这部分资源放入其它的业务系统中。

  • 软件服务内容更新
    为了修改业务系统中的bug,或者发布新的功能等操作,要对软件进行不断的迭代升级。 在只有一台或少量机器的业务系统中还好办,只需要把软件包拷贝过去,然后安装配置即可,但在分布式系统中机器数量众多,所以服务端软件需要开发相应的软件更新,版本升级的功能,预先对于配置文件、命令行参数、系统变量的使用做一些规划,让安装部署的工具运行更快更可靠。

软件版本升级,有时候还涉及到数据格式的更改,如修改数据表结构,所以软件在架构之初就应该考虑到这些,做些预设准备。

客户端程序的升级,有时候会涉及到跟服务器的通信协议改变的问题,而一般客户端升级不会和服务器同步,这就会造成一个问题,网络中需要为不同版本的客户端部署不同的服务端系统。为了避免同时维护多套服务器系统,在软件架构之初时应该使用“版本兼容”的协议定义方式。

  • 数据统计
    分布式系统的日志数据一般需要集中到一起,统一进行分析统计。当分布式系统规模越来越大时,这个日志数据的量会变得非常大,统计工作非常消耗计算机资源。

    经典的分布式统计模型有Google的Map Reduce模型,这种模型可以利用大量服务器进行统计工作,但实际使用中由于它统计的数据格式与常见的SQL差别很大,所以最后往往还需要借助MySQL进行更细层面的统计。

图片 6

Google Map Reduce的示意图

分区分服的关系型数据库我们常常会使用MySQL这种关系型数据库来存放游戏数据。由于SQL能够表述非常复杂的数据操作,这对于游戏数据的一些后期处理有非常好的支持:如客服需要发奖励,需要撤销某些错误的运营数据,需要封停某些特征的玩家……但是,分布式数据库也是最难做分布的。一般来说我们都需要通过某一主键字段做分库和分表;而另外一些如唯一关键字等数据,就需要一些技巧来处理。

二. 游戏服务器架构的要素
服务器端软件的本质,是一个会长期运行的程序,并且它还要服务于多个不定时,不定地点的网络请求。所以这类软件的特点是要非常关注稳定性和性能。这类程序如果需要多个协作来提高承载能力,则还要关注部署和扩容的便利性;同时,还需要考虑如何实现某种程度容灾需求。由于多进程协同工作,也带来了开发的复杂度,这也是需要关注的问题。
功能约束,是架构设计决定性因素。一个万能的架构,必定是无能的架构。一个优秀的架构,则是正好把握了对应业务领域的核心功能产生的。游戏领域的功能特征,于服务器端系统来说,非常明显的表现为几个功能的需求:
对于游戏数据和玩家数据的存储

5. 解决分布式系统管理性问题的基本手段

  • 目录服务
    一个自动化程度高的分布式系统会动态保存系统中的进程状态,如自己负责的模块、自己的负载情况、对某些数据的掌握等,还有进程和其它相关进程的对应关系,如IP地址和端口。这样一来整个分布式系统才能让程序自己去做容灾和负载均衡。这个自动的过程就依赖于目录服务。

一个目录服务是用来记录集群中运行的进程的状态的。集群中的进程会自动和目录服务关联,这样系统在容灾、扩容、负载均衡时可以自动根据目录服务里的数据来调整请求的目的地,从而绕开故障机器,连接新的服务器。

图片 7

目录服务示意图

zookeeper是用来实现目录服务的开源软件。目录服务需要进行集群部署以防单点故障导致整个分布式系统工作异常。zookeeper可以启动奇数个进程,以组成一个集群。zookeeper的数据存储结构,是一个类似文件目录的树状系统,所以需要利用它的功能,把每个进程都绑定到其中一个分支上,通过检查这些分支来进行请求的转发,还可以在这些分支上标记负载状态,以实现负载均衡。

  • 消息队列服务
    计算机系统中两个进程要跨机器通讯,需要用到tcp/udp协议,如果直接使用网络API去编写跨进程的程序,需要写大量底层的socket代码,需要处理如何找到交互数据的进程,如何保障数据包不至于丢失,如果通讯的对方进程挂了,或者进程要重启应该如何处理,这些问题在程序开发时都要考虑到。

分布式系统中进程间更有效的通讯模型是消息队列模型。这一模型就是把进程间的交互,抽象成对一个个消息的处理,这些消息本身都有一些队列,也就是管道来对消息进行缓存,每个进程可以访问一个或者多个队列,从里面读取消息(消费)或写入消息(生产)。消息本身的路由,是由存放的队列决定的,这样就把复杂的路由问题,变成了如何管理静态的队列的问题。

  • 事务系统
    分布式系统中的一个事务可能分布在不同的进程上,任何一个进程都可能出现故障,要在分布式系统上解决事务问题,必须有两个核心工具:一个是稳定的状态存储系统,另一个是方便可靠的广播系统。

一个事务的处理过程都必须在整个集群中可见,需要将事务处理每步的状态都写到目录服务上。

  • 自动部署工具
    分布式系统最大的需求,是在运行时进行服务容量的变更:扩容或者缩容。而在分布式系统中某些节点故障的时候,需要新的节点来恢复工作。在分布式系统中,一般采用池的方式来管理服务,在有需要的时候将某服务器在不同的服务间进行转换。。

分布式系统中服务的变化需要用到自动的软件部署工具,如Chef,这一可编程的通用部署系统,比rpm更简便。

图片 8

Chef工作原理示意图

Docker也具备强大的自动部署能力,下图为Docker的原理示意图:

图片 9

Docker原理示意图

  • 日志服务
    服务器端的日志是开发测试,排除BUG,了解软件运行情况非常有用的工具。现代的分布式系统中日志会有一些标准化的规范:
    • 日志必须是一行一行的。
    • 每行日志都应该有一些统一的头部。
    • 日志的输出应该是分等级的(Debug、info、warn、error、fatal)。
    • 日志的头部应该有一些字段可以用于缩小日志查找范围,如用户ID、IP等(日志染色)。
    • 日志还应该具有回滚功能,保持固定大小的多个文件。

图片 10

日志染色

在开源界有名为log4x的日志家族,最为出名的是log4j日志组件库。

  • 日志收集
    在分布式系统中需要有一个系统专门用来收集各服务器上的日志文件,对它们进行统一集中管理,分析并产生预警信息,从而实现对整个分布式系统运行状况的监控。由于日志文件众多,一般会采用分布式文件系统来进行存放源源不断到达的日志,这些日志一般通过UDP协议发送过来。然后在这个系统中还有一个类似Map Reduce的架构以实现对海量日志信息的快速分拣及预警。下图为常用的分布式系统中日志服务的架构示意图:

图片 11

日志服务架构示意图

图片 12

对玩家客户端进行数据广播

6. 分布式系统给开发带来的挑战及应对

分布式系统软件开发除了满足业务需求的功能外,还需要一些功能来让多进程的系统稳定可靠地运行,这些功能的实现可以交由微服务框架来完成。

现在流行的微服务框架有EJB(企业JavaBean)、WebService。微服务框架包含了服务进程之间通讯所涉及的消息的路由、编码解码、服务状态的读写等,在开发分布式系统软件时候使用微服务框架可以简化这一过程。 WebService则是把复杂的路由、编解码等操作简化成常见的一次HTTP操作。

分布式系统复杂之处就在于需要把容灾、扩容、负载均衡等功能都融合到跨进程调用里。所以使用一套通用的代码来为所有的跨进程通讯,统一的实现容灾、扩容、负载均衡、过载保护、状态缓存命中等非功能性需求,可以大大简化整个分布式系统的复杂性。

微服务框架在路由阶段会对整个集群所有节点的状态进行观察,如哪些地址上运行了哪些服务的进程,以及这些服务进程的负载如何,是否可用,然后对于有状态的服务,还会使用一致性哈希算法,去尽量试图提高缓存的命中率。当集群中的节点状态发生变化的时候,微服务框架下的所有节点都能尽快的获得这个变化的情况,重新规划服务路由方向,从而实现自动化的路由选择,避开那些负载过高或失效的节点。

  • 异步编程工具
    为了解决回调函数对于代码可读性的破坏作用,可以采用协程来进行改进,所谓的协程类似于多线程,但区别在于协程不会同时运行,它只是在需要阻塞的地方,用Yield()切换出去执行其他协程,然后当阻塞结束后,用Resume()回到刚刚切换的位置继续往下执行。

Future/Promise模型也是用于改善回调函数的写法,这种写法的基本思路是”一次性把所有回调写到一起”。

lamda模型是另一种改善回调函数的方法,lamda意味着闭包。

  • 云服务模型
    现在常用的云服务模型有三种:IaaS、PaaS、SaaS。
    在分布式系统中要集中管理被不同的网络和硬件切割成小块的计算资源是比较难的。
    随着虚拟化技术的发展,可以把被分割的计算单元,更智能的统一起来,最常见的就是IaaS技术,当我们可以用一个服务器硬件运行多个虚拟的服务器操作系统时,需要维护的硬件数量就会成倍下降。而PaaS技术可以为某一种特定的编程模型,统一的进行系统运行环境的部署维护,而不在需要一台台服务器去安装系统去部署应用软件。

随着业务模型成熟到可以抽象为一些固定的软件时,分布式系统会变得更加易用,计算能力不再是代码和库,而是一个个通过网络提供服务的云---SaaS,这样使用者只需要申请一个接口,填上预期的容量额度就能直接使用了。

[图-分表分库]
以玩家ID作为分表分库是一个非常自然的选择,但是这种方案,往往需要在逻辑代码中,对玩家数据按照自定义的规则,做存储进程的选择。但是如果发现这个分表分库的算法(原则)不符合需求,就需要把大量的数据做搬迁。如上图是按玩家ID做奇偶规则分布到两个表中,一旦需要增加第三台服务器,数据存储的目的服务器编号就变成了id%3,这样就需要把好多数据需要从原来的第一、二台数据库中拷贝出来,非常麻烦。
有的开发者会预先建立几十个表(如120个表=2x3x4x5),一开始是全部都放在一个服务器上,然后在增加数据库服务器的时候,把对应的整个表搬迁出来。这样能减轻在搬迁数据的时候造成的复杂度,但还是需要搬迁数据的。最后如果与建立的表还是放不下了,依然还是需要很复杂和耗时的重新拷贝数据。

把一部分游戏逻辑在服务器上运算,便于游戏更新内容,以及防止外挂。

7. 分布式系统问题的解决方式汇总

图片 13

分布式系统问题的解决方式

NoSQL在很多开发者绞尽脑汁折腾mysql的时候,NoSQL横空出世了。实际上在很早,目录型存储进程就在DNS等特定领域默默工作了。NoSQL系统最大的好处正是关系型数据库最大的弱点——分布。
由于主键只有一个,因此内置的分布功能使用起来非常简便。而且游戏玩家数据,绝大多数的操作都是根据主键来读写的。“自古以来”游戏就有“SL大法”之称,其本质就是对存档数据的简单读、写。在网游的早期版本MUD游戏时代,玩家存档只是简单的放在硬盘的文件上,文件名就是玩家的ID。这些,都说明了游戏中的玩家数据,其读写都是有明显约束的——玩家ID。这和NoSQL简直是天作之合。

针对以上的需求特征,在服务器端软件开发上,我们往往会关注软件对电脑内存和CPU的使用,以求在特定业务代码下,能尽量满足承载量和响应延迟的需求。最基本的做法就是“时空转换”,用各种缓存的方式来开发程序,以求在CPU时间和内存空间上取得合适的平衡。在CPU和内存之上,是另外一个约束因素:网卡。网络带宽直接限制了服务器的处理能力,所以游戏服务器架构也必定要考虑这个因素。
对于游戏服务器架构设计来说,最重要的是利用游戏产品的需求约束,从而优化出对此特定功能最合适的“时-空”架构。并且最小化对网络带宽的占用。

8. 总结

腾讯WeTest的这篇干货长文,对于接触Linux生态圈还不长的我来说,实在是干货满满。对于从整体上理解分布式系统很有帮助,所以近乎原版地将它摘抄在此,值得多读几次加深理解。

图片 14

图片 15

[图-NoSQL]
NoSQL的确是非常适合用来存储游戏数据。特别是有些服务器如Redis还带有丰富的字段值类型。但是,NoSQL本身往往不带很复杂的容灾热备机制,这是需要额外注意的。而且NoSQL的访问延迟虽然比关系型数据库快很多,但是毕竟要经过一层网络。这对于那些发展了很多年的ORM库来说,缺乏了一个本地缓存的功能。这就导致了NoSQL还不能简单的取代掉所有服务器上的“状态”。而这些正是分布式缓存所希望达成的目标。

[图-游戏服务器的分析模型]
三. 核心的三个架构
基于上述的分析模型,对于游戏服务端架构,最重要的三个部分就是,如何使用CPU、内存、网卡的设计:
内存架构:主要决定服务器如何使用内存,以保证尽量少的内存泄漏的可能,以及最大化利用服务器端内存来提高承载量,降低服务延迟。

分布式缓存在业界用的比较多的缓存系统有memcached,开发者有时候也会使用诸如hibernate这样的ROM库提供的cache功能。但是这些缓存系统在使用上往往会有一些限制,最主要的限制是“无法分布式使用”,也就是说缓存系统本身成为性能瓶颈后,就没有办法扩容了。或者在容灾的情景下,缓存系统往往容易变成致命的单点。
Orcale公司有一款叫Coherence的产品,就是一种能很好解决以上问题的“能分布式使用”的产品。他利用局域网的组播功能来做节点间的状态同步,同时采用节点互相备份的方案来分布数据。这款产品还使用Map接口来提供功能。这让整个缓存系统既使用简单又功能强大。更重要的是,它能让用户对于数据的存取特性做配置,从而提供用户可接受的数据风险下的更高性能——本地缓存。
由于游戏的数据,真正变化频繁的,往往不是“关键”的需要安全保障数据,如玩家的位置、玩家在某次战斗中的HP、子弹怪物的位置等等。而那些非常重要的数据,如等级、装备,又变化的不频繁。这就给了开发者针对数据特性做优化以很大的空间。而且,大部分数据的读、写频率都有典型的不平衡状态。普遍游戏数据都是读多写少。少量的日志、上报数据是写多、几乎不读。
对于缓存系统来说,有三个重要的因数决定了在游戏开发中的地位。首先是其使用的便利性,因为游戏的数据结构变化非常频繁,如果要很繁琐的配置数据结构,则不会适合游戏开发;其次是要能提供近似本地内存的性能,由于游戏服务器逻辑基本上都是在频繁的读写某一特定数据块,如玩家位置、经验、HP等等,而且游戏对于处理延迟也有较高的需求(WEB应用在2秒以内都可以忍受,游戏则要求最好能在20ms以内完成)。要能同时满足这两点,是不太容易的。

调度架构:设计如何使用进程、线程、协程这些对于CPU调度的方案。选择同步、异步等不同的编程模型,以提高服务器的稳定性和承载量。同时也要考虑对于开发带来的复杂度问题。现在出现的虚拟化技术,如虚拟机、Docker、云服务器等,都为调度架构提供了更多的选择。

图片 16

通信模式:决定使用何种方式通讯。网络通讯包含有传输层的选择,如TCP/UDP;据表达层的选择,如定义协议;以及应用层的接口设计,如消息队列、事件分发、远程调用等。

[图-分布式缓存]

本文的讨论,也主要是集中于对以上三个架构的分析。
四. 游戏服务器模型的进化历程
最早的游戏服务器是比较简单的,如UO《网络创世纪》的服务端一张3.5寸软盘就能存下。基本上只是一个广播和存储文件的服务器程序。后来由于国内的外挂、盗版流行,各游戏厂商开始以MUD为模型,建立主要运行逻辑在服务器端的架构。这种架构在MMORPG类产品的不断更新中发扬光大,从而出现了以地图、视野等分布要素设计的分布式游戏服务器。而在另外一个领域,休闲游戏,天然的需要集中超高的在线用户,所以全区型架构开始出现。现代的游戏服务器架构,基本上都希望能结合承载量和扩展性的有点来设计,从而形成了更加丰富多样的形态。本文的讨论主要是选取这些比较典型的游戏服务器模型,分析其底层各种选择的优点和缺点,希望能探讨出更具广泛性,更高开发效率的服务器模型。
分服模型
一. 模型描述

集成缓存的NoSQL根据上面的描述,读者应该也会想到,如果数据库系统,或者叫持久化系统,自带了缓存,是否更好呢?这样确实是会更好的,而且特别是对于NOSQL系统来说,能以一些内部的算法策略,来降低前端逻辑开发的复杂程度。一般来说,我们需要对集成缓存的NOSQL系统有以下几方面的需求:首先是冷热数据自动交换,就是对于常用数据有算法来判别其冷热,然后换入到内存以提高存取性;其次是分布式扩容和容灾功能,由于NOSQL是可以知道数据的主关键字的,所以自然就可以自动的去划分数据所在的分段,从而可以自动化的寻找到目标存储位置来做操作;最后是数据导出功能,由于NOSQL支持的查询索引只能是主键,对于很多后台游戏操作来说是不够的,所以一定要能够到处到传统的SQL服务器上去。
在这方面,有很多产品都做过一定的尝试,比如在redis或者MangoDB上做插件修改,或者以ORM系统封装MySQL以试图构造这种系统等等。

分服模型是游戏服务器中最典型,也是历久最悠久的模型。其特征是游戏服务器是一个个单独的世界。每个服务器的帐号是独立的,而且只用同一服务器的帐号才能产生线上交互。在早期服务器的承载量达到上限的时候,游戏开发者就通过架设更多的服务器来解决。这样提供了很多个游戏的“平行世界”,让游戏中的人人之间的比较,产生了更多的空间。所以后来以服务器的开放、合并形成了一套成熟的运营手段。一个技术上的选择最后导致了游戏运营方式的模式,是一个非常有趣的现象。

图片 17

图片 18

编辑:小说 本文来源:浅析分布式系统,经典游戏服务器端架构概述

关键词: