負載均衡--大型在線系統實現的關鍵(服務器集羣架構的設計與選擇)

 負載均衡--大型在線系統實現的關鍵(服務器集羣架構的設計與選擇)

 

作者:sodme

網站:http://blog.csdn.net/sodme/archive/2005/06/12/393165.aspx

 

要了解此篇文章中引用的本人寫的另一篇文章,請到以下地址:
  http://blog.csdn.net/sodme/archive/2004/12/12/213995.aspx
  以上的這篇文章是早在去年的時候寫的了,當時正在作休閒平臺,一直在想着如何實現一個可擴充的支持百萬人在線的遊戲平臺,後來思路有了,就寫了那篇總結。文章的意思,重點在於闡述一個百萬級在線的系統是如何實施的,倒沒真正認真地考察過QQ遊戲到底是不是那樣實現的。

   近日在與業內人士討論時,提到QQ遊戲的實現方式並不是我原來所想的那樣,於是,今天又認真抓了一下QQ遊戲的包,結果確如這位兄弟所言,QQ遊戲的架 構與我當初所設想的那個架構相差確實不小。下面,我重新給出QQ百萬級在線的技術實現方案,並以此展開,談談大型在線系統中的負載均衡機制的設計。

  從QQ遊戲的登錄及遊戲過程來看,QQ遊戲中,也至少分爲三類服務器。它們是:
  第一層:登陸/賬號服務器(Login Server),負責驗證用戶身份、向客戶端傳送初始信息,從QQ聊天軟件的封包常識來看,這些初始信息可能包括“會話密鑰”此類的信息,以後客戶端與後續服務器的通信就使用此會話密鑰進行身份驗證和信息加密;
  第二層:大廳服務器(估且這麼叫吧, Game Hall Server),負責向客戶端傳遞當前遊戲中的所有房間信息,這些房間信息包括:各房間的連接IP,PORT,各房間的當前在線人數,房間名稱等等。
  第三層:遊戲邏輯服務器(Game Logic Server),負責處理房間邏輯及房間內的桌子邏輯。

  從靜態的表述來看,以上的三層結構似乎與我以前寫的那篇文章相比並沒有太大的區別,事實上,重點是它的工作流程,QQ遊戲的通信流程與我以前的設想可謂大相徑庭,其設計思想和技術水平確實非常優秀。具體來說,QQ遊戲的通信過程是這樣的:

   1.由Client向Login Server發送賬號及密碼等登錄消息,Login Server根據校驗結果返回相應信息。可以設想的是,如果Login Server通過了Client的驗證,那麼它會通知其它Game Hall Server或將通過驗證的消息以及會話密鑰放在Game Hall Server也可以取到的地方。總之,Login Server與Game Hall Server之間是可以共享這個校驗成功消息的。一旦Client收到了Login Server返回成功校驗的消息後,Login Server會主動斷開與Client的連接,以騰出socket資源。Login Server的IP信息,是存放在QQGame\config\QQSvrInfo.ini裏的。

  2.Client收到Login Server的校驗成功等消息後,開始根據事先選定的遊戲大廳入口登錄遊戲大廳,各個遊戲大廳Game Hall Server的IP及Port信息,是存放在QQGame\Dirconfig.ini裏的。Game Hall Server收到客戶端Client的登錄消息後,會根據一定的策略決定是否接受Client的登錄,如果當前的Game Hall Server已經到了上限或暫時不能處理當前玩家登錄消息,則由Game Hall Server發消息給Client,以讓Client重定向到另外的Game Hall Server登錄。重定向的IP及端口信息,本地沒有保存,是通過數據包或一定的算法得到的。如果當前的Game Hall Server接受了該玩家的登錄消息後,會向該Client發送房間目錄信息,這些信息的內容我上面已經提到。目錄等消息發送完畢後,Game Hall Server即斷開與Client的連接,以騰出socket資源。在此後的時間裏,Client每隔30分鐘會重新連接Game Hall Server並向其索要最新的房間目錄信息及在線人數信息。

  3.Client根據列出的房間列表,選擇某個房間進入遊戲。根據我的抓 包結果分析,QQ遊戲,並不是給每一個遊戲房間都分配了一個單獨的端口進行處理。在QQ遊戲裏,有很多房間是共用的同一個IP和同一個端口。比如,在鬥地 主一區,前50個房間,用的都是同一個IP和Port信息。這意味着,這些房間,在QQ遊戲的服務器上,事實上,可能是同一個程序在處理!!!QQ遊戲房 間的人數上限是400人,不難推算,QQ遊戲單個服務器程序的用戶承載量是2萬,即QQ的一個遊戲邏輯服務器程序最多可同時與2萬個玩家保持TCP連接並 保證遊戲效率和品質,更重要的是,這樣可以爲騰訊省多少money呀!!!哇哦!QQ確實很牛。以2萬的在線數還能保持這麼好的遊戲品質,確實不容 易!QQ遊戲的單個服務器程序,管理的不再只是邏輯意義上的單個房間,而可能是許多邏輯意義上的房間。其實,對於服務器而言,它就是一個大區服務器或大區 服務器的一部分,我們可以把它理解爲一個龐大的遊戲地圖,它實現的也是分塊處理。而對於每一張桌子上的打牌邏輯,則是有一個統一的處理流程,50個房間的 50*100張桌子全由這一個服務器程序進行處理(我不知道QQ遊戲的具體打牌邏輯是如何設計的,我想很有可能也是分區域的,分塊的)。當然,以上這些只 是服務器作的事,針對於客戶端而言,客戶端只是在表現上,將一個個房間單獨羅列了出來,這樣作,是爲便於玩家進行遊戲以及減少服務器的開銷,把這個大區中 的每400人放在一個集合內進行處理(比如聊天信息,“向400人廣播”和“向2萬人廣播”,這是完全不同的兩個概念)。

  4.需要特 別說明的一點。進入QQ遊戲房間後,直到點擊某個位置坐下打開另一個程序界面,客戶端的程序,沒有再創建新的socket,而仍然使用原來大廳房間客戶端 跟遊戲邏輯服務器交互用的socket。也就是說,這是兩個進程共用的同一個socket!不要小看這一點。如果你在創建桌子客戶端程序後又新建了一個新 的socket與遊戲邏輯服務器進行通信,那麼由此帶來的玩家進入、退出、逃跑等消息會帶來非常麻煩的數據同步問題,俺在剛開始的時候就深受其害。而一旦 共用了同一個socket後,你如果退出桌子,服務器不涉及釋放socket的問題,所以,這裏就少了很多的數據同步問題。關於多個進程如何共享同一個 socket的問題,請去google以下內容:WSADuplicateSocket。

  以上便是我根據最新的QQ遊戲抓包結果分析得到的QQ遊戲的通信流程,當然,這個流程更多的是客戶端如何與服務器之間交互的,卻沒有涉及到服務器彼此之間是如何通信和作數據同步的。關於服務器之間的通信流程,我們只能基於自己的經驗和猜想,得出以下想法:

   1.Login Server與Game Hall Server之前的通信問題。Login Server是負責用戶驗證的,一旦驗證通過之後,它要設法讓Game Hall Server知道這個消息。它們之前實現信息交流的途徑,我想可能有這樣幾條:a. Login Server將通過驗證的用戶存放到臨時數據庫中;b. Login Server將驗證通過的用戶存放在內存中,當然,這個信息,應該是全局可訪問的,就是說所有QQ的Game Hall Server都可以通過服務器之間的數據包通信去獲得這樣的信息。

  2.Game Hall Server的最新房間目錄信息的取得。這個信息,是全局的,也就是整個遊戲中,只保留一個目錄。它的信息來源,可以由底層的房間服務器逐級報上來,報給誰?我認爲就如保存的全局登錄列表一樣,它報給保存全局登錄列表的那個服務器或數據庫。

  3.在QQ遊戲中,同一類型的遊戲,無法打開兩上以上的遊戲房間。這個信息的判定,可以根據全局信息來判定。

   以上關於服務器之間如何通信的內容,均屬於個人猜想,QQ到底怎麼作的,恐怕只有等大家中的某一位進了騰訊之後才知道了。呵呵。不過,有一點是可以肯定 的,在整個服務器架構中,應該有一個地方是專門保存了全局的登錄玩家列表,只有這樣才能保證玩家不會重複登錄以及進入多個相同類型的房間。

  在前面的描述中,我曾經提到過一個問題:當登錄當前Game Hall Server不成功時,QQ遊戲服務器會選擇讓客戶端重定向到另位的服務器去登錄,事實上,QQ聊天服務器和MSN服務器的登錄也是類似的,它也存在登錄重定向問題。

  那麼,這就引出了另外的問題,由誰來作這個策略選擇?以及由誰來提供這樣的選擇資源?這樣的處理,便是負責負載均衡的服務器的處理範圍了。由QQ遊戲的通信過程分析派生出來的針對負責均衡及百萬級在線系統的更進一步討論,將在下篇文章中繼續。

  在此,特別感謝網友tilly及某位不便透露姓名的網友的討論,是你們讓我決定認真再抓一次包探個究竟。

 

      在網絡應用中,“負載均衡”已經不能算是什麼新鮮話題了,從硬件到軟件,也都有了很多的方法來實現負載均衡。我們這裏討論的負載均衡,並不是指依靠DNS轉向或其它硬件設備等所作的負載均衡,而是指在應用層所作的負載均衡。

  一般而言,只有在大型在線系統當中纔有必要引入負載均衡,那麼,多大的系統才能被稱爲大型系統呢?比如動輒同時在線數十萬的網絡遊戲,比如同時在線數在10萬以上的WEB應用,這些我們都可以理解爲大型系統,這本身就是一個寬泛的概念。

   設計再好的服務器程序,其單個程序所能承載的同時訪問量也是有限的,面對一個龐大且日益增長的網絡用戶羣,如何讓我們的架構能適應未來海量用戶訪問,這 自然就牽涉到了負載均衡問題。支持百萬級以上的大型在線系統,它的架構核心就是如何將“百萬”這麼大的一個同時在線量分攤到每個單獨的服務器程序上去。真 正的邏輯處理應該是在這最終的底層的服務器程序(如QQ遊戲平臺的遊戲房間服務器)上的,而在此之前所存在的那些服務器,都可以被稱爲“引路者”,它們的 作用就是將客戶端一步步引導到這最終的負責真正邏輯的底層服務器上去,我們計算“百萬級在線”所需要的服務器數量,也是首先考慮這底層的邏輯服務器單個可 承載的客戶端連接量。

  比如:按上篇我們所分析QQ遊戲架構而言,假設每個服務器程序最高支持2W的用戶在線(假設一臺機子只運行一個 服務器程序),那麼實現150萬的在線量至少需要多少臺服務器呢?如果算得簡單一點的話,就應該是:150/2=75臺。當然,這樣算起來,可能並不能代 表真正的服務器數量,因爲除了這底層的服務器外,還要包括登錄/賬號服務器以及大廳服務器。但是,由於登錄/賬號服務器和大廳服務器,它們與客戶端的連接 都屬於短連接(即:取得所需要信息後,客戶端與服務器即斷開連接),所以,客戶端給這兩類服務器帶來的壓力相比於長連接(即:客戶端與服務器始終保持連 接)而言就要輕得多,它們的壓力主要在處理瞬間的併發訪問上。

  “短連接”,是實現應用層負載均衡的基本手段!!!如果客戶端要始終與登錄/賬號服務器以及大廳服務器保持連接,那麼這樣作的分層架構將是無意義的,這也沒有辦法從根本上解決用戶量不斷增長與服務器數量有限之間的矛盾。

   當然,短連接之所以可以被使用並能維護正常的遊戲邏輯,是因爲在玩家看不到的地方,服務器與服務器之間進行了大量的數據同步操作。如果一個玩家沒有登錄 到登錄服務器上去而是直接連接進了遊戲房間服務器並試圖進行遊戲,那麼,由於遊戲房間服務器與大廳服務器和登錄/賬號服務器之間都會有針對於玩家登錄的邏 輯維護,遊戲房間服務器會檢測出來該玩家之前並沒有到登錄服務器進行必要的賬號驗證工作,它便會將玩家踢下線。由此看來,各服務器之間的數據同步,又是實 現負載均衡的又一必要條件了。

  服務器之間的數據同步問題,依據應用的不同,也會呈現不同的實現方案。比如,我們在處理玩家登錄這個問 題上。我們首先可以向玩家開放一些默認的登錄服務器(服務器的IP及PORT信息),當玩家連接到當前的登錄服務器後,由該服務器首先判斷自己同時連接的 玩家是不是超過了自定義的上限,如果是,由向與該服務器連接着的“登錄服務器管理者”(一般是一個內部的服務器,不直接向玩家開放)申請仲裁,由“登錄服 務器管理者”根據當前各登錄服務器的負載情況選擇一個新的服務器IP和PORT信息傳給客戶端,客戶端收到這個IP和PORT信息之後重定向連接到這個新 的登錄服務器上去,完成後續的登錄驗證過程。

  這種方案的一個特點是,在面向玩家的一側,會提供一個外部訪問接口,而在服務器集羣的內部,會提供一個“服務器管理者”及時記錄各登錄服務器的負載情況以便客戶端需要重定向時根據策略選擇一個新的登錄接口給客戶端。

   採用分佈式結構的好處是可以有效分攤整個系統的壓力,但是,不足點就是對於全局信息的索引將會變得比較困難,因爲每個單獨的底層邏輯服務器上都只是存放 了自己這一個服務器上的用戶數據,它沒有辦法查找到其它服務器上的用戶數據。解決這個問題,簡單一點的作法,就是在集羣內部,由一箇中介者,提供一個全局 的玩家列表。這個全局列表,根據需要,可以直接放在“服務器管理者”上,也可以存放在數據庫中。

  對於邏輯相對獨立的應用,全局列表的 使用機會其實並不多,最主要的作用就是用來檢測玩家是不是重複登錄了。但如果有其它的某些應用,要使用這樣的全局列表,就會使數據同步顯得比較複雜。比 如,我們在超大無縫地圖的MMORPG裏,如果允許跨服操作(如跨服戰鬥、跨服交易等)的話,這時的數據同步將會變得異常複雜,也容易使處理邏輯出現不可 預測性。

  我認爲,對於休閒平臺而言,QQ遊戲的架構已經是比較合理的,也可以稱之爲休閒平臺的標準架構了。那麼,MMORPG一般的架構是什麼樣的呢?

   MMORPG一般是把整個遊戲分成若干個遊戲世界組,每個組內其實就是一個單獨的遊戲世界。而不同的組之間,其數據皆是相互獨立的,並不象QQ休閒平臺 一樣所有的用戶都會有一個集中的數據存放點,MMORPG的遊戲數據是按服務器組的不同而各自存放的。玩家在登錄QQ遊戲時,QQ遊戲相關的服務器會自動 爲玩家的登錄進行負載均衡,選擇相對不忙的服務器爲其執行用戶驗證並最終讓用戶選擇進入哪一個遊戲房間。但是,玩家在登錄MMORPG時,卻沒有這樣的自 動負載均衡,一般是由玩家人爲地去選擇要進入哪一個服務器組,之所以這樣,是因爲各服務器組之間的數據是不相通的。其實,細緻想來,MMORPG的服務器 架構思想與休閒平臺的架構思想有異曲同工之妙,MMORPG的思想是:可以爲玩家無限地開獨立的遊戲世界(即服務器組),以滿足大型玩家在線;而休閒平臺 的思想則是:可以爲玩家無限地開遊戲房間以滿足大量玩家在線。這兩種應用,可以無限開的都是“具有完整遊戲性的遊戲世界”,對於MMORPG而言,它的一 個完整的遊戲地圖就是一個整體的“遊戲世界”,而對於休閒平臺,它的一個遊戲房間就可以描述爲一個“遊戲世界”。如果MMORPG作成了休閒平臺那樣的全 服皆通,也不是不可以,但隨之而來的,就是要解決衆多跨服問題,比如:好友、組隊、幫派等等的問題,所有在傳統MMORPG裏所定義的這些玩家組織形式的 規則可能都會因爲“全服皆通”而改變。

  架構的選擇是多樣性的,確實沒有一種可以稱得上是最好的所謂的架構,適合於當前項目的,不一定就適合於另一個項目。針對於特定的應用,會靈活選用不同的架構。但有一點,是可以說的:不管你如何架構,你所要作的就是--要以儘可能簡單的方案實現儘可能的穩定、高效!

發佈了59 篇原創文章 · 獲贊 1 · 訪問量 3481
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章