利用Terracotta實現SmartFoxServer2X集羣

博客搬家啦——爲了更好地經營博客,本人已經將博客遷移至www.ijavaboy.com。這裏已經不再更新,給您帶來的不便,深感抱歉!這篇文章的新地址:點擊我微笑


        兩個多月沒有更新博客了,那是因爲剛進入一個新的領域,瘋狂地學習並工作。這兩個月,對於我來說,是一次新的旅程。從之前的Android開發,一不小心溜入遊戲服務器端的開發。現在,終於有了一點閒暇,記錄一下這兩個月中學到的和領悟到的知識。

        兩個月前,進入一家做互聯網3D產品的創業公司,而我負責的,正是服務器端的開發。和傳統的3D遊戲不同,這裏沒有複雜的遊戲邏輯,只專注於產品需要的功能,客戶端中不外乎用戶的登陸和聊天等功能。而服務器端主要的任務就是處理用戶的登陸登出和各種信息的同步。之前的一個月,學習了SmartFoxServer引擎,同時一併學習了下Unity3D引擎(因爲客戶端使用的是這個,學這個主要是爲了可以很好地和客戶端配合)。

        一直到幾個星期前,當老大說要支持高達200000個用戶同時在線的時候,才知道SFS2X試用版最多隻可以支持100個用戶,幾經周折破解了SFS2X,消除了這個限制。但是,就算消除了限制,讓一臺機子同時處理200K個用戶同時在線並操作,最後的結果只有一個——它將活活累死!於是,到SFS官方論壇和網站上尋求答案,雖然英文馬馬虎虎,但還可以表情達意,最終得知Terracotta是個好東東。而且官方有一個SmartFoxServer1.6和Terracotta集成的文檔。

       正當我興致突起,準備大幹一場的時候,無意中被當頭一棒——SmartFoxServer2X明確表態,從2X起,SmartFoxServer不再支持Terracotta集羣。花了好幾個晝晝夜夜,在其官方論壇上用那生硬的English發帖詢問,結果終於得到證實,2X開始真的不支持或者不再提倡使用Terracotta來集羣。再次看到1.6的那份官方集羣文檔的最後一句:

      Finally the future releases of SmartFoxServer  will move towards a tighter integration with Terracotta,
      to provide even more distributed services out of the box, and further simplify the development

我不禁啞然!

        後來,翻閱了大量了官方論壇上的帖子,卻又找到官方人員的相關言論說,可以按照1.6思想的來使用Terracotta完成SFS的集羣。於是,我決定嘗試一把...

        寫好了集羣擴展的代碼,當想要測試一把的時候,才發現,怎樣讓Terracotta識別SFS2X呢?也就是怎樣將SFS2X作爲Terracotta集羣的客戶端來啓動呢?

       下載了1.6的集羣的Demo,看到了它是使用了一個新的bat文件來啓動的。看了下這個文件,其中含有Terracotta的啓動包,終於明白了,原來如此。於是將其拷貝到

SFS2X的啓動bat文件中,成功實現將SFS2X加入到Terracotta集羣中。通過Terracotta Developer Console也可以看到連接上的客戶端。

興奮之餘,將寫好的SFS2X集羣擴展Demo打了個jar包放到了SFS2X中,又寫了個測試的Client,結果一運行,報了一個大大的異常,從異常信息看出,這個和ClassLoader有關。

        之前學習SFS2X的時候,看到過官方介紹過2X中使用了新的ClassLoader機制。核心SFS2X使用SystemClassLoader加載,每一個擴展使用一個新的ClassLoader進行加載,這樣是爲了方便應用擴展的熱部署。但是,這個熱部署我倒不太願意用,現在又因爲這個鳥東東和Terracotta集羣有了衝突。

        從Terracotta的官方論壇中又再次得知,加載Terracotta中共享數據的ClassLoader必須命名,Terracotta就是根據ClassLoader的名稱來完成不同JVM之間相同數據的同步。

        這下徹底死了個翹翹,難道註定了無法實現SFS2X和Terracotta的集成嗎?心有不甘。。。

       這時,一個強烈的念頭湧上心頭,SmartFoxServer2X不是用java寫的嘛,反編譯你的源碼,殊死一搏吧。

       這個時候,發現其代碼並沒有進行加密,心中大喜。反編譯後的代碼清楚無比,看到了在加載每個擴展的時候,其都定義了一個URLClassLoader來完成擴展的加載。那麼我現在就需要替換掉這個URLClassLoader,而使用自己的定義的ClassLoader。

       於是引入Terracotta和SmartFoxServer相關的jar包,重新實現了個命了名的ClassLoader,讓這個ClassLoader完成擴展的加載。

       打成jar包,替換掉原來的jar包,運行起來,OK!測試通過,集羣終於實現。

       實現集羣的目的,主要是爲了分擔負載和容錯。那麼現在如何實現負載均衡成爲一個關鍵,看了很多關於負載均衡的資料,基本是基於Http請求的負載均衡。但是,對於像SmartFoxServer一樣的遊戲服務器端引擎來說,其使用的往往是Tcp或者Udp協議。而我們知道,Http協議是無狀態的,用戶的每一次請求都可以做到負載均衡。而Tcp或者Udp使用的是長連接的形式,用戶一旦和某個物理機器連接了,那麼直到他主動退出或者這個物理機器上的SmartFoxServer出現故障,否則其在登陸中所發出的每一次請求都是在同一個TCP或者UDP連接中完成的。那麼如何實現SFS2X的負載均衡呢?



       有兩個思路:

        1、客戶端維護一個服務器端可用的SFS2X節點的列表,然後每次請求的時候隨即獲取一個進行連接,如果請求超時或者失敗,則再重新選擇一個嘗試連接。但是這個方案不能根據負載狀況進行請求。

        2、就是外加一個負載均衡服務器,這個服務器作爲一個普通的Web Server。可以使用Tomcat或者Apache等。他主要的功能就是負責維護每個SFS2X節點的負載情況(每個節點上登陸的用戶數)和可用的SFS2X節點信息。當一個客戶端請求登陸SFS2X服務器的時候,其首先發送Http請求到這個WebServer,這個WebServer會查詢並返回當前所有可用的節點和每個節點對應的負載信息。然後,客戶端根據返回的數據,選擇一個負載最小的節點進行連接。但是這個方案,這個單點的WebServer容易成爲整個系統的瓶頸,同時可能成爲單點故障。但是這個可以使用傳統的負載均衡技術來避免這些問題。


        第一個基本排除,採用第二個。但是第二個又引發一個問題。就是負載均衡服務器和SFS2X集羣如何完成數據的同步。是每個SFS2X節點每隔一定的時間將連接到本機的用戶數等信息發送到一個存儲媒介,這樣,負載均衡服務器每次只需要查詢這個存儲媒介就可以了。但是,這個會成爲瓶頸嗎?

I DON'T KNOW,JUST TEST IT!











發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章