项目数据库逻辑 数据库主要逻辑模块分为asynDBCenter,DBNet,DBSvr asynDBCenter与DBNet之间通过共享内存通信(缓存进程为了防止GS崩溃导致玩家数据丢失,并且在DBNet里面可以做定时存储) 这里的共享内存有点复杂 1.发包类型的,就是跟GS与Net之间的相似带回收类型的 2.不带回收的,每个玩家独占一个小块,只有玩家独占,当服务器蹦了玩家数据可以存储数据库 3.对于道具由于玩家身上的道具数量众多,不可能有那么多内存分给,当玩家装备属性发生变化时将其放到共享内存中 而且有一个tick,过了这个tick直接归还,防止不常更新的道具长期占据共享内存 4.帮会,拍卖行也一行给他分配共享内存 共享内存GS这边创建DBNet那边读取 游戏过程中哪个属性发生变化,设置脏标记 DBNet根据脏标记发送差异更新包到DBSvr 问题:其实我们这个DBSvr没必要,我们现在是直接发差异更新包到DBSvr然后DBSvr访问数据库,其实可以再DBNet这一端直接访问mongo的api,就这个问题我问过经理 经理说其实是在DBNet这一段去访问数据库,不是在DBSvr,DBSvr不跟数据库打交道,DBSvr的作用是同步在各个服务器的表,服务器直接访问数据库,我也是醉了一地 听说类似memcached和redis缓冲东西应用到数据库不错,我问过经理,经理说在web上应用的比较多,在游戏中直接同步到共享内存中,在换从进程中进行定时存储,不用这个memcached机制 但貌似不是这样的,应该能用的上 举个例子吧 /* 设置玩家等级 */ inline void ShuiHu::ActorInfoEx::SetLevel(int nLevel) { __COMPARE_START(m_actInfo.m_nLevel, nLevel) SetDBEnumAttrDirty(eCharDBAttr_Level); __COMPARE_END } void SetDBEnumAttrDirty(CharDBAttr eCharDBAttr) { char cUseState = m_pActSM->GetUseStateSafe();//获取保存状态 if (DB::GetbIsState(cUseState, SM_USE_SAVED))//数据库已保存清除上一次脏标记 { m_attrFlag.ClearFlag(); } m_attrFlag.SetBitFlag(eCharDBAttr);//将当前标记设置成脏比较 UpdateActSMInfo(eCharDBAttr);//拷贝对于的数据到共享内存中 } DBNet每次遍历所有的脏标记,如果是脏的话,拷贝数据出来拼相关BSON bool DBNet::NormalDBModifyOpt(int nIndex) { SM_Data<ShuiHu::ActorInfoEx>* pSMData = m_spSMDataActEx->GetSMData(nIndex); char cUseState = pSMData->GetUseStateFast(); static ShuiHu::ActorInfoEx InfoEx; if (DB::GetbIsState(cUseState, SM_USE_READYSAVE)) //判断是否处于待保存状态 { char cOpt = 0; pSMData->GetDBOptSafe(cOpt); size_t nCurSaveTime = pSMData->GetSaveTimeFast(); //每个共享内存头部保存一个tick,每次循环根据tick定时保存数据库,正式根据这个tick和脏比较减少数据库压力 if(!IsCanSaveDB(cOpt, cUseState, nCurSaveTime)) return false; //... } 在看个玩家下线 void asynDBCenter::SetActorInfoEx(guid_t actorID,const ShuiHu::ActorInfoEx& info) { SMDataInfo<ShuiHu::ActorInfoEx>& smInfo = m_mapSMAct[actorID]; smInfo.GetSMData()->CopyDataIn(&info); smInfo.GetSMData()->AddDBOpt(DB::eSM_DB_Update); smInfo.GetSMData()->AddUseState(SM_USE_READYSAVE); smInfo.GetSMData()->AddUseState(SM_USE_OFFLINE); //将玩家放到回收队列中,如果DBNet还没有将玩家数据保存并把玩家共享内存设置成已保存状态,这边回收队列中还有玩家的数据 //玩家再次上线可以直接从共享内存中获取数据不用访问数据库 if (!smInfo.GetbInRec()) { smInfo.SetbInRec(true); m_spActorInfoExRecMgr->Push(&smInfo); } } DBNet那边 if(DB::GetbIsState(cOpt, DB::eSM_DB_Del) || DB::GetbIsState(cUseState, SM_USE_OFFLINE)) pSMData->SetUseState(SM_USE_READYREC);//将内存设置成待回收状态 else { pSMData->SetUseState(SM_USE_SAVED); } GS这边 if (DB::GetbIsState(cOpt, SM_USE_READYREC))//待回收状态 { pData->SetUseState(SM_USE_FREE); //设置为可利用状态 m_pSmPoolMgr->Push(pData);//将这块内存放到可用队列中,下次还是从可用队列中分配一块出来 m_pAsynDBCenter->DelSMData(pData); it = m_recycleDeq.erase(it); }