小弟最近需要為公司的遊戲服務端框架增加一個熱更+集羣的方案.

由於我們公司的遊戲伺服器一直完全使用C++開發.所以為了邏輯執行效率考慮.一直以來都是在伺服器開啟時從資料庫裏載入所有必要的數據到內存中(用戶賬戶數據,各種公共數據比如地圖,工會等等),在調用時就可以直接通過工廠類或管理類取到相應的類指針就能方便的操作-&>修改-&>存庫了.但是這樣帶來的缺點就是在生產環境下每次更新維護,甚至每次緊急修復BUG都需要比較長的時間(因為每次更新完之後伺服器啟動要從資料庫讀取大量數據都非常耗時).所以就有了這個增加熱更功能的需求.集羣的功能是這樣的.以前比如說遊戲要開10組服.那麼所有的伺服器配置就需要打開10套(比如每個服都有相應的網關/邏輯/社交/地圖).但是最早開的服隨著玩家流失可能剩下的人已經非常少了.所以每次單獨維護它以及考慮到上面更新的問題(要載入大量數據,啟動慢),所以希望能做到伺服器是可以動態擴展以增加承載能力的.需要承載更多人的時候則在集羣中增加節點即可.目前經過我的初步研究方案有如下三種:

1.使用C++/Lua.用Lua寫邏輯.這樣如果只是邏輯改變的話就只用引擎重新載入Lua即可.我也研究了下雲風的skynet.但是沒有明白skynet是準備怎麼做緩存的.是直接通過Lua調用Redis/MongoDB交互的?希望有在生產項目中用了skynet的朋友介紹下.

2.使用C++載入動態庫寫邏輯.邏輯更新的話則重新載入動態庫即可.使用主框架來緩存數據.動態庫每次向主框架請求需要操作的數據.由主框架負責和資料庫交互.3.增加一組緩存伺服器.邏輯伺服器只負責邏輯.每次操作都從緩存伺服器請求相應的數據.操作完再還給緩存伺服器保存.以達到每次維護只更換邏輯伺服器.而且玩家連接到任何一組邏輯伺服器都不影響操作的目的.目前遇到主要的糾結在於:1.數據應該如何緩存?對於複雜的業務操作可能需要大量的緩存數據以支持判斷查找修改(比如大規模混戰/國戰)等等.那在這種情形下.如何才能確保能最快捷地從緩存中取到大量數據.2.緩存伺服器是自己寫還是採用現有的NoSQL.比如Redis,memcached之類.如果用這樣現成的NoSQL,如何保存一些比較複雜的結構數據.3.以上所述的幾種方案中哪種比較靠譜?獲取各位前輩有什麼好的遊戲伺服器解決方案能夠支持熱更+集羣動態擴展的還望指教.希望各位遊戲界前輩/同行/兄弟姐妹不吝賜教.--------------------------------------------------------------------------------------------------------------------------------------------

2016.08.01更新.

感謝各位的回答.在此補充一點大家可能有誤會的細節.1.為什麼會有大量的緩存數據?我也做過其它類型的遊戲,有很多冷熱數據有很明顯界限的遊戲我也用過redis等等的緩存.比如RPG,可以明顯的分為在線/不在線.一個不在線的玩家基本除了社交相關係統.其它數據幾乎都是不可能被需要到的.比如一些類RPG的卡牌和匹配模式的遊戲,玩家和玩家交互基本是1對1的聯繫.基本上主要的操作都不會涉及到大量的數據存取.只需要對排行榜以及社交服務專門做就好了.但是碰到困難的架構,主要所需要支持的遊戲類型要求玩家之間非常頻繁而且強烈的交互,包括不在線的玩家(基於地圖的經營策略遊戲,如Game of War,Clash of Kings這一類,但是比這些還要複雜).其他玩家的很多數據會被大規模的,極頻繁的存取到.比如在世界地圖上掃地圖,還有大規模的混戰,其實相當於是RPG遊戲裏所有的玩家都可以下一個掛機命令不在線由伺服器完成自動掛機戰鬥甚至智能尋路等操作.所以可能一個操作或者一個定時器消息裏需要大量的操作多個玩家的多種數據.而且這些玩家未必在線.都需要緩存速度快容量大以及便於跨模塊存取數據.2.根據各位的回答.我感覺TSF4G是個看著還比較靠譜的思路,利用共享內存掛載的方法實現快速重啟是可以滿足需要的.但是TSF4G似乎沒有一個比較完善的資料.都只是寬泛的介紹了下概念.我主要是沒有想明白怎麼利用共享內存把如此大規模的內存掛載到一個新進程上去.比如我有一個管理類裡面保存了一些指針,新進程起來從共享內存裏載入這個管理類,裡面保存的指針豈不是已經變成野指針了麼?莫非只能從邏輯上重新構建所有保存的指針數據麼?


問題描述寫了這麼多,看得出題主是位認真負責的同學。本人不邀自來,僅憑個人經驗略答一二,也算是交流經驗探討問題吧。 關於熱更。題主提到遊戲伺服器啟服時載入數據太多,導致啟服時間慢。遊戲伺服器啟服時從資料庫中載入必要的全局數據是肯定需要的,據我的經驗這個數據量雖然不小,但也還不至於到不能接受的地步,不知道題主能不能先從設計的角度考慮對數據做一些精簡呢?遊戲功能邏輯的熱更新實際上是有不少限制的,因為這種更新往往不僅是伺服器操作,遊戲客戶端也需要做相應的修改。最簡單的情況是配表的更新,只需要更新文本文件還是比較好處理的。C++/Lua的方式可以在一定程度上實現對功能邏輯的熱更新,相比C++動態庫更靈活。 關於集羣。遊戲伺服器的動態擴展是一個比較複雜的問題。一般來說遊戲伺服器都是按服劃分,後期玩家流失之後,可以考慮合服了吧。 你說的三種解決方案,第一種C++寫框架Lua等腳本語言寫邏輯已經比較成熟;第二種方案我覺得不是很好,首先C++寫遊戲邏輯已經很複雜,而C++動態庫其中的坑也不少,建議慎重。第三種方案緩存伺服器,正是我們也採用的,雖然可能和你想的不完全一樣,但我還是多說一些吧。

遊戲伺服器框架:遊戲邏輯伺服器---數據存儲伺服器---Database(MySQL)

數據存儲伺服器主要負責數據緩存,載入數據時首先在緩存中查找,如果未命中再到資料庫中載入。保存數據時,玩家數據由邏輯服發送到數據存儲伺服器的緩存中,然後每隔一段時間,緩存中臟數據寫入到資料庫中。這也是考慮到遊戲數據存儲「讀少寫多」的特點。 數據存儲伺服器中緩存系統是自己設計實現的,開發語言是C#。首先我們對遊戲數據進行了抽象和簡化,主要支持查找更新刪除等基本操作。緩存中的數據基本上是key-value的形式和具體的遊戲功能邏輯無關。如果換成Redis的話應該也是可以實現的,Redis支持更豐富的數據類型。我們的緩存系統有個問題是如果數據存儲伺服器宕掉會導致數據丟失,現在正在考慮對緩存數據加一個備份,就是內建緩存數據再發送到redis或memcached中做備份保存,這樣也可以支持加快伺服器重啟,新進程直接從redis或者memcached中載入數據,和共享內存的方案類似。

就我知道的幾個答一下吧。

1. skynet只是按用戶存了一份數據,並沒有做大量的緩存,如果需要大量緩存還是要自己寫緩存服務

2. 最好不要用動態庫的形式轉移數據,不能跨平臺是一定的,並且跨動態庫維護數據很容易出問題,特別是涉及全局變數和靜態變數的時候。單例模式的實現基本都是全局變數或者靜態變數。

3. 外部緩存服務是比較靠譜的,你自己能寫當然最好,沒時間寫完整的話用redis什麼的也行啊。具體哪些用現成的哪些自己寫還是要根據具體項目需要的。我們就是一部分用redis,一部分自己寫。但是一定要控制好淘汰機制。

tsf4g:其實這貨並沒有規定你一定要用共享內存放數據。而且如果你實在想用共享內存放數據的話,很多都要手動處理。所有對象得自己維護索引,然後在進程重啟後恢復索引。然後基本上你就和stl容器告別了,因為所有數據裏都不能存任何地裸指針,當然你可以用boost的方法存偏移指針,或者按類型寫支持共享內存和stl容器的allocator。很多用tsf4g的項目是用index的。如果你想用任何堆相關的演算法,紅黑樹,鏈表等等,自己寫。

https://github.com/owent-utils/c-cpp/blob/master/include/MemPool/IdxShmMemType.hc-cpp/IdxShmMemTypeKV.h at master · owent-utils/c-cpp · GitHub

c-cpp/StaticShmAllocator.h at master · owent-utils/c-cpp · GitHub

比如這個就是當時用tsf4g的時候拿來存對象的,創建的時候寫索引,進程重啟的時候重新掛載索引。共享內存放數據還有一個比較麻煩的是,如果對象內存佈局變化了,你必須能夠檢測到並且正確升級,這點很重要。所以我的建議是,除非你要寫大型MMO遊戲,否則用共享內存絕對性價比太低呀。最後說一下我們目前的做法吧。就是更新伺服器的時候部署另一組,然後部署完後把路由切過去,最後通知所有老伺服器的玩家斷線重連。就完事兒了,部署的時候慢就慢一點唄。不過我們對不同類型的緩存有優化,會控制到它並不太大就是了。
熱更新並不一定要你不關閉進程來更新邏輯。如果你有gate伺服器,那說明你的客戶端不跟邏輯服直連,那你只要啟個新的邏輯服進程,然後把之前的連接轉到新啟的服就好了。這樣你也不用糾結伺服器的啟動時間。如果你的客戶端與邏輯伺服器直連,那可以考慮用lua之類的熱更新方案。至於緩存,其實共享內存啊redis哪種方案都可以,建議單獨一個進程處理讀寫資料庫和緩存。這樣可以讓遊戲邏輯伺服器專註於處理遊戲邏輯。

你們都錯了,哈哈,C++是可以熱更新的,無縫更新,用so動態庫就可以,不過寫代碼要規範,把全局變數寫在單例類裡邊,然後在主程序傳遞各種單例指針給so庫去操作就可以了


題主第三個想法靠譜。糾結的那幾點取決於你的能力。大型成熟的SNS、電商和遊戲,都是採用的緩存的辦法。但至於自己寫專用緩存,還是redis,memcache等,取決你你們的能力。

如果能力不夠,就用redis、mc等,如果能力足夠,建議自己寫專用緩存。

性能,效率會提高很多很多。
推薦閱讀:
相關文章