遊戲服務器架構調研報告

服務器架構調研報告

                                                                                                                                                     劉源霖20151119 php

1.      前言

本文檔主要是調研分析新的手遊服務端架構,爲下一款手遊服務端研發提供可參考的方案。主要的參考點是數據持久化,併發效率,分佈式,沙盒機制,熱更新機制,研發維護成本。若是從頭根據需求開發一款新的服務器架構,須要大量的時間,並且可能會得不償失,一款新的架構穩定都須要時間的。咱們應該嘗試使用開源的,成熟的,活躍度高的開源框架。正文將先從服務器設計須要考慮的因素進行需求分析,以致明確咱們須要的服務器架構原型,而後再分析現有的開源架構方案。 html

 

 

2.      遊戲服務器設計因素

2.1.             服務器運行平臺選擇

服務器操做系統大多采用UnixLinux操做系統,而Linux發行版本系統中,多使用CentOSRedhatUbuntuGentooDebian。而這些發行版本能夠大致分爲兩類,一類是商業公司維護的發行版本,一類是社區組織維護的發行版本,前者以著名的RedhatRHEL)爲表明,後者以Debian爲表明。Redhat的穩定性和硬件兼容性都比Debian高。而且RHEL的生命週期是710年,基本上能夠覆蓋硬件的生命週期,也就意味着一個新硬件安裝之後,不用再次安裝操做系統。而Debian的生命週期是不固定的,通常新版本發佈之後,上個版本再維護18個月。而Debian的版本發佈時間間隔不穩定,常常會延期。綜合起來一個版本的生命週期通常在34年。若是選用了 Debian 或者 Ubuntu做爲服務器,等生命週期過了之後,就沒有安全補丁,服務器就會有安全風險。 前端

 

基於以上對比,在給服務器選擇Linux操做系統時,咱們會優先考慮Redhat系統的操做系統。 html5

因爲CentOS源於 Red Hat 企業級 LinuxRHEL)的源代碼,依照開放源代碼規定釋出的源代碼所編譯而成。因爲CentOS開源特性,選擇CentOS能夠下降成本,同時又可以享受RHEL的服務支持。目前市場最大的兩個centos系統是centos52007)和centos62011),最新的是centos72014),每一次的大版本升級系統意味着更好的穩定性和功能擴展。因爲centos7剛剛在2014.7月發佈,最新版本7.2穩定性還有待考證。因此選擇centos6是最爲合適的。 Centos6版本最新centos6.7。 java

 

2.2.             數據持久化

對於服務器而言,數據是最重要的。有一個好的數據持久化方案,對於服務器開發將會是事半功倍。在介紹數據的持久化方案之前,咱們如今介紹服務器數據讀取和修改的運用場景。服務器運行過程當中會不斷的生產數據(增刪讀改),而且將數據落地(如存入數據或者文件)。 python

可是若是服務器每次都直接從數據庫或者文件讀取和修改數據,那麼服務器的io操做可能成爲瓶頸,能夠採用異步讀寫方案來下降io讀寫對服務器邏輯處理能力影響,可是同時提升邏輯的複雜度。 因此較好的方式是將數據緩存到內存中,同步讀寫,每次讀寫都先操做緩存,而後再由緩存同步到數據庫。同步機制決定了數據持久化能力。若是本身去實現這套機制無疑是造輪子,並且效果不必定好。數據持久是每一個服務器都須要的。已經有不少專業的團隊提供有不少開源的成熟的解決方案。如memchache redis 緩存系統。 mysql

下面提供三種方案: c++

第一:redis + mysql git

第二:redis + unsqlite(推薦,兩種都是key-valuenosql 程序員

第三:redis.redis 自帶數據落地策略)

 

對於具體如今那種能夠後續再討論

注意:對於在選擇數據持久化方案時,須要考慮咱們的對數據的需求,如是多讀少寫,仍是少讀多寫。在遊戲服務器中還應該考慮合服和跨服等需求是否方便實現。

 

2.3.             服務器併發處理能力

對於遊戲服務器而言,首先應該保證的就是高併發處理能力,從而最大限度的提升服務器的吞吐率,提升單服在線人數,下降服務器硬件成本。實現的方式有不少,沒有決對好壞。只有針對具體的需求,纔有好差之分。

方式有不少,經常使用的兩種:單線程多進程,單進程多線程

第一:主邏輯單線程+[多輔助線程]

好處:不用考慮鎖,多線程數據同步等。開發門檻低,開發方式方式靈活,bug定位容易,新人上手容易

壞處:沒法充分利用cpu多核

對於遊戲服務器架構而言,服務中存在不少模塊,因此的模塊都將混入這個單線程中,若是cpu性能出現瓶頸, 優化成本將會很是高,因爲是單線程,拋棄了鎖等束縛,給程序員提供太大的空間,每每在書寫的過程當中比較隨意,若是沒有沙盒機制,要保證代碼的質量對參與開發的每一個程序員的水平要求都要要比較高。

第二:主邏輯多線程+[多輔助線程]

好處:充分利用多核

壞處:開發過程要考慮數據同步等問題。Bug定位困難

因爲單核cpu的能力限,而且遊戲服務器模塊較多,並不是處理某一類單一問題,因此服務器的實現應該儘可能利用cpu的多核處理能力,並且能夠綁定線程,提升cache命中機率。可是多線程併發編程若是沒有一個好的系統機制或者語言支持,如使用c 或者 c++語言。門檻較高,要求開發人員的必須具備較高的架構能力,不然將會出現多線程處理能力不如單線程。因此如何下降併發編程的門檻也是服務器架構設計的重要部分。

 

 

2.4.             服務器分佈式能力

服務器分佈式,是指服務器支持分別部署在不一樣物理機上。能夠以增長物理機的方式提升服務器的承載能力。因此好的服務器應當有一個靈活的擴展分佈方案。因此如何讓咱們的服務器具備靈活的擴展能力,將是服務器架構中的重要部分。

 

 

2.5.             服務器沙盒機制

沙盒機制:就是讓代碼在一個比較安全的受包含的環境中運行,即便代碼出現錯誤,產生了叫惡劣的影響,其破壞能力將被禁止在沙盒中不會影響到沙盒外的環境。這樣的機制能夠提升服務器的安全性和穩定性,而且提升開發效率。因此如何讓服務器架構具有沙盒能力將是服務器架構設計的重要部分。

 

2.6.             服務器熱更新機制

若是服務器可以作到不停服維護,那麼能夠在不承受停服帶來的損失的狀況下,修復服務器缺陷。然而咱們一般應的c語言,c++ java的語言都是不支持熱更新。一般只有解釋型的腳本語言才能支持人更新,還有函數編程語言也支持簡單熱更新,由於函數編程語言函數內無狀態。

 

 

2.7.             服務器研發維護成本

相信有不少知足上面要求的服務器架構,可是選擇這些架構須要根據團隊成員的自身能力。好比erlang語言,天生支持分佈式,支持沙盒機制,因爲自己是函數式編程語言,天生時候併發編程,簡單熱更新等機制。可是團隊成員中沒有一個會erlang,咱們也不會選擇erlang語言。由於咱們耗不起從頭學習erlang的時間。

 

 

3.      調研報告

調研報告主要從兩個方面進行:語言、開源引擎。

3.1.             語言調研

如今有不少面向併發或者易於併發編程的語言,他們大可能是一些小衆語言,如goerlang語言。不少遊戲喜歡用erlang語言作服務端。Erlang是函數式編程語言,接近天然語言易於理解,而且天生支持併發編程,熱更新。Erlang的核心概念是節點,一個節點就是一個獨立的系統包含了地址空間和獨立的進程集的完整虛擬機,這種設計基礎讓erlang語言天生具備分佈式和沙盒機制。根據erlang的這些特性,無疑徹底知足咱們對服務器的要求,並且大大下降了門檻了,由於咱們不在須要考慮併發,考慮分佈式,考慮鎖等。可是通常小衆的誕生都是爲了特意的解決某一類問題而誕生的。天然就有這種語言最適合的,和不適合作的事情。Erlang適合作非計算密集超大併發服務器,不適合作數值計算和業務邏輯很是複雜的系統。

 

經過上面的分析,erlang語言確實適合輕量級遊戲的開發,並且開發門檻低,特別是對於沒有經驗和技術沉澱的小公司而言。可是咱們團隊成員都沒有學過erlang語言,都沒有學習過任何函數式編程語言,雖然erlang的門檻低,可是要用好,相信仍是須要的時間的。這將會大大提升的咱們的時間成本。因此對於咱們選擇erlang是不太合適的。可是erlang的思想是能夠借鑑的。若是咱們能用熟悉的語言實現erlang的思想,無疑是很是完美。那有沒有一套這樣現成的系統,答案是確定的。 Skynet(開源服務器引擎)正是研發者在使用erlang時出現瓶頸後使用c語言和lua語言模擬了erlang的機制,最終替換了erlang語言。而且通過日活躍用戶50萬的考驗。具體細節後面具體章節再討論。

 

3.2.             開源引擎調研

可以站在巨人的肩膀上,利用前人的研究成果,是最快最有效的方式。開源的遊戲服務器有不少,根據咱們自身的因素,咱們只能選擇c/c++ lua相關的。這樣的服務器引擎目前比較活躍的有兩個:KBEngine(c++ + python),  skynet(c + lua)

KBEngine:

發佈時間20126月,

開源地址:https://github.com/kbengine/kbengine

Fork次數766

Issues  22

Pull requests 83

Star:891

最新release版本:V0.6.21

社區關注人數:1773

成功產品:

 

KBEngine是一款開源mmog服務端引擎, 使用統一協議可以輕鬆與前端對接,能輕鬆使用unity3d ogre cocos2d html5等做爲前端表現。

底層框架由c++編寫, 邏輯層使用python(支持熱更新), 開發者無需重複實現一些通用的底層服務端技術, 使開發者可以真正集中精力到遊戲開發上來, 快速打造各類遊戲。

KBEngine底層架構被設計爲多進程分佈式動態負載均衡方案, 理論上只須要不斷擴展硬件就可以不斷增長承載上限,單臺機器的承載上限取決於遊戲邏輯自己的複雜度。


Skynet

發佈時間:20127

開源地址:https://github.com/cloudwu/skynet

Fork次數:1469

Issues16

Pull requests: 192

Pull requests: 192

Star:3038star> 3000, all1386 c 46 c++ 28

最新release版本:V1.0.0

社區關注人數:1213

表明產品:陌陌爭霸(日活躍50萬,大服結構),每天來戰, , 戰神黎明,逍遙西遊

http://tech.qq.com/a/20140325/020893.htm

 

skynet是雲風編寫的服務端底層管理框架,底層由C編寫,配套lua做爲腳本使用,可換python等其餘腳本語言。

skynet默認開啓_timer線程、_socket線程、_monitor線程以及可配置個數的多個_worker線程,啓動skynet服務就是向skynet註冊由c編寫的so模塊實例也就是服務。

skynet主要工做是經過模塊註冊管理服務,並協調服務之間的調用和通信。

 

二者數據對比分析,發佈時間相同,社區關注度kbengine更勝一籌,可是參與開源貢獻和維護方面skynet更勝一籌,而且skynet已發佈1.0版本。 Kbengine目前沒有成功的產品。爲何會出現這種狀況呢, 第一:kbengine 封裝完整,代碼量大,用戶能夠很簡單快速的搭建遊戲服務器,可是很難把握其底層整個架構,一旦出現問題很難跟蹤,這就是爲何參與其開源貢獻的人比較少, 而skynet至提升一個簡單框架,代碼量少,使用者很容易把握住,雖然沒有kbengine那麼方便,可是也提供更多自由選擇的空間。第二:skynet成功的產品都主導研發skynet的簡約公司的產品,而kbengine沒有成功的產品,有多是有產品用了沒有宣傳,還有多是研發者並無將引擎用於本身的項目,只是業餘時間開發。

 

總之從二者來看,skynet更適合,skynet只提供簡單框架,徹底模擬erlang的思想,而且採用了咱們熟悉的二者語言luac, 而且代碼量少,容易把握。而且已有成功的產品和相對客觀數據驗證了skynet的健壯性。下面對skynet架構作具體分析。

 

 

4.      Skynet 架構解析

在正式具體的介紹skynet設計細節以前,先來分析它是如何模擬實現erlang思想的。

Erlang的主要幾個核心點:節點核心概念,分佈式, 併發編程,actor 模式,沙盒機制, 多進程實,熱更新,開發簡單。

Skynet核心概念也是節點,通常稱之爲服務,也使用actor模式,也提供分佈式方案(harbor cluster模式),多線程驅動, 與lua結合,利用lua天生的沙盒機制(state)和熱更新機制,同時經過lua來下降開發門檻。簡單說:skynet 利用了操做系統線程+luaState + lua coroutine實現了簡單的erlangErlang底層也是採用c實現的,只是封裝的更加完善,沒有接種其餘的語言實現本身是的沙盒方式。

 

 

4.1.             Skynet簡介

skynet是簡約公司雲風主導研發的輕量級服務端底層管理框架,底層由C編寫,配套lua做爲腳本使用,可換python等其餘腳本語言。整個服務器邏輯層偏lua。底層C框架主要工做是經過模塊註冊管理服務,並協調服務之間的調用和通信。

Skynet 發佈與20127月,201511月正式發佈release版本1.0

簡約公司產品都使用了skynet框架:如陌陌爭霸,每天來戰,陌陌彈珠,逍遙西遊等

設計綜述:http://blog.codingnow.com/2012/09/the_design_of_skynet.html

 

 

4.2.             Skynet層次

Skynet是設計是使用actor模式,所有工做線程以消息驅動。服務器初始化啓動多個工做線程,一個網絡線程,一個定時器線程,一個監控線程。用線程帶動各個服務運行,若是是lua服務則須要一個lua state 協助運行,在lua state能夠啓動多個coroutine協同工做。詳細見其層次圖。

 

 

 

4.3.             Skynet任務調度

因爲skynet使用actor模式,使用消息驅動,那麼全局就須要維護消息隊列。Skynet的消息隊列設計以下,每一個服務有個獨立消息隊列,全局有一個全局的全局隊列,每一個服務啓動後須要將本身的消息隊列註冊到全局隊列中, 全部的工做線程依次輪詢全局隊列,以此調度各個服務執行本身的任務。

每一個消息隊列都是多個生產者和多個消費者。見下圖

Skynet採用的自旋鎖

 

 

4.4.             Skynet-lua 服務

每個lua服務都有一個獨立lua state,由此造成服務器的沙盒機制。配合lua中協同開發模式,能夠同時執行多個任務。 對於c層的異步接口,能夠在lua層封裝一層阻塞接口,而後交給coroutine去等待。等待有結果時再喚醒coroutineCoroutine的阻塞並不會致使整個lua state的阻塞,因此整個工做線程仍是在運行的,簡單的說就是用同步寫異步。如:lua socket

 

4.5.             Skynet-harbor集羣模式

當單臺機器的處理能力達到極限後,能夠考慮經過內置的 master/slave 機制來擴展。

每一個 skynet 進程都是一個 slave 節點。但其中一個 slave 節點能夠經過配置 standalone 來多啓動一個 cmaster 服務,用來協調 salve 組網。對於每一個 slave 節點,都內置一個 harbor 服務用於和其它 slave 節點通信。

 

4.6.             Skynet-cluster集羣模式

skynet 提供了更具彈性的集羣方案。它能夠和 master/slave 共存。也就是說,你能夠部署多組 master/slave 網絡,而後再用 cluster 將它們聯繫起來。固然,比較簡單的結構是,每一個集羣中每一個節點都配置爲單節點模式(將 harbor id 設置爲 0)。

要使用它以前,你須要編寫一個 cluster 配置文件,配置集羣內全部節點的名字和對應的監聽端口。並將這個文件事先部署到全部節點,並寫在 Config 中。

4.7.             Skynet部署方案

如下是skynet主導研發雲風在騰訊課堂上對skynet提出的二者部署方案。

 

 

5.      Skynet實例

 

5.1.             skynet實例-單服

Skynet實例介紹,過程參考下圖:

1.  本實例是將登錄單獨出了一個skynet節點,也能夠與遊戲服之前作成同一個skynet

2.  登錄的主服務負責接收登錄消息,從節點負責驗證

3.  網關服務負責接收網絡消息,並轉發給對應的agent

4.  Redis主服務負責接收數據請求,並派發給從節點,從節點負責從各自鏈接的redis數據查詢更改數據。用於數據庫鏈接池

5.本方案只考慮單服

 

 

5.2.             skynet實例-多服

對於多服的實現並必定時由於單服的承擔能力不夠,有多是運營須要,運營須要多個排行榜,以養更多的大R,如不少頁遊開了幾百個服,實際上是開了幾百個排行榜。因此實現爲服務架構支持靈活的多服部署方式和合服策略是很重要的,合服操做的是數據,因此要保證在數據標識設計時要爲後期的合服作準備。下圖是skynet多服部署圖,採用使用skynet cluster模式。

相關文章
相關標籤/搜索