请选择 进入手机版 | 继续访问电脑版

NoahFrame

 找回密码
 Register Now
搜索
热搜: redis mysql tutorial
查看: 2671|回复: 0

第九章 NF分布式服务器解决方案--数据追踪与分析

[复制链接]

30

主题

112

帖子

668

积分

Administrator

Rank: 9Rank: 9Rank: 9

积分
668
发表于 2016-12-30 11:23:54 | 显示全部楼层 |阅读模式
NF(https://github.com/ketoo/NoahGameFrame)全称为 NoahFrame/NoahGameFrame。


NF最早为客户端设计,后来随着时代的变化,而为自己又转为服务器开发,故在吸收了众多引擎的优点后(包含Ogre的插件模式&模块化管理机制,Bigworld的数据管理&配置机制,类似MYGUI的接口层次设计),经过多年演化和实践,变成了一套游戏开发J解决方案。方案中包含开源的服务器架构,网络库(站在libevent的肩膀上),和unity3d的demo源码。现在NF已经在多个公司的多个项目中使用,其中包含知名产品 《全民无双》。


关键词


NoahGameFrame/NoahFrame/NF
集群/负载均衡/分布式
网关服务器 GateServer 心跳 多线程/线程池 开源网络框架/模型
一致性hash算法/ConsistentHash
游戏开发中的设计模式/数据结构
Socket Nagle/粘包/开源游戏服务器/ Game Server





所谓的数据追踪技术,特指一些数据流跟踪系统的在一些架构或者环境中引入某种数据的健康那个/记录的技术,这种技术为生产环境提供了强有力的分析和纠错手段。而在NF中,则可以非常轻松的实现类似的技术,可以监控/追踪所有的数据变化(当然必须得是基于NF通用的属性管理模板),简单的我都不知道如何说起这项技术。

数据追踪,首要条件当然是数据监控,数据监控则NF就简单了,因为NF的架构中,任何一个数据都有据可循,任何一个数据都可以给它添加观察者,因此任何一个数据,都能轻而易举的监控。
其实NF的教程2就是一个简单的数据追踪原型(https://github.com/ketoo/NoahGameFrame/tree/master/Tutorial/Tutorial2
则NF中要做到数据追踪,会有如下几个步骤:


1:确认追踪数据目标,其实就是指哪些数据需要关心,以方便我们第二部添加观察者,我们现在假设所有的数据都需要追踪,那么只需则初始化的时候便利所有数据添加观察者即可,那么这一步则可以省略,不过初步还是计划有那么一个追踪模块:

  1. class NFCPropertyTrailModule
  2.     : public NFIPropertyTrailModule
  3. {
  4. public:
  5.     NFCPropertyTrailModule(NFIPluginManager* p)
  6.     {
  7.         pPluginManager = p;
  8.     }
  9.     virtual ~NFCPropertyTrailModule() {};

  10.     virtual bool Init();
  11.     virtual bool Shut();
  12.     virtual bool Execute();
  13.     virtual bool AfterInit();

  14.     virtual void StartTrail(const NFGUID self);
  15.     virtual void EndTrail(const NFGUID self);

  16. protected:

  17.     int LogObjectData(const NFGUID& self);
  18.     int TrailObjectData(const NFGUID& self);

  19.     int OnObjectPropertyEvent(const NFGUID& self, const std::string& strPropertyName, const NFIDataList::TData& oldVar, const NFIDataList::TData& newVar);

  20.     int OnObjectRecordEvent(const NFGUID& self, const RECORD_EVENT_DATA& xEventData, const NFIDataList::TData& oldVar, const NFIDataList::TData& newVar);

  21. private:

  22.     NFIKernelModule* m_pKernelModule;
  23.     NFIElementInfoModule* m_pElementInfoModule;
  24.     NFILogicClassModule* m_pLogicClassModule;
  25.     NFILogModule* m_pLogModule;
  26. };
复制代码



2:添加数据观察者(追踪者),在NF中,很简单的说法就是添加Property/Record回调函数,既然假设所有的数据都需要追踪,那么则需遍历所有Property和Record添加观察者即可:

  1. int NFCPropertyTrailModule::TrailObjectData(const NFGUID& self)
  2. {
  3.     NF_SHARE_PTR<NFIObject> xObject = m_pKernelModule->GetObject(self);
  4.     if (nullptr == xObject)
  5.     {
  6.         return -1;
  7.     }

  8.     NF_SHARE_PTR<NFIPropertyManager> xPropertyManager = xObject->GetPropertyManager();
  9.     if (nullptr != xPropertyManager)
  10.     {
  11.         NF_SHARE_PTR<NFIProperty> xProperty = xPropertyManager->First();
  12.         while (nullptr != xProperty)
  13.         {
  14.             m_pKernelModule->AddPropertyCallBack(self, xProperty->GetKey(), this, &NFCPropertyTrailModule::OnObjectPropertyEvent);

  15.             xProperty = xPropertyManager->Next();
  16.         }
  17.     }

  18.     NF_SHARE_PTR<NFIRecordManager> xRecordManager = xObject->GetRecordManager();
  19.     if (nullptr != xRecordManager)
  20.     {
  21.         NF_SHARE_PTR<NFIRecord> xRecord = xRecordManager->First();
  22.         while (nullptr != xRecord)
  23.         {
  24.             m_pKernelModule->AddRecordCallBack(self, xRecord->GetName(), this, &NFCPropertyTrailModule::OnObjectRecordEvent);


  25.             xRecord = xRecordManager->Next();
  26.         }
  27.     }

  28.     return 0;
  29. }
复制代码


3:展示数据追踪结果,则观察者回掉函数中打印数据变化流,就可以知道数据如何变化,特别是则多个数据一起组合分析的时候,可以解决很多疑难杂症(比如上线后,不方便调试,则可以打开数据追踪开关或GM命令可以很清新的观察某个玩家的数据变化流水,分析线上产生的问题)
其中属性结果如下(打印类型为 "ropertyName" Trailing [Old] "old_value" [New] "new_value"):

  1. int NFCPropertyTrailModule::OnObjectPropertyEvent(const NFGUID& self, const std::string& strPropertyName, const NFIDataList::TData& oldVar, const NFIDataList::TData& newVar)
  2. {
  3.     std::ostringstream stream;

  4.     stream << " Trailing ";
  5.     stream << " [Old] ";
  6.     stream << oldVar.GetString();
  7.     stream << " [New] ";
  8.     stream << newVar.GetString();

  9.     m_pLogModule->LogProperty(NFILogModule::NF_LOG_LEVEL::NLL_INFO_NORMAL, self, strPropertyName, stream.str(),  __FUNCTION__, __LINE__);

  10.     return 0;
  11. }
复制代码


表结果如下(打印类型为分好几类add,del,swap,create,updata,sort,clear):
  1. int NFCPropertyTrailModule::OnObjectRecordEvent(const NFGUID& self, const RECORD_EVENT_DATA& xEventData, const NFIDataList::TData& oldVar, const NFIDataList::TData& newVar)
  2. {
  3.     std::ostringstream stream;
  4.     NF_SHARE_PTR<NFIRecord> xRecord = m_pKernelModule->FindRecord(self, xEventData.strRecordName);
  5.     if (nullptr == xRecord)
  6.     {
  7.         return 0;
  8.     }

  9.     switch (xEventData.nOpType)
  10.     {
  11.         case NFIRecord::RecordOptype::Add:
  12.         {
  13.             NFCDataList xDataList;
  14.             bool bRet = xRecord->QueryRow(xEventData.nRow, xDataList);
  15.             if (bRet)
  16.             {
  17.                 stream << " Trail Add Row[" << xEventData.nRow << "]";

  18.                 for (int j = 0; j < xDataList.GetCount(); ++j)
  19.                 {
  20.                     stream << " [" << j << "] " << xDataList.StringValEx(j);
  21.                 }

  22.                 m_pLogModule->LogRecord(NFILogModule::NF_LOG_LEVEL::NLL_INFO_NORMAL, self, xRecord->GetName(), stream.str(),  __FUNCTION__, __LINE__);
  23.             }
  24.         }
  25.         break;
  26.         case NFIRecord::RecordOptype::Del:
  27.         {
  28.             stream << " Trail Del Row[" << xEventData.nRow << "]";
  29.             m_pLogModule->LogRecord(NFILogModule::NF_LOG_LEVEL::NLL_INFO_NORMAL, self, xRecord->GetName(), stream.str(),  __FUNCTION__, __LINE__);
  30.         }
  31.         break;
  32.         case NFIRecord::RecordOptype::Swap:
  33.         {
  34.             stream << " Trail Swap Row[" << xEventData.nRow << "] Row[" << xEventData.nCol << "]";
  35.             m_pLogModule->LogRecord(NFILogModule::NF_LOG_LEVEL::NLL_INFO_NORMAL, self, xRecord->GetName(), stream.str(),  __FUNCTION__, __LINE__);
  36.         }
  37.         break;
  38.         case NFIRecord::RecordOptype::Create:
  39.             break;
  40.         case NFIRecord::RecordOptype::UpData:
  41.         {
  42.             stream << " Trail UpData Row[" << xEventData.nRow << "] Col[" << xEventData.nCol << "]";
  43.             stream << " [Old] " << oldVar.StringValEx();
  44.             stream << " [New] " << newVar.StringValEx();
  45.             m_pLogModule->LogRecord(NFILogModule::NF_LOG_LEVEL::NLL_INFO_NORMAL, self, xRecord->GetName(), stream.str(),  __FUNCTION__, __LINE__);
  46.         }
  47.         break;
  48.         case NFIRecord::RecordOptype::Cleared:
  49.             break;
  50.         case NFIRecord::RecordOptype::Sort:
  51.             break;
  52.         default:
  53.             break;
  54.     }

  55.     return 0;
  56. }
复制代码


上面的代码可以随意则任意时刻追踪NF中的一个对象的数据。但是如果想则某一时刻看一下所有的数据,如何操作呢?代码如下,此段代码,本来是每次打开数据追踪时就需要调用的,这样可以把开始数据追踪的那一刻的所有数据全部dump出来,但是平时的任意时刻,也均可以调用它,用来打印当时的数据情况。
  1. int NFCPropertyTrailModule::LogObjectData(const NFGUID& self)
  2. {
  3.     NF_SHARE_PTR<NFIObject> xObject = m_pKernelModule->GetObject(self);
  4.     if (nullptr == xObject)
  5.     {
  6.         return -1;
  7.     }

  8.     NF_SHARE_PTR<NFIPropertyManager> xPropertyManager = xObject->GetPropertyManager();
  9.     if (nullptr != xPropertyManager)
  10.     {
  11.         NF_SHARE_PTR<NFIProperty> xProperty = xPropertyManager->First();
  12.         while (nullptr != xProperty)
  13.         {
  14.             std::ostringstream stream;

  15.             stream << " Start trail ";
  16.             stream << xProperty->ToString();

  17.             m_pLogModule->LogProperty(NFILogModule::NF_LOG_LEVEL::NLL_INFO_NORMAL, self, xProperty->GetKey(), stream.str(),  __FUNCTION__, __LINE__);

  18.             xProperty = xPropertyManager->Next();
  19.         }
  20.     }

  21.     NF_SHARE_PTR<NFIRecordManager> xRecordManager = xObject->GetRecordManager();
  22.     if (nullptr != xRecordManager)
  23.     {
  24.         NF_SHARE_PTR<NFIRecord> xRecord = xRecordManager->First();
  25.         while (nullptr != xRecord)
  26.         {
  27.             for (int i = 0; i < xRecord->GetRows(); ++i)
  28.             {
  29.                 NFCDataList xDataList;
  30.                 bool bRet = xRecord->QueryRow(i, xDataList);
  31.                 if (bRet)
  32.                 {
  33.                     std::ostringstream stream;
  34.                     stream << " Start trail Row[" << i << "]";

  35.                     for (int j = 0; j < xDataList.GetCount(); ++j)
  36.                     {
  37.                         stream << " [" << j << "] " << xDataList.StringValEx(j);
  38.                     }

  39.                     m_pLogModule->LogRecord(NFILogModule::NF_LOG_LEVEL::NLL_INFO_NORMAL, self, xRecord->GetName(), stream.str(),  __FUNCTION__, __LINE__);
  40.                 }
  41.             }

  42.             xRecord = xRecordManager->Next();
  43.         }
  44.     }

  45.     return 0;
  46. }
复制代码



是不是超级简单? 赶快去实践吧,类地址是 https://github.com/ketoo/NoahGameFrame/blob/master/NFServer/NFGameServerPlugin/NFCPropertyTrailModule.cpp
赶快操练起来,看看你的数据是怎么变化的,也许一下子,你就发现某个地方,你先赠送物品而后扣款了呢?有了此数据追踪技术,在NF中,你的项目中再也不存在查不出原因的BUG了!!!



NF项目为开源的分布式服务器解决方案,其中包含了网络库,actor库,以及数据驱动等新技术,能大幅提升开发效率节省开发周期以及提高程序的稳定性。
项目地址 https://github.com/ketoo/NoahGameFrame
如感觉对您有帮助,请给与star,同时也邀请广大同行参与开发和维护,作者QQ 342006,交流QQ群 341159815。
欢迎转载,转载请注明来源,本文版权归作者所有!

回复

使用道具 举报

您需要登录后才可以回帖 登录 | Register Now

本版积分规则

 

GMT+8, 2018-12-12 03:05 , Processed in 0.096654 second(s), 29 queries .

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表