近期在寫(xiě)基于go的游戲服務(wù)器框架, 在全面脫離C/C++前, 需要對(duì)老架構(gòu)進(jìn)行一個(gè)總結(jié)
基于C/C++游戲服務(wù)器框架總體設(shè)計(jì)的還是不錯(cuò)的, 兄弟們總體使用效果都是好評(píng). 因?yàn)樵诩夹g(shù)上喜歡"偷懶", 所以在很多設(shè)計(jì)上, 都是力求簡(jiǎn)單, 高效(開(kāi)發(fā)效率).
基于任務(wù)的異步DB查詢系統(tǒng), 帶多重異步的同步
代碼示例:
1:
2: void BatchQueryPlayerInfo( uint32 ClientID, const std::string& AccountName, int64 CharID )
3: {
4: GDBExecutor->Commit
5: (
6: dynamic_cast<DBDataTask*>( (new DBQueryCharInfo( ClientID, CharID ) )
7: ->LinkAtomTask( new DBQueryQuest( ClientID, CharID ) )
8: ->LinkAtomTask( new DBQuerySkill( ClientID, CharID ) )
9: ->LinkAtomTask( new DBQueryHero( ClientID, CharID ) )
10: ->LinkAtomTask( new DBQueryAccountInfo( ClientID, AccountName ) )
11: ->LinkAtomTask( new DBQueryEquip( ClientID, CharID ) )
12: ->LinkAtomTask( new DBQueryObject( ClientID ,CharID ) )
13: ->LinkAtomTask( new DBQueryLevel(ClientID, CharID))
14: ->LinkAtomTask( new DBQueryChapter(ClientID, CharID))
15: ->LinkAtomTask( new DBQueryActivity( ClientID, CharID ))
16: )
17: );
18:
19: }
這段主要處理玩家在登陸時(shí), 需要從DB查詢大量的不同分類(lèi)的數(shù)據(jù). 為了保證效率, 我讓每個(gè)Task并行執(zhí)行, 然后通過(guò)一個(gè)機(jī)制, 讓所有任務(wù)完成后, 回調(diào)第一個(gè)任務(wù)的一個(gè)函數(shù). 這樣就無(wú)需手動(dòng)實(shí)現(xiàn)很多粘合代碼, 避免了反復(fù)調(diào)試和錯(cuò)誤
基于protobuf反射機(jī)制的語(yǔ)句自動(dòng)合成
1: DBUpdateCharInfo::DBUpdateCharInfo( int64 CharID, const std::string& Buffer )
2: {
3: char buffer[256];
4:
5: sprintf( buffer, "update tb_char set $FIELD$ where charid = %lld;", CharID );
6:
7: ExecuteCommand( buffer, Buffer, dbopr::FET_Equation );
8: }
這段就是一個(gè)典型的DB任務(wù), 構(gòu)造函數(shù)提供了CharID和一個(gè)由結(jié)構(gòu)體序列化好的buffer, $FIELD$字段, 是通過(guò)反射根據(jù)Buffer內(nèi)容, 自動(dòng)填充字段
這段例子中, $FIELD$可以填充為 hp=100, mp=100之類(lèi)的. 自動(dòng)填充避免了因?yàn)樘砑幼侄蔚牡教幪砑哟a, 還需要調(diào)試, 容易搞錯(cuò)
配置系統(tǒng)概念
基于同一個(gè)配置系統(tǒng), 分層實(shí)現(xiàn)不同的需求. 更簡(jiǎn)單的說(shuō), 解決的1個(gè)實(shí)際問(wèn)題是:
自己改了配置文件中的ip, 上傳svn后, 覆蓋了別人的配置, 很多人的解決方法都是, 本地配置不提交. 但同時(shí)問(wèn)題又來(lái)了:
當(dāng)配置中有別人新加的系統(tǒng)配置, 怎么保證每個(gè)人都能更新到?
上線后, 服務(wù)器交付運(yùn)維, 他們會(huì)對(duì)配置有一定程度的修改, 這個(gè)時(shí)候怎么合并程序配置和運(yùn)維配置?
其實(shí)對(duì)于沖突的需求, 只要對(duì)系統(tǒng)進(jìn)行分層就可以解決問(wèn)題,我的處理方式:
配置分為:
全局配置: 所有服務(wù)的總體配置
單服務(wù)配置: 本服務(wù)的配置, 涉及網(wǎng)絡(luò)及邏輯
本地配置: 這個(gè)配置每個(gè)人一份, 不上傳SVN
命令行配置: 格式和前面的一致, 這塊就可以通過(guò)運(yùn)維進(jìn)行配置
總體結(jié)構(gòu)其實(shí)就是OO的派生概念, 下層可以覆蓋, 修改上層的配置
服務(wù)器互聯(lián)及識(shí)別框架
基本功能: 基于一些簡(jiǎn)單的配置就可以將多臺(tái)服務(wù)器, 同種類(lèi)的不同服務(wù)器互相連接起來(lái), 斷線自動(dòng)重連.
服務(wù)器連接后, 所有服務(wù)器可知曉并可自動(dòng)按需連接
邏輯端也很方便的進(jìn)行廣播或者單獨(dú)發(fā)送等
也就是說(shuō), 每個(gè)服務(wù)器的連接和接受端都是帶識(shí)別名稱(chēng)或id的.
后面覺(jué)得這套東西實(shí)在是做的復(fù)雜, 多整出一臺(tái)中心服務(wù)器來(lái)做. 但好歹框架穩(wěn)定下來(lái)了, 也就好了.
基于lua的服務(wù)器web后臺(tái)框架
思想是很不錯(cuò)的, C++ 配合lua本身絕對(duì)是個(gè)失敗
問(wèn)題出在web處理,本身都是一個(gè)同步阻塞過(guò)程, 而這個(gè)后臺(tái)框架是異步方式來(lái)做, 所以特別別扭
不過(guò)比起以前的本地GM系統(tǒng), 這塊的設(shè)計(jì)是偉大的進(jìn)步
現(xiàn)在正在設(shè)計(jì)基于golang的服務(wù)器框架, 基本框架已經(jīng)完工, 等待編寫(xiě)邏輯后的實(shí)戰(zhàn)測(cè)試
以上的很多思想在golang的服務(wù)器框架都有改進(jìn), 特別是golang本身做web也是優(yōu)秀的, 外加martini這種牛X框架, 更是水到渠成
如果你對(duì)服務(wù)器框架設(shè)計(jì)有特別的認(rèn)識(shí), 或者想碰撞思想, 可以加博客群 309800774或者我的qq: 20998333討論