新的工程模式 完整的数据集中式 2

其实在一个MMORPG的项目中,经常会遇到这种问题,服务器作为主控方,掌握了绝大部分数据的修改权利,通常对于不同类型的数据包,需要专门定义协议,然后在数据改变的时候同步给客户端(在《武林至尊》中,我们把这种数据主要分为资产和FOV数据两种)。在客户端的逻辑模块,根据服务器发过来的消息包修改本地数据。而客户端的其他模块(UI,渲染)需要定期扫描客户端逻辑模块的数据变化(也可以由逻辑模块主动通知),然后再将部分数据转换为自己模块内部的本地数据(脚本数据,渲染数据)。

                                                               Image

服务器端掌管着数千个客户端需要得到的数据集,如果在上图中,把客户端本身也看出一个控制器,我们可以想象这样一种抽象结构,主要的数据都集中在服务器端,上千个客户端就像控制器一样联接在数据中心上,通过网络来存取数据。在客户端本地,它自己又是一个比较小的数据中心,它的每个功能模块连接在数据中心上,通过函数调用来存取数据。

在一个C/S结构的项目中,数据的变化应该主要包含几种方式:

  1. 数据在A端被修改,B端需要知道这种变化
  2. 数据在A端被修改,B端不需要知道这种变化
  3. 数据在A端和B端同时被修改(不是严格意义上的同时)。双方互不关心变化
  4. 数据在A端和B端同时被修改(不是严格意义上的同时)。以其中一端为主,另外一端需要通过各种机制进行数据纠正。
  5. 数据在A端,B端定期或事件型触发对数据的请求。

无论是哪一种情况,数据都可以归纳为3种类型。

  1. 数据有原稿和拷贝,原稿的拥有者可以修改和读取最终的数据结果,拷贝方的拥有者只能读取结果,无法修改结果。
  2. 数据有两份,分别由拥有者读取和修改,双方之间在一定时间内互不影响。
  3. 数据只有一份,拥有者都可以进行修改和读取。
其中2,3情况在客户端设计时经常会遇到,1情况则在服务器设计时大量出现。

让我们来考虑一种新的设计模式 - 包含了网络端的数据集中式。

首先要定义数据层的定位和功能

数据层能够定义数据,并且定义数据的类型,是原稿还是拷贝。对所有数据,数据层都应该提供数据在最小粒度上的置脏功能,但对于数据的划分粒度,则应该根据业务逻辑来决定。例如背包数据,可以认为所有数据是一个完整整体(最终会导致每次背包的数据变化是全量更新),也可以认为一个背包格的数据是一个整体(增量更新)。粒度的划分难以建立统一的标准,通常要考虑到数据量的大小和数据本身的各种特性。

      数据层应该为数据的最小粒度单元提供读写功能,当然也应该为最小单元之上的整合单元提供一些辅助型的读写功能,否则最终代码的实现上会非常繁琐。

      数据脏标志的写功能,不应该暴露到数据层之外,避免在上层应用上无意间调用。脏标准的读取功能是否暴露可以根据实际需求来决定。如果认为所有数据的变化都应该由数据层主动通知给其他模块的话,就无需暴露。如果有由外围模块扫描数据的情况,则需要暴露。

     如果要保留脏标准的读取功能,则应该暴露数据变化的次数。之所以要这样要求,是因为无法保证只有一个模块会关心一个对应的数据,例如A B模块同时关心一个数据,那么数据只要一脏,A B就无法停止更新了,A在读取数据时不能将数据改为不脏,B也同样不能这样做。

     对于数据层来说,最重要的功能应该是如何管理数据的原稿和拷贝。考虑到原稿和拷贝通常在不同的网络终端上,数据层应该提供从原稿方将数据变化同步到拷贝方的功能。这种同步和解析的执行应该是自动和透明的,无需上层关心。例如可以将不同的数据设置不同的标志,数据层定期扫描原稿方数据的变化标准,如果发现有变化的数据,就将这些数据统一压到协议中,然后一次性同步给拷贝方。

     细化上述设计的话,主要有两点需要扩展。

首先数据的同步应该分为不同的频道,每个频道有流量控制和频率控制,以免数据的变化过快时导致模型的崩溃。每个数据在定义时应该指定所属的频道,一些控制型的数据可以注册到高频率的频道中(减小网络延时导致的体验感问题),一些数据量大的资产数据,可以注册到低频率的频道中。

其次数据的同步流应该一种自解释功能,或者说应该提供一个通用协议,可以把任意数量的,不同类型的数据按任意顺序组织起来,一次型同步给数据的拷贝方。类似于一个文件流的概念,先有一个文件头,后面是文件的具体内容。这样可以让数据层在每次扫描时,只对一个拷贝方放送少量的网络包,避免出现大量小包,导致TCP/IP头占用大量流量的问题。

 

--未完待续

posted @ 2011-02-04 10:56  BadKeeper  阅读(379)  评论(0编辑  收藏  举报