H2Engine伺服器引擎介紹

来源:http://www.cnblogs.com/zhiranok/archive/2017/09/11/ffengine.html
-Advertisement-
Play Games

H2Engine伺服器引擎架構是輕量級的,與其說是引擎,個人覺得稱之為平臺更為合適。因為它封裝的功能非常精簡,但是提供了非常簡潔方便的擴展機制,使得可以用C++、python、lua、js、php來開發具體的伺服器功能。H2引擎的靈感來源於web伺服器Apache。 H2引擎集成了websocke... ...


H2Engine伺服器引擎介紹

簡介

  H2Engine伺服器引擎架構是輕量級的,與其說是引擎,個人覺得稱之為平臺更為合適。因為它封裝的功能非常精簡,但是提供了非常簡潔方便的擴展機制,使得可以用C++、python、lua、js、php來開發具體的伺服器功能。H2引擎的靈感來源於web伺服器Apache。大家都知道Apache封裝了瀏覽器的的連接和協議通訊,而具體功能邏輯則通過fastcgi的方式交由不同的編程語言實現,本人大學的剛接觸php的時候,看到在php里print的字元串直接就出現在瀏覽器里,當時的感覺就是哇!這介面設計的真是帥!因為每個程式員最先學會的就是print,就會感覺這個介面設計的真是簡單易用。所以php真是當之無愧的最好的編程語言(哈哈)。後來一直從事游戲伺服器開發,發現在伺服器引擎領域就一直沒有這種Apache類似的設計非常通用、易理解、易擴展的引擎。現在游戲伺服器領域大部分項目都是各搞各的,每個主程各搞一套自己用的舒服的架構。有些大廠或者相關的公司開源了一些伺服器引擎,乍一看特別弔,但是跟Apache+php的這種架構相比,其易用性難以望其項背。當然伺服器的長連接模式比web的request/response的模式本質上有更大的複雜性,伺服器引擎的設計難點主要有如下幾點。

  1. 通訊協議沒有標準。大家都知道,http有行業標準,所有瀏覽器都是按照標準與伺服器通信的,而通信部分的實現是伺服器最為關鍵的部分,伺服器程式員一般都知道,《網路編程》沒看過幾遍是寫不了伺服器程式的。一般而言伺服器會採用二進位通信,常見的組包格式有2位元組協議號+2位元組標記+4位元組包體長度+包體數據,這種協議格式緊湊,2位元組的標記留作擴展也比較夠用,比如是否啟用壓縮、加密等,但是這種對某些編程語言不是很友好,比如js就無法採用此種協議。
  2. 消息封包沒有標準。消息封包常見的有struct二進位、自研的序列化、pb、thrift、json等幾種形式,而在web領域,一般要不json要不xml。在伺服器領域一般採用pb的較多。
  3. 編程語言多樣。伺服器編程語言為了高效,總體以c++為主,但是java、c#、python、lua、php、js也越來越流行,尤其是c++嵌入lua的模式大行其道。讓伺服器引擎像Apache一樣可以支持各種語言,實現上很有難度。
  4. 併發與非同步。通常游戲伺服器為了平衡游戲複雜性和性能,採用多進程且每個進程主邏輯單線程的方案,多進程增加吞吐,單線程的程式更好保證穩定性,為了主邏輯不阻塞,幾所所有的io操作都是非同步完成的,這與Apache的理念有很大的區別,這使得Apache引擎很難封裝的像Apache那樣簡潔,市面上有些人嘗試了用協程簡化非同步,但是目前還形成相對成熟的方案。
  5. 數據同步的複雜性。Apache中php也是多進程的,但是不共用數據,無狀態的php設計本身就大大降低了複雜性,但是長連接是有狀態的。php中把狀態數據放到memcahe、redis等記憶體資料庫中,游戲伺服器的多進程架構中也難免有數據需要共用,比如行會數據,但是像php那種通過分散式記憶體資料庫同步方式獲取在性能上(比如實時rpg游戲)是無法忍受的。如果採用非同步獲取,邏輯代碼勢必支離破碎,到處都是回調,難以維護。通常的解決方案是單獨拎出來一個進程處理共用數據,比如CenterServer處理行會請求,所有行會操作都會轉到CenterServer處理,再將結果同步到其他進程,這樣不存在數據競爭和同步的性能問題,但是邏輯因為非同步仍然是複雜了特別多。
  6. 性能難以量化。大家都知道Apache提供了ab程式可以量化伺服器的性能,在伺服器領域幾乎沒有通用的量化工具。一般都是會上線前用機器人壓力測試一下,不能很好的量化各個介面的性能,web領域對介面性能量化的工具比較多,很成熟,確實值得研究學習,因為優化的原則就是現有數據再優化,必須知道哪些需要優化,優化完有多少效果。

  那麼如何解決以上問題呢?經過閉關苦思七七四十九天,終於有所開悟,繼而設計出來了H2Engine伺服器引擎。接下來本文將闡述H2架構的設計細節,以及是如何演化得來。

H2Engine伺服器引擎的演化

  先看下最為常見的游戲伺服器架構圖:

   這個架構是很成熟的,同時充分考慮了系統可伸縮性。Gate和GameServer是性能的關鍵,這兩個都可以平行擴展,H2引擎就是從這個架構抽象而來。首先看Gate這個組件,每個Client連接一個Gate,而GameServer具體有多少個是對client透明的。因為可以啟動N個Gate,所以這個架構理論上可以支持N個Client。linux實現的Gate單個進程撐2萬連接已經不是問題,但是對於分服方式的RPG游戲,有哪個能做到單服線上2萬的?我們的游戲都是限6000線上上限,超過就得排隊了。主要是怕後邊GameServer太卡,因為玩家有聚集效應,都會集中在比較熱門的地圖上。所以當今linux epoll單機如此高性能的基礎上,單個gate進程玩家就足夠應付一個區服的Client連接。所以在上面的架構圖中簡化為單gate,如下圖:

   這個時候發現LoginServer的功能就有些雞肋了。LoginServer本來是類似於DNS的功能,它會返回負載最小的Gate給Client,從而保證Gate的負載均衡,但是現在已經單Gate了,LoginServer變得不是很有必要了,原來的LoginServer上的賬戶驗證功能完全移植到GameServer來做。所以在H2引擎架構中,不再有LoginServer的角色。

   Gate和GameServer肯定是不能少的了。DB是不是是必須的組件呢?答案是否定的。如果從DBServer發展的歷史來看,當DBServer出現的時候,記憶體資料庫還沒有興起,如今,Memcache、Redis等記憶體資料庫已經大行其道,無論從效率還是穩定性,或者靈活性上,都更值得推薦。從運維角度講,他們維護通用的記憶體資料庫也更有經驗。但是就本人看來,大部分情況下連Memcache、Redis這種都不需要,直接GameServer緩存一下就行了(主要是處理下斷線重連,手游閃斷還是很頻繁的),因為GameServer本身就是有狀態的伺服器, 從上線後玩家數據就已經載入記憶體了,相當於所有的讀操作都是緩存好的,所有的更新操作直接寫資料庫理論上完全可以撐住,而且直接寫資料庫也避免了小回檔問題。因為畢竟寫操作對於讀操作量級小太多。如果真的應用場景需要緩存數據,那麼部署一個Redis吧。去掉了DBServer,H2引擎架構簡化成了只有Gate和GameServer,這次真的簡化到極限了。

   下麵讓我們來討論N個GameServer應該放幾台機器上的問題。標準答案當然是需要幾台放幾台,但是如果你身邊有運維的話,他可能給出的答案是一臺機器,為什麼呢,原因其一是這樣運維更方便管理,下發程式、配置、重啟、監控等也更容易。原因其二是現在機器都是多核cpu,記憶體也是過剩的,單台機器的處理能力與往日不可同日耳語。GameServer是主邏輯單線程的,如果一臺機器上部署一個,那麼cpu資源無法得到更好的利用。就本人經驗而言,GameServer很少需要超過4個,為啥?想想看,如果一個RPG游戲單服設計線上1萬人,平均分配到每個進程也就是2500人,很輕鬆啊,當然如果人過多聚集在單個進程,那還有有可能單個GameServer成為瓶頸,這種情況多開GameServer也解決不了問題。從cpu利用上來說,GameServer主邏輯單線程只能用一個cpu內核,考慮到啟停io線程的計算需要一個cpu的計算量,那麼平均2個cpu,4個GameServer也就是8個cpu,現在伺服器沒有8核好意思說是伺服器?以往經驗來看,玩家會比較集中在熱點地圖,一般會某個或某兩個GameServer相對會cpu較高。另外一個伺服器角色Gate是io密集型的,所以和GameServer放到一個機器上,也是扛得住的。這樣在H2引擎中,完全有理由將進程全部跑在一個機器上,先上一個架構圖,然後再講一下這樣設計有何特點。

   到這裡大家有沒有發現,跑在一臺物理機的Gate和GameServer像不像Apache和php的關係?到此,H2引擎的雛形已經形成。Gate在這裡扮演Apache的角色,GameServer在這裡就是php的角色,Apache有一層fastcgi的東西實現進程間通信,只要按照fastcgi的標準,就可以讓Apache支持任何的編程語言,在H2引擎中,也設計了一套進程間通信機制ffrpc,區別於Apache的fastcgi,ffrpc是基於消息+回調機制的長連接通信方式。ffrpc的實現暫時不展開了,現在H2引擎里已經實現了c++、python、lua的支持。H2的雛形已經有了,還需要進一步的抽象完善,因為H2不僅可以用於游戲伺服器,在實時聊天、消息推送等需要長連接的應用場景也可以適用。所以為了更加容易理解,對Gate和GameServer組件的名稱進行重新命名,變得更加通用一些。

   前邊講到伺服器引擎設計的6大難題,下麵討論下在H2引擎中是如何解決的。首先是通信問題,Apache通用是因為Client都是用http協議,那麼可不可以讓游戲伺服器的Client統一用某種通信協議呢?坦白說太難了。但是本人認為,隨著websocket的逐漸普及,websocket可能有一統江湖的可能。其實有了websocket大家自己設計通信協議的理由已經很小了。H2集成了兩種通信協議,websocket和普通的二進位協議,如果你的Client已經使用了websocket,那麼接入H2就是so easy了。

   對於問題2數據封包的處理,H2給出的答案就是無為而治,既然沒有標準,那麼H2也不幹涉你的選擇自由,交給H2Worker處理,數據封包對於H2引擎是透明的,但是建議大家使用pb或者thrift就好了,H2的ffrpc就是使用了thrift完成的進程間通信。本人更推薦thrift,因為thrift對於各個語言的支持更好,對於js這種處理二進位尷尬的語言都相容的很好。

   問題3的多語言問題,H2設計了ffrpc庫,每個語言只需要接入並實現幾個簡單介面就可以了,相當於每個語言都需要開發自己專用的H2Worker,比如H2WorkerPhp、H2WorkerPython、H2WorkerLua等,目前C++、Python、Lua、js、php的Worker實現已經集成到H2Engine中,也就是說如果你想用lua或者python來寫游戲伺服器,那你直接寫腳本就可以了。H2Engine晚些會加入支持的語言是C#。

   問題4併發與非同步的問題,H2Engine的設計是主邏輯單線程,提供一個IO線程池,IO操作用非同步+回調的方式完成。其實IO操作主要就是資料庫操作,IO線程會創建一個非同步IO句柄,每個IO句柄投遞的IO非同步操作都是串列保證順序的,所以IO線程池既能夠保證多線程併發,又能夠保證比如針對某個User的操作是順序的、可靠的。

   問題6性能量化的問題,由於客戶端的請求通過引擎被處理,那麼H2Worker上就可以收集到所有介面的性能數據,統計後格式化定時輸出,這樣就可以量化各個介面的的性能。甚至可以開發出圖形化展示工具,可以看介面性能隨時間的變化,或者不同介面間性能的比較。

   最後著重討論問題5數據共用的問題。前邊提到ffrpc提供了基於TCP進程間通信的機制,對於單機還是多機,都是無差別的,那麼H2Engine和H2Worker理論上放不同機器也是可以的。事實也的確如此,H2引擎其實對於多機是完美支持的,但是為什麼將H2的架構限制在同機器呢,這主要是考慮到數據共用的需求,同機情況下,H2Engine和H2Worker就可以通過共用記憶體共用數據,其效率和便捷性與多機tcp模式不可同日而語。經過權衡,要比較優雅的實現進程間共用數據,限制在同機可以大大的降低複雜性,雖然犧牲了一些可伸縮性。

  首先SharedMemory並不存儲共用的數據,只存需要更新的數據,相當於共用記憶體作為交換數據的媒介。進程間共用數據的流程如下:

  1. 每個H2Worker維護一個自己的ShareMemDataSet,在共用記憶體中創建一個信號量,並且單獨開一個線程,監聽在此信號量上,如果被觸發,則立即從共用記憶體拷貝要更新的數據到自己的進程,並投遞給主邏輯線程去更新SharedMemDataSet。由於ShareMemDataSet是主邏輯維護的,這樣的好處就是主邏輯線程如果只是讀取而不修改,那麼直接使用本線程的SharedMemDataSet數據,性能自然是杠杠的,比如行會數據一般讀取操作遠大於寫操作。

  2. 如果H2Worker要修改共用數據,他就要獲取共用記憶體上的全局鎖,然後拷貝要更新的數據到共用記憶體,然後喚醒其他H2Worker的信號量,待所有數據被拷貝完畢後,解除全局鎖,因為更新操作一定是主邏輯操作的,所以獲取完全局鎖後,主邏輯會自動檢查一下本地要更新的操作是否全部完成,保證加鎖完畢後,當前進程的SharedMemDataSet一定是最新的。下麵來一段模擬行會操作的偽代碼:

  這種數據同步有多個好處,首先是數據競爭,共用記憶體加鎖同步數據,效率非常高,使得加鎖的粒度較小,避免多進程鎖競爭。其二是更新操作很像發送消息,區別於非同步發送消息的機制是,消息發送完,其他worker的數據立即得到了更新,這是非同步消息發送機制不能比擬的。

總結

  1. H2引擎集成了websocket,也推薦大家在長連接應用中,逐漸使用websocket。
  2. 協議的封包pb、thrift已經很夠用了,H2引擎支持pb、thrift、json以及傳統二進位struct,但是推薦thrift,主要是效率和多語言支持都更好。
  3. 基於網游伺服器的場景,H2引擎考慮到單台物理機的處理能力當前足以應付單服的需求,所以將H2的架構設計為部署在同機上,這樣大大簡化了伺服器的架構,多gate的架構其實來源於rpg剛興起的年代,那時候伺服器的記憶體有限,cpu多核也還沒流行,但是今非昔比,單機模式也就是偽分散式模式其實更符合實際。
  4. 針對傳統網游伺服器架構中多進程數據共用的痛點,H2做了特殊的設計,由於H2Worker在同一臺機器上,得以使H2可以通過共用記憶體共用數據。
      大家知道,Apache+php之所以在web領域里流行,還有很大一個原因是php的框架又多又好用,相比而言,網游伺服器領域的引擎、框架都太落後了,主要原因還是伺服器沒有形成標準,這也是本人從業多年,孜孜不倦想要有所突破的地方。從web的成熟經驗來看,功能開發的快,就要有好多框架,要有好的框架,就要有成熟標準的引擎,現在市面上有些游戲伺服器引擎就經常會糅合引擎和框架的功能,有的甚至夾雜了游戲伺服器的數據結構和游戲邏輯。H2的設計哲學,引擎的歸引擎,框架的歸框架,雖然跟Apache相比距離“引擎”的稱號相距甚遠,但是這是H2的目標。另外,基於H2的框架也會不斷的增加完善。舉個例子,針對rpg游戲,我們可以設計出一套c++的框架,比如封裝地圖管理、角色管理、道具管理、任務系統、成就系統、副本系統、npc系統等,想想看,2d rpg領域相關的系統還是很好抽象的。問題是沒有標準的、成熟的引擎作為基礎。相關從業人員應該有共鳴,比如A團隊開發一套任務系統,給B團隊也是用不了啊,大家的定時器、資料庫介面都不一樣,無法做到拿來就用。如果大家都用H2,別人開源的系統分分鐘就可以拿來用,想象下還是挺美好的。不同的游戲類型框架實現是不一樣的,不同語言實現細節也會不同,使用H2引擎後可以根據不同游戲類型、不同語言分類框架,這個是後續擴展H2引擎的計劃。

相關連接

  1. 文檔 http://h2cloud.org
  2. 源碼 https://github.com/fanchy/h2engine

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1、首先在MyEclipse菜單欄找到"windows"下拉菜單中找到首選項(英文Prefenerces),彈出首選項界面。 2、打開java ——>editor > templates 就出現了templates界面 3、然後點擊右上角的"new",按鈕創建你的組合鍵,在"Name"處輸入你的快捷 ...
  • 剛開始先從最簡單的爬蟲邏輯入手 爬蟲最簡單的解析面真的是這樣 這隻是一個函數而已 那麼在下麵加上: 哈哈,搞定 就是這麼一個爬蟲了 太神奇 但是得到的只是網頁的html頁面的東西 而且還沒篩選 那麼就篩選吧 那就用上面的來解析一下我的博客園 解析的是<a>...</a>之間的東西 看起來還不錯吧 我 ...
  • 詳細說明:http://php.662p.com/thread-1023-1-1.html ...
  • 或許您正在使用 REST 端點(endpoint)來擺脫 Web 服務和客戶端。如果您是一名 Java 開發人員,您可能已經嘗試過 JAX-RS、Spring REST 或者兩者。但哪一個好用呢?在這篇文章中,我將介紹兩者之間的差異,使用大體相同的代碼進行對比。在之後的博文中,我將向您展示如何輕鬆地... ...
  • 測試代碼放在兩個地方纔有效果,一個是模塊開頭,一個是函數聲明語句的下一行 doctest 的概念模型 在python的官方文檔中,對doctest是這樣介紹的: doctest模塊會搜索那些看起來像是python互動式會話中的代碼片段,然後嘗試執行並驗證結果。 從名字上是否會讓你聯想到docstri... ...
  • 前面我們實現了使用PC端上位機串口發送圖像數據到VGA顯示,通過MATLAB處理的圖像數據直接是灰度圖像,後面我們在此基礎上修改,從而實現,基於FPGA的動態圖片的Sobel邊緣檢測、中值濾波、Canny運算元邊緣檢測、腐蝕和膨脹等。那麼這篇文章我們將來實現基於FPGA的Sobel邊緣檢測。 圖像邊緣 ...
  • 針對入門新手的普及,有過大型網站技術架構牛人路過,別耽誤浪費了時間,閱讀之前,請確保有一定的網路基礎,熟練使用Linux,瀏覽大概需要3 5分鐘的時間,結尾有彩蛋。 目錄 "分散式" "微服務" "負載均衡集群" "高可用集群" "彈性雲" "故障轉移" "總結" 分散式 小馬正在經營一個線上購物網 ...
  • 1.welcome dede 2.計算圓面積 ...
一周排行
    -Advertisement-
    Play Games
  • 前言 本文介紹一款使用 C# 與 WPF 開發的音頻播放器,其界面簡潔大方,操作體驗流暢。該播放器支持多種音頻格式(如 MP4、WMA、OGG、FLAC 等),並具備標記、實時歌詞顯示等功能。 另外,還支持換膚及多語言(中英文)切換。核心音頻處理採用 FFmpeg 組件,獲得了廣泛認可,目前 Git ...
  • OAuth2.0授權驗證-gitee授權碼模式 本文主要介紹如何筆者自己是如何使用gitee提供的OAuth2.0協議完成授權驗證並登錄到自己的系統,完整模式如圖 1、創建應用 打開gitee個人中心->第三方應用->創建應用 創建應用後在我的應用界面,查看已創建應用的Client ID和Clien ...
  • 解決了這個問題:《winForm下,fastReport.net 從.net framework 升級到.net5遇到的錯誤“Operation is not supported on this platform.”》 本文內容轉載自:https://www.fcnsoft.com/Home/Sho ...
  • 國內文章 WPF 從裸 Win 32 的 WM_Pointer 消息獲取觸摸點繪製筆跡 https://www.cnblogs.com/lindexi/p/18390983 本文將告訴大家如何在 WPF 裡面,接收裸 Win 32 的 WM_Pointer 消息,從消息裡面獲取觸摸點信息,使用觸摸點 ...
  • 前言 給大家推薦一個專為新零售快消行業打造了一套高效的進銷存管理系統。 系統不僅具備強大的庫存管理功能,還集成了高性能的輕量級 POS 解決方案,確保頁面載入速度極快,提供良好的用戶體驗。 項目介紹 Dorisoy.POS 是一款基於 .NET 7 和 Angular 4 開發的新零售快消進銷存管理 ...
  • ABP CLI常用的代碼分享 一、確保環境配置正確 安裝.NET CLI: ABP CLI是基於.NET Core或.NET 5/6/7等更高版本構建的,因此首先需要在你的開發環境中安裝.NET CLI。這可以通過訪問Microsoft官網下載並安裝相應版本的.NET SDK來實現。 安裝ABP ...
  • 問題 問題是這樣的:第三方的webapi,需要先調用登陸介面獲取Cookie,訪問其它介面時攜帶Cookie信息。 但使用HttpClient類調用登陸介面,返回的Headers中沒有找到Cookie信息。 分析 首先,使用Postman測試該登陸介面,正常返回Cookie信息,說明是HttpCli ...
  • 國內文章 關於.NET在中國為什麼工資低的分析 https://www.cnblogs.com/thinkingmore/p/18406244 .NET在中國開發者的薪資偏低,主要因市場需求、技術棧選擇和企業文化等因素所致。歷史上,.NET曾因微軟的閉源策略發展受限,儘管後來推出了跨平臺的.NET ...
  • 在WPF開發應用中,動畫不僅可以引起用戶的註意與興趣,而且還使軟體更加便於使用。前面幾篇文章講解了畫筆(Brush),形狀(Shape),幾何圖形(Geometry),變換(Transform)等相關內容,今天繼續講解動畫相關內容和知識點,僅供學習分享使用,如有不足之處,還請指正。 ...
  • 什麼是委托? 委托可以說是把一個方法代入另一個方法執行,相當於指向函數的指針;事件就相當於保存委托的數組; 1.實例化委托的方式: 方式1:通過new創建實例: public delegate void ShowDelegate(); 或者 public delegate string ShowDe ...