mqant分散式伺服器框架設計動機

liangdas發表於2017-02-28

2016年底的時候對即時通訊以及遊戲開發產生了一些興趣,而且自己這方面的知識掌握也非常少,在未來很多產品應該都會使用到長連線技術(物聯網IOT),因此很有必要掌握這方面的技術。於是就在網路上查詢相關的資料,但發現目前網路上的開源遊戲伺服器框架相對較少,而目前市面上已有的一些開源遊戲框架又不太對自己的胃口。正好17年初剛回公司的時候事情比較少,就抽時間按照自己對遊戲伺服器的架構思路做了一套,取名就叫mqant了,現在已經發布到Github上,歡迎大家Fork mqant開源框架

為什麼決定要重新造一個輪子?

目前網上優秀的開源遊戲伺服器框架也不少(當然與web框架比起來就少太多了),但總結起來都各有各的優缺點,下面列出我在選型過程中的一些考量,希望大家能開放的討論,有不恰當的地方也請指正。

首先是開發語言

目前用於遊戲伺服器開發的主要應該有以下這些語言:

  1. c/c++

    優點:

    效能很好

    缺點:

    不過我個人不會C++

    開源框架:

    skynet
    底層是C 開發語言是lua,
    沒有客戶端庫
    
    kbengine
    底層是C++ 開發語言可以使用C#,Python
    有多個平臺的客戶端庫
  2. C#

    優點:

    效能很好

    缺點:

    不過我個人不會C#

    開源框架:

    Scut
    底層C#   開發語言是 C#、Python和Lua多種指令碼進行開發
    有多個平臺的客戶端庫
    
    Photon
    底層C#   好像是收費的,但畢竟出名
    有多個平臺的客戶端庫
  3. python

    是我最想使用的一種開發語言

    1. 開發效率非常高
    2. 支援協程,能開發出高併發性的遊戲,而且程式碼可讀性好
    3. 目前有很多遊戲公司應該都使用的是Python作為後端遊戲伺服器開發語言,有相對成熟的案例

    缺點:

    1. Python很致命的一個問題是程式不能利用多核,也就是說一個程式只能利用一個CPU進行計算,如果要用多核就需要新開程式,這樣會造成伺服器的維護成本增加,而且開發專案時所需要考慮的問題也更多

    開源框架:

    twisted  可以用來做閘道器伺服器
    firefly  應該很早就不維護了
  4. java

    1. 沒有找到比較好的開源框架
    2. 對協程支援不夠好
    3. 開發效率較低
  5. javascript

    優點:

    1. 語法靈活(這是一把雙刃刀,用起來要小心,尤其是團隊開發中)
    2. 開源庫豐富

    缺點:

    1. 語法上有一些缺陷
    2. 跟Python一樣不支援多核
    3. 對協程支援不夠好,地獄回撥很可怕,雖然有一些解決方案,但用起來稍微有點彆扭

    開源框架:

    Pomelo 網易出的,安靜了一段時間,最近又開始維護了
    有多個平臺的客戶端庫
  6. golang

    優點:

    1. 效能好,跟C/C++/C#一樣編譯型語言
    2. 語法比較簡單,開發效率也比較高,接近Python
    3. 語言級別支援協程
    4. 單程式支援多核併發計算

    缺點:

    1. 開源庫較少,會golang的開發者比較少

    開源框架:

    leaf        接觸的第一個golang框架,設計不錯,但不支援多程式
    沒有客戶端庫,需要自己實現
    cellnet 剛接觸,沒法評價,但好像它用了callback回撥函式的設計,這樣的設計在golang應該可以避免

遊戲框架的不足

結合個人的實際情況,當時我主要的選擇從 skynet Pomelo leaf 這三個框架裡面來選擇

skynet設計思路非常牛逼,看了風雲大牛的設計感覺應該是一個高效能,高穩定性的遊戲伺服器框架,而且有很多產品已經使用上了。 但個人認為skynet可能也會有以下的兩個問題

  1. Actor模式可能對架構能力比較高,不如rpc模式明瞭
  2. skynet使用第三方網路庫的時候可能需要造輪子,要放開膀子開發有些難,跟python tornado的一樣,要寫出高效能的程式也對開發人員有一定的要求

Pomelo由網易團隊開發的,對多程式架構做的非常好,不過由於javascript效能的關係Pomelo的定位也在一些中小型非即時戰鬥類遊戲,經過一段時間的學習和測試,最後還是無奈放棄了

最後經過多方考慮,我選擇golang作為開發語言,當時第一個接觸的就是leaf,學習開發了一段時間發現了leaf的一些不足

  1. 不支援多程式
  2. 沒有客戶端開發庫,需要自己造輪子

上面列出來的都是這幾個框架的缺點,其實這幾個框架都非常優秀,只是不同的需求有不同的要求罷了,希望大家能根據自己實際需求選擇最適合自己的框架

對遊戲伺服器框架的想法

自己心裡也對遊戲伺服器框架有一些自己的想法,最終決定造這個輪子。

  1. 高效能,支援多核

    這在未來開發,擴充套件,維護會輕鬆很多,比如Python這樣一臺伺服器跑上百個程式的遊戲伺服器,維護起來就很讓人頭疼

  2. 支援協程

    協程在客戶端中應用不大,但在伺服器開發中可以發揮極大的威力:

    1. 高併發,能最大的利用cpu資源
    2. 非同步開發同步化,免去了回撥函式設計,避免了地獄回撥
  3. 支援分散式,但也支援單程式部署

    有些框架寫一個demo都需要啟動多個程式,實際上在專案前期可能一臺伺服器就能夠支援了,我希望實現一個既可以單程式部署又可以分散式部署的框架

    1. 單程式能夠實現高效能
    2. 分散式部署不用重新設計編碼

    這個需求的實現主要靠約定,只要開發的時候按分散式環境來開發,程式碼一般都不需要移植

  4. 有豐富的客戶端開發庫

    讓開發者專心業務開發,不同再去造輪子了

mqant框架的架構

mqant就是按照以上的思路設計的,同時設計思路上參考了Pomelo,並且也使用了leaf框架的部分程式碼。

  1. golang本身支援高效能,支援多核
  2. 支援協程 因此mqant的RPC通訊都可以按同步來寫, 例如:

    //遠端呼叫 Login模組的getRand方法
    result,err:=m.RpcInvoke("Login","getRand",roomName)
    if err==nil{
        //getRand 呼叫成功了,再做下面的遠端呼叫
        result,err:=m.RpcInvoke("Login","getName",roomName)
    }
    //上面的呼叫都執行完了才執行下面的程式碼
    ....
    
    result 是遠端呼叫成功以後的返回值
    err     是遠端呼叫失敗的資訊
    
    以上程式碼非常清晰,跟普通的函式呼叫基本一樣,但如果用回撥函式的話,如下:
    
    m.RpcInvoke("Login","getRand",roomName,func(result string,err string){
            if err!=nil{
                m.RpcInvoke("Login","getName",roomName,func(result string,err string){
                    //呼叫都執行完了才執行下面的程式碼
                })
            }
    })
    ...
  3. 支援分散式,但也支援單程式部署

    mqant是按模組為單位來劃分功能模組的,可以將一組模組放到一個程式來執行,也可以將所有模組放到同一個程式來執行(即單程式模式)

    mqant模組間約定按標準的RPC來相互呼叫

    RPC底層分兩種模式

    1. 基於golang chan的單程式通訊
    2. 基於rabbitmq的跨程式通訊

    RPC會根據模組間的部署情況選用適當的通訊方式,以達到在單程式模式下RPC通訊的最低效能損耗和最快的響應時間

  4. 有豐富的客戶端開發庫

    mqant沒有考慮幫開發者造一個客戶端開發庫,而是選用了目前物聯網中非常流行mqtt協議來作為通訊協議,mqtt本身就有各個平臺的客戶端開發庫,因此可以直接用mqtt的客戶端開發庫對接到mqant上來。實現了mqant跨平臺通訊的要求

總結

mqant還是一個非常新的框架,有很多地方都不完善,但我相信有更多大牛的加入進來參與完善和優化的話,mqant框架將變得更好。

相關文章