SLG手游Java服務器的設計與開發——架構分析


  • 文章版權歸騰訊GAD所有,禁止匿名轉載;禁止商業使用;禁止個人使用。

一、前言

從去年12月份開始,到現在,我全程參與了公司一款SLG手游的研發,負責整個游戲的服務端部分。這也是我第一次單獨負責一款網游的服務端開發,整個研發過程,也讓我的各方面技術提升了不少。目前這款游戲正在緊張的測試中,預計下周左右會在XY渠道進行一輪封測,以測試玩家對我們的游戲的反饋數據。

這款游戲集合市面上大多數SLG的特點,包含了卡牌、裝備、科技、建築的等養成內容,同時也在戰斗系統做了創新,通過卡牌搭配,裝備搭配,以及陣型搭配,再加上各方面的養成數據,能讓玩家在戰斗中產生不同的效果。同時,他最大的特點也是最核心的部分,就是國戰,不過很遺憾的是,第一版上線不會有國戰內容,因為在測試過程中,我們發現整個國戰的游戲機制還存在很多漏洞,我們將會持續優化,優化出一版完整的國戰內容,再呈現給玩家。

我經歷了整個開發過程,在游戲服務器開發方面有了不少新的認識,我想通過寫文章的方式把這些設計思路、技術難點、以及踩過的坑,都分享給大家,所以我們准備通過系列文章的方式一點一點把服務器的框架內容分享出來,本章首先從游戲服務器的架構分析開始。

二、功能介紹

在開始設計整個游戲服務器的架構之前,我首先需要對游戲的功能有所掌握。上文已經簡單提到了部分核心功能,比如卡牌、裝備、陣型等,但實際上游戲的內容並不止這些。這款游戲屬於SLG手游,即策略類的游戲,游戲以三國為題材,通過獲得三國名將卡牌,搭配各種裝備,設置戰斗陣型,達到在戰斗中的不同表現效果,戰斗模式類似於《小小軍團》的戰斗,但是小小軍團主要以兵種為核心,而我們的戰斗以武將為核心,不同武將有不同的技能,不同的戰斗屬性,合理搭配,才能發揮最大的效果。圍繞着這些游戲核心,設計了以下不同的功能模塊。

1.賬號系統

作為一款網游,最基礎的,就是賬號系統,一款網游一定會有賬號系統,這是保證玩家能從不同終端都能進入自己的游戲數據的憑證。不過最近在手游市場,一般情況游戲都不會有自己的賬號系統,而是接入第三方的賬號系統,比如騰訊游戲一般會讓玩家選擇QQ登錄或微信登錄,網易一般會讓玩家選擇網易賬號登錄,還有很多渠道如XY,海馬玩,快用等,都有自己的賬號系統,賬號系統的功能,就是保證玩家的唯一標識。

2.君主模塊

進入游戲之后,玩家就需要創建一個君主,並設置君主的名字,性別,頭像和國家。SLG游戲中,資源也是一個很重要的內容,所有的資源都是跟玩家直接相關的,所以資源內容也是跟君主相關,我們就可以把資源內容綁定在君主模塊中,玩家在游戲中,是扮演這個君主的角色,所有游戲中的資源消耗以及資源產出,都是跟君主息息相關。在競技場以及國戰等pvp玩法中,君主也是玩家在游戲的唯一身份顯示。

3.卡牌模塊

這款游戲在SLG的基礎之上加上了卡牌養成玩法,玩家需要通過收集卡牌來進行游戲的操作,卡牌包含了呂布、關羽、張飛、華雄等三國名將。卡牌分了白綠藍紫橙紅的品質分段,不同品質的卡牌有着不同的屬性數值。卡牌可以通過酒館抽卡獲得,抽卡分為單次抽卡和十連抽,十連抽會必中一張橙色卡片。卡牌具有星級屬性,多張相同的卡牌還可以進行升星操作,升星具有一定的失敗幾率,品質越高,失敗率越高。如果有多余的卡牌,還可以進行分解操作,分解卡牌可以獲得將魂和銀兩,而將魂還可以繼續用於抽卡。在戰斗中,上陣的卡牌將會增長經驗,而卡牌的等級,就與它的經驗相關。總結起來,卡牌具有等級和星級兩個養成屬性,其它還有統勇智以及攻擊防御,技能傷害,普攻傷害等基礎屬性。整個卡牌模塊還有很多養成點的。

4.裝備模塊

有了戰斗的卡牌,那就必須給卡牌配備裝備模塊了,所有的卡牌具有6個裝備位,每個裝備位對應一種裝備,裝備也分為了白綠藍紫橙紅的幾個品質階段,不同品質的卡牌也能給卡牌加上不同的屬性效果,卡牌同樣具有等級和星級兩個養成屬性以及其他的基礎屬性,裝備可以進行強化以強化等級,以及升星來提升裝備的星級,升星消耗任意的裝備作為材料。卡牌模塊配合裝備模塊,可以有更多的養成玩法的自由發揮空間。

5.道具模塊

游戲中也有常見的背包,背包中存放着各種道具,道具種類繁多,包括糧草、銀兩、經驗丹等資源道具,也可以在背包中查看擁有的卡牌和裝備。背包中可以直接使用道具,使用完道具就能增加相應的資源。

6.建築模塊

玩家剛進入游戲會看到很多建築,這些建築都具有不同的功能,升級這些建築會增強建築的屬性效果,建築包括皇城、軍機處、校場、倉庫、招商局、兵營、酒館、競技場、鐵匠鋪、農田(6個)、民居(6個),各個建築具有不同的功能,皇城等級限制所有建築的最高等級,軍機處可以解鎖升級科技,軍機處等級限制科技等級,倉庫等級限制最高資源上限,招商局等級限制民居產出,兵營等級限制兵力上限,鐵匠鋪等級限制裝備強化等級,農田和民居的等級限制資源的產出,競技場和酒館沒有等級,競技場是功能入口,酒館包含抽卡,卡牌升星和卡牌分解的功能。

7.科技模塊

軍機處的科技收到軍機處建築的等級限制,科技一共有30個,隨着軍機處的等級分別開放,不同的科技能增加不同的效果,其實有部分科技是屬於陣型,每解鎖一種陣型,就能在戰斗前設置戰斗的陣型,陣型中的位置也會隨着君主的等級而開放。

8.關卡模塊

游戲核心內容是戰斗,戰斗包含了普通關卡和精英關卡、以及競技場、國戰和日常副本。其中,普通關卡、精英關卡和日常副本在功能上來說是差不多的,只是戰斗中的數值配置不同,精英關卡和日常副本加了挑戰次數限制,日常副本還加了難度解鎖限制。

9.競技場

玩家的君主等級升級到16級時會開啟競技場,競技場是玩家第一次感覺自己玩的不是單機的內容,競技場的規則是打離線數據,服務器開服之后會初始化2000名機器人,玩家選擇挑戰前面排名的玩家,如果挑戰成功,則互換位次,如果挑戰失敗,則位次不變,同時成功失敗均會損失挑戰次數,挑戰次數次日刷新。

10.活動模塊

國產游戲最少不了的還是活動模塊了,做游戲除了賣情懷,就是賣活動,活動是一款游戲付費率最高的內容。這款游戲中包含的活動不多,只有每日簽到、會員、首沖、以及豪華簽到。每日簽到是每9天一個輪回,每天簽到送不同的獎勵,其他幾種活動均是需要充值人民幣之后再領取到相應的獎勵。

11.國戰模塊

國戰分為兩個模塊,國戰PVE和人國戰PVP,玩家30級開啟國戰之后會進入一個大地圖,地圖上有76座城池,玩家首先需要進入國戰PVE模塊,把所有的城池都攻打下來才會開啟國戰的PVP模塊,不過很遺憾的是,即將上線的版本的國戰PVP模塊並沒有開放,打完PVE之后就會彈出提示PVP暫未開放。雖然沒有開放,但實際上我們也做了一版國戰,不過在測試中發現其機制有問題,便決定優化之后再上線這個模塊。國戰PVE同關卡部分大同小異,只不過由闖關改為了攻打城池。

12.熱更新

現在的網游大部分都會有熱更新的功能,所謂熱更新,就是指用戶在不從應用商店更新游戲版本的情況下,直接進入游戲,在游戲中更新游戲版本。熱更新的原理就是在服務端存儲一個游戲版本,客戶端每次進入游戲先讀取服務端的版本信息,如果有最新版本,就直接從服務端進行下載,下載完在本地解壓更新本地資源,然后再進入游戲,這樣玩家就能看到最新版本的游戲資源。

以上是部分功能內容,其他還有很多邊緣的系統功能沒有介紹,通過這部分內容我們就可以開始對游戲的服務器框架進行分析設計了。

三、網絡通信

通過功能設計,可以發現,除了國戰模塊,游戲整體對實時性要求都不高,與前端商議之后,決定先使用HTTP短連接,國戰部分再做商議(但其實后來開發國戰模塊也是通過短連接實現的,因為其機制就是一個異步的機制),網絡通信的數據傳輸也暫時采用最簡單的JSON字符串。不過目前這個機制確實產生了很多問題,首先是HTTP協議,在其他模塊沒多大問題,但在國戰模塊的時候要求實時性較高,應該采用實時性更強的TCP長連接比較合適。另外就是數據傳輸的問題,直接采用JSON字符串確實也沒問題,但是傳輸字符串會讓傳輸信息量變大,這樣在弱網情況下會使得游戲的體驗很不好,如果采用二進制進行傳輸,就會好很多。這次的這方面問題沒有考慮周全,下一次我還是希望采用TCP長連接加Google Protobuffer這樣的二進制傳輸協議進行數據交互。

四、數據存儲

游戲數據分為兩部分:游戲數據和玩家數據,游戲數據指的是游戲中的靜態數據,如果簽到獎勵,戰斗掉落,抽卡概率等內容,這部分內容均由策划配置好靜態表,服務器啟動時直接讀取靜態表,將表中內容加載到服務器內存,使用時直接從內存讀取,而玩家數據指是隨着玩家的操作而變化的數據,這部分數據我又分為了冷數據和熱數據,熱數據即游戲中讀寫頻繁的數據,如免費抽卡次數、君主體力恢復、國戰城池狀態等,這部分數據的特點就是讀寫都很頻繁,並且數據結構各不相同,每時每刻這些數據都有可能產生變化,產生讀寫操作,這部分數據,數據結構各不相同,可以采用nosql數據庫,而Redis不僅是nosql數據庫,還是內存數據庫,非常適合這部分數據的存儲。冷數據,則指的是交互相對不是很頻繁的數據,如君主等級,卡牌等級,卡牌星級,裝備等級,裝備星級等,這部分數據的特點就是讀寫不是很頻繁,需要玩家做了一定操作才會發生變化,並且數據具有結構化的特點,這些數據可以抽象出關系型數據表,所以我采用了Mysql進行了這部分數據的存儲,為了考慮數據庫性能,我采用了Memcache進行Mysql結果集的緩存。后來我認為,其實游戲數據的結構應該是采用Mongo更符合需求,它多變的數據結構滿足游戲中的各種數據類型,但由於確實Mongo的實際開發經驗和維護經驗,也沒敢輕易嘗試。

五、架構設計

作為后端服務器,能否對前端請求快速做出響應,是判斷一個服務器性能是否良好的重要指標,對於客戶端來說,服務端就是一個url地址或者一個套接字,但是對於整個服務端架構來說,暴露給客戶端的或許只是其中的一個連接處理服務器。良好的服務端架構是整個服務端開發成功了一半。我個人經驗並不是很豐富,所以我所設計的架構也並不是很好的架構,大多數都是我參考了網上大量的關於服務端架構的文章之后的設計,在參考別人文章的過程中,自己也有了很多感悟。
根據游戲的需求,可將服務器大致分為登錄服務器、邏輯服務器、文件服務器、支付服務器、國戰服務器和聊天服務器。在第一輪進行封測時候只有一台服務器,所以目前所有的服務器設計均部署在同一台服務器上,提前設計好架構以便在以后更多玩家進來之后進行服務器分離,以承受更多的負載。
總體的結構設計圖如下:
服務器架構圖

1.登錄服務器

負責接入客戶端的登錄,選服的功能,多台登錄服務器可通過Nginx配置負載均衡以承載更多玩家的連接。玩家登錄選服之后,登錄服務器會返回邏輯服務器的地址,此時客戶端與登錄服務器便沒有任何關系,只需要拿着地址去連接相應的邏輯服務器,通過引導玩家去到不同的游戲服就實現了玩家流量的分流。

2.邏輯服務器

這是游戲中最重要的用於處理玩家游戲邏輯的服務器,玩家的所有邏輯操作都將基於此服務器,如果要用到其他的服務,則采用Rpc的通信方式調用其他服務器的進程,邏輯服務器與其他服務器的通信采用Motan Rpc框架,邏輯服務器作為Motan的調用方,其他服務器均作為Motan的服務方。

3.文件服務器

主要用於游戲中的熱更新,進入游戲前,客戶端將進行版本檢查,如果發現有最新版本的內容,會提供文件服務器的最新版本下載地址,客戶端請求文件服務器進行更新版本文件下載。

4.支付服務器

游戲中的充值付費均由支付服務器完成,在邏輯服務器調用支付操作之后,邏輯服務器會通過Motan Rpc調用支付服務器發起支付操作,之后支付服務器會開始調用相應的支付操作,目前游戲的支付一般是眾多平台的聯運,會接入第三方的支付SDK,各聯運商的支付接口規范各式各樣,開發商必須要遵循個平台的規范。

5.國戰服務器

國戰服務器負責處理游戲中的核心玩法——國戰玩法,由於國戰的同時在線人數可能較多,所以我把此部分單獨分為一個服務器,來處理國戰部分的內容,玩家通過邏輯服進入國戰服務器之后,所有的接入將會轉為國戰服務器,由國戰服務器來處理國戰相關的內容,這樣又能把一部分玩家流量分出來,承擔更多的負載。

6.聊天服務器

游戲暫無聊天功能,但如果以后加入聊天功能,會將此功能單獨分出來作為聊天服務器,處理游戲中的聊天信息。

六、系統架構

以上對服務器的部署架構進行了設計,以上設計按照功能划分,把游戲服務器分為了多個模塊,以邏輯服為中心,其他服為服務提供者的方式進行的服務器划分。各個模塊在承受不住玩家壓力時都可以再縱向做服務器的集群擴展,個人感覺這種設計還是比較合理的。由上可見,邏輯服務器是游戲服務器整個架構的核心。

架構設計之后就要開始對服務器中的技術進行選型,首先開發語言是定位了Java,那么從網絡層來說,常見的就有Servlet、Spring、Struts、Netty、和Mina,Servlet、Spring和Struts其實可以歸為一類,因為Spring和Struts實際上就是對Servlet的一層封裝,在Java Web開發來說,應該說已經是很成熟的技術了,他們其實已經對底層的鏈路做了良好的封裝,僅支持HTTP協議,用戶使用他們只需要關注核心的業務邏輯即可,但在Servlet3.0以前,Servlet的IO都是同步阻塞的IO處理(BIO),從3.0開始,才將Servlet API和NIO結合在了一起,在游戲中,玩家客戶端與游戲服務端的請求處理操作是非常頻繁的,從IO方式來看,顯然異步的NIO機制要比同步的BIO快很多,基於NIO能構建出IO處理速度更快的服務端,而Mina和Netty都是基於NIO的網絡框架。最終,在Servlet3和Netty,以及Mina中,我選擇了Netty作為我的網絡層框架,原因是Netty有更多的成熟案例,API開發更加簡易,並且有更多的社區和資料。
從數據層來說,前文已經提到了,我將使用Mysql來存儲玩家冷數據,用Redis存儲玩家熱數據,使用Mysql時結合Memcache緩存查詢結果集,增加數據庫的讀性能。使用Redis直接使用Redis官方的Jedis API即可,Jedis不僅能直接連接Redis,也能用Sentinel進行Redis的主從集群。Mysql我使用了Hibernate做數據庫ORM框架,原因是游戲中不會有太多的復雜查詢,最多會有一個類似於"where userid=1"這樣的查詢條件,沒有太復雜的SQL語句,Hibernate對JDBC做了良好的封裝,如果沒有很多復雜的SQL語句,則可以直接使用Hibernate即可。雖然Hibernate的性能不如MyBatis或JDBC,但有了Hibernate+Memcache的方案,相信能彌補一些性能上的不足。
還有其他一些技術就不再做過多的介紹,總體的架構流程如下:
1.游戲客戶端為Cocos2d,與服務器交互采用Http通信,數據傳輸采用Json格式字符串
2.服務器端的網絡層使用基於Netty實現的Http服務器
3.通過Netty接入客戶端請求,根據請求數據中的協議號,調用服務器中相對應的邏輯模塊
4.邏輯模塊處理消息,若要處理游戲數據則調用Jedis或Hibernate處理,若觸發某事件,則調用事件處理器
5.通過Netty的ChannelHandlerContext返回處理結果
6.客戶端與服務器交互的數據通過XXTea+Base64進行加密處理
系統架構圖如下:
系統架構圖

七、總結

至此,本文對游戲的架構分析的內容就結束了,我參加工作也不久,個人經驗很欠缺,文中描述的技術若有誤導的部分,還請幫忙指出來,不要繼續誤導其他人,再次感謝大家。本系列文章是我本人參與一款SLG手游服務端開發的一些個人見解,我只是想把我學到的,我知道的東西分享給大家。下章開始,我將從各個部分,以源代碼為基礎進行詳細介紹,下章先講講Netty在HTTP游戲服務器中的應用。

八、后續

從產品立項到開發,到測試,我經歷了整個開發的過程,整個過程除了讓我在個人技術上有了不少提升、對游戲服務器有了新的認識之外,也讓我對整個游戲行業有了很多的看法。在產品的研發過程中,我們團隊見證了COK的火爆,CR的興起,ChinaJoy中也看到了中國有很多優秀的手游作品,同時我們也看到了國家在7月1日開始對游戲行業立的新規,以及蘋果對中國政策的妥協。我們目前的狀態,可以說是挑戰與機遇並存,小型游戲CP團隊,不是生,就是死。在這大半年開發中,我們的產品也是在不斷調整方向,以適應殘酷的游戲市場,國家出了新規之后,我們也是第一時間就去申請了文網文以及游戲版號,足以見得,我們團隊的每個人,都想要在這場無聲的戰爭中活下來。眼看產品就要上線,我們也對自己這款產品做了上線后的數據目標以及盈利目標,不管怎么樣,我認為這是我們辛勤付出的東西,不管成功與否,我們都有了寶貴的經驗,也算對得起努力的付出了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM