zoukankan      html  css  js  c++  java
  • 《架构之美》阅读笔记3

    问题、品质需求

    1. 系统的伸缩性需求。如大型在线游戏,需要满足大量用户。在线用户数量短时间内可能有很大的变化。 
    这其中隐含的需求是: 
    多用户 
    并行 
    分布式系统,系统运行在多台机器上 
    高可扩展性(用于加入新的故事情节,意味着新的代码) 
    高稳定性、可靠性(一个用户崩溃,不影响其他用户) 
    数据一致性(多个用户看到同一个东西的状态应该是一样的) 
    2. 架构设计目标 
    即另外一个需求,对其他开发者部署出一个简单的编程模型,程序员可以将系统视为一个单机开发环境。 
    隐藏分布式和并发是一件困难的事。需要一种严格限制的编程模型。 
    典型的游戏服务器开发模型:反应式 
    客户端(游戏机)(生成事件) - 服务端的事件监听器(监听事件,并生成任务) - 此任务可与多个客户端进行交互 
    或者是服务端自己周期性生成任务。 
    这是一种典型的胖客户端机制,适用于游戏和虚拟世界,也适用于J2EE和Web服务的应用。 
    区别另外一种经典的企业级架构: 
    瘦客户端 - 胖客户端 - 更胖的数据库服务器。服务器保存客户端的绝大部分信息,绝大多数真正的工作在服务器上完成。 
    在游戏的软件架构中。不被修改的数据都被放在客户端完成,只有共享的数据才放在服务器,服务器尽量保持简单,减少计算。保持共享事实的最终来源,防止玩家作弊。客户端只访问少量的状态数据,但访问的数据大部分会被改写。 
    而另外一种架构是90%的数据都是只读的,大多数任务会读取大量数据,再修改少量数据。 
    3. 延迟的需求 
    游戏架构要求用户体验好,大的延迟不被接受,甚至牺牲吞吐量换取少的延迟。 
    而企业环境的架构重在吞吐量,管理业务。有一点延迟可以接受。 
    一般情况下,处理拥塞的解决方案: 
    1. 基于地理位置来实现。游戏设计包含不同的游戏区域,每个虚拟区域运行一台服务器,每个区域拥有自我限制功能,当人数过多时,服务拥塞,游戏变慢,趣味性下降,用户就转向更有趣的区域,响应时间就会得到改进。(对于棋牌类游戏,每个房间或区域有人数限制,满的房间可以限制进入) 
    这种开发方法的问题:游戏设计时,需要决定哪些区域放在一台服务器上,而添加新的区域时比较容易,若改动原来的区域,可能需要改动代码,这些都是开发的工作量。 
    2. 分区sharding。一个分区是一个区域的副本,运行在自己的服务器上,独立于其他分区,不同的玩家进入同一个区域的不同副本(分区)。这样的缺点时,不允许不同副本的玩家彼此进行交互。 
    3. Darkstar架构就是克服以上缺点,支持随时伸缩,同时又不要求游戏逻辑受到伸缩影响。支持动态响应负载,而不是放在游戏设计中完成。 

    Darkstar的架构

    DarkStar是由一组服务组成。每个服务定义为一个小的编程接口。这些接口很像经典操作系统的服务,支持对服务端的访问持久存储、调度并执行任务、与游戏的客户端进行通信。 
    这些服务的程序不会受低层实现变更的影响,因为每个服务由一个接口来描述。当接口不变时,一个服务的变更,不会影响其他服务的实现。这是一个"分治"的过程。 
    另外,将基础设施设计为一组服务,可以将这些服务在不同场景下进行不同的组合,更加灵活,复用性强。一组服务可以组成一个Darkstar栈,Darkstar栈中具体包含哪些服务可以由一个配置文件来设置。 

    从宏观结构上来看

    (分层、模块化、通信机制)

    每个Darkstar栈运行在一个服务器上,Darkstar栈就是服务的副本和游戏逻辑的副本。客户端连接到其中一个服务器,与该世界的抽象表示进行交互。

    每个副本可以与客户端独立的交互,不需要处理相同事件。复制主要是用于支持伸缩性。游戏逻辑也不知道其他服务器上的副本。而不同服务器上的副本协作是由Darkstar项目的基础设施完成的。 
    游戏客户端与服务端的通信机制包含两种,一种是直接通信,另外一种是"发布-订阅"模式。 
    Darkstar栈由一组元服务来协调,这是一组网络访问服务,对游戏程序员是不可见的。这些服务支持在线的副本相互协作,共同运营整个游戏。而且副本间相互独立,某副本失效,会发起失效恢复操作。 

    此外,这些Darkstar元服务会跟踪各副本的负载,在需要的时间重新分配负载,或随时添加服务器,增加总体容量。

     

    基本的组件/服务

    对于游戏程序员而言,可见的架构就是栈中包含了一组服务,而4个基本服务是必须的。数据服务、通道服务、客户端会话服务、任务服务。

    数据服务 
    数据存储、数据读取、数据操作。 
    特征:大部分都是持久化数据、数据间静态关系少、很少有复杂查询、需要对延迟进行优化、需要修改的数据多 
    选型:与标准数据库的使用方式有区别、数据库简单的命名策略,编程语言上对对象的引用 
    任务服务 

    用于调度、执行任务。

    任务来源:响应某个事件、或游戏内部逻辑触发的。常见任务的操作包括:从数据服务中读取、修改一些数据,可能会有一些通信、或者生成其他的任务。

    时间限制:执行任务的时间必须很短。配置中可以设置,默认值是100ms。 
    底层特征:Darkstar的底层在尽量的调度最多的任务。但对游戏程序员,因事件只响应一个任务。 
    并行性:客户端产生的任务、服务端响应逻辑的任务是并行执行的。 
    数据竞争:由并行性带来的数据竞争,同步、事务性操作(一个操作要么全部成功,要么回退) 
    通信机制:若任务包含事务操作,通信机制也必须支持事务 
    通信服务、会话服务: 
    登录、认证后建立会话,监听客户端消息,并响应生成任务。会话也负责维持消息的顺序,前一消息未处理完,后一消息就先不提交。这样也让"任务服务"得到了简化。因为任务服务假定其任何时候触发的任务都是并发的。 
    通道服务: 
    一对多的通信机制。客户端之间可以交互,这种方式不能采取让客户端直接通信的方式,虽然这样会减轻服务端的负载,但容易产生作弊行为。所有通道信息都必须经过服务器。 
    这些抽象层不会暴露客户端或服务端的真实端点,这样Darkstar系统能将服务端的通信端点从一个服务器上移到另外一个机器上,同时又不改变客户对通信的感觉。底层的基础设施可以根据需要进行动态调整。 

    任务的可移动性

    要实现负载的动态均衡能力,就应该实现任务的可移动性,从一台机器移到另外一台机器上。这是系统伸缩性的要求和目标。 
    技术要求: 
    1. 任务是由java写成,这样物理机器上运行JVM,任务就可以运行 
    2. 任务数据来源。任务的数据都来自数据服务。而数据服务是所有游戏实例和Darkstar栈所共享的。 
    3. 通信由"会话服务"或"通道"来实现中介。其抽象能力,使得特定的会话由一个服务器移向另外一个服务器。 
    4. 负载的监控。Darkstar元服务的工作,这是网络层面的服务,对程序员不可见,但对Darkstar栈中的服务是可见的。不会影响游戏的逻辑性,而能实现系统的伸缩性。 
    5. 利用伸缩机制来实现系统的高容错能力。由于任务和通信机制是与具体机器无关的,且任务本身也是持久对象,保存在"数据服务"中。若任务中断,等同于事务中断,系统会重新调度不同的机器运行。这样的后果是延迟有点长,但系统的正确性不变。 

    游戏架构的思考、改进

    游戏与虚拟架构的特点: 
    1. 由于此行业的保密性,专用性, 其性能测试,数据指标比较难获取,另外很多偶然性的因素,使得无法对不同的基础设施做比较,对通用基础设施的测试更加困难。 
    2. 很多服务器的架构都是定制的,很少有可复用的基础设施假设,不注重这方面的积累。 
    Darkstar架构是围绕服务器性能做出了很多关键决定。 

    1. Darkstar拒绝在服务器中存放任何重要信息。

    所有生存周期超过一个任务的数据都需要放入"数据服务"中统一管理。这是Darkstar的核心。为什么?因为它能检测数据的并发问题,对游戏程序员隐藏这些细节,让服务器能利用多核架构,并实现整体是伸缩性。

    2. 延迟的分析。

    以上对并行性的处理,会引发一些延迟。将数据放入内存,才能将延迟最小化,是主流观点。

    而采用"数据服务"的方式会影响性能,访问数据会引入一定延迟。但比其他方法会更有竞争力:1)持久化存储可以利用数据库缓存和一致性,尽量减少数据访问延迟。2)将相关联的玩家放到一个服务器上去,也可以利用数据库的标准缓存技术,减少访问和保存持久数据的延迟。(与基于地理位置的技术不同,这部分工作无需放入游戏开发工作中,而是根据运行时进行优化,(类似于编译优化与运行优化))

    3. 可靠性更高。

    利用高并发来弥补持久化存储的延迟损失,方案总体上是更有优势,也更符合未来芯片基础架构发展的方向。另外,持久化"数据服务"将服务器失效而导致的数据丢失减少到了最小。

    4. 简化游戏程序员工作。 
    当同时要求支持伸缩性和减少延迟的开发目标,那么开发者需要编写自己的分布式和多线程基础架构和代码,这对开发者的要求更高,且工作量更大。而Darkstar将所有任务封装到事务中,并在"数据服务"中检测数据冲突,开发者就能享受多线程的好处,又不必在他们的代码中引入锁协议、同步和信号量。 Darkstar提供透明的负载平衡。 

    但是开发者还是需要了解Darkstar的底层并发和分布式实质,需要遵循一定编程模型,尽量利用数据服务的并发性,提升游戏的整体性能。

  • 相关阅读:
    qt 学习(三)消息基础
    qt学习(二)控件
    sqlserver学习_01
    java对文件操作--01
    js 将json字符串转换为json对象的方法解析
    实现动态代理(Java和spring)
    mysql_01_游标的使用
    java实现多文件上传01
    oracle-2_dblink的创建和使用
    sqlserver学习3---sql函数
  • 原文地址:https://www.cnblogs.com/zql-42/p/14336368.html
Copyright © 2011-2022 走看看