抽個時間,把java語言開發遊戲服務器的技術盲點補上,方便複習。前端
注:這裏僅僅是討論流程解決方案,具體的細節等,不做說明。java
1.網絡通信mysql
1.1 遊戲客戶端與遊戲服務器的通信linux
客戶端複雜多變,好比傳統頁遊flash,手機遊戲,h5等,所用消息協議不一樣,但無非是tcp,http,websocket等。web
jdk傳統的阻塞io模式,顯然沒法知足遊戲高併發的需求。即便是nio(非阻塞io),對於研發人員來講開發成本大,錯誤率高,對於之後遊戲擴展算法
也是一個極大考驗。sql
1.7之後,jdk提供了aio(windows上是經過iocp實現了真正的異步io)。這樣全部的讀、寫、鏈接等通知,都經過數據庫
事件來驅動。因爲linux上未實現真正的異步,並且相比較nio,aio的效率提高不明顯,目前這種方式使用很少。後面會單獨一篇文章來講明如何apache
使用aio。json
java語言的偉大之處,不只僅是在語言自己,各類各樣的優秀框架也極大的簡化開發複雜度。對於遊戲通信這塊,netty(目前4版本較多)必然是
首選。netty實在太優秀了,這裏不做太多介紹,若是netty不瞭解的,能夠看我前幾篇博客的源碼,或者買本關於netty的書籍。
1.2 客戶端與服務器約定速成的通訊規則
通信框架咱們已經選用netty了,咱們已經接受到了客戶端的鏈接,網絡傳輸的碼流如何解析成程序熟悉的pojo對象,如何避免粘包,半包,
接着如何處理客戶端發送的消息,服務器又是如何通知客戶端呢?
經過上面幾種方案,能夠簡單的解決粘包和半包問題,netty經過某種神奇的手段(噠噠。。。)終於拿到了客戶端發送的消息內容。
這裏netty處理的內容不少,好比channelHandler的鏈式流程,好比ssl認證,讀寫超時,tcp最大鏈接數設置等,我就不細說了。
2.複雜的線程模型
遊戲的線程模型,較爲複雜,畫圖比較容易理解。這裏我就偷懶,概述一下常見的解決方案。
2.1咱們知道,在1網絡通信裏所說的一切消息編解碼,轉換pojo對象等,都是io作的事。io的線程數量,也是伴隨着遊戲類型和複雜度
不一樣而不一樣,咱們一般的設置是:cpu+1。
2.2上文中,咱們經過某種神奇的手段,拿到了客戶端發送的消息內容,這裏依然是io線程,你能夠想象下,若是客戶端發送一個A消息,
讓咱們從數據庫load 10W條數據,這裏會有必定的延遲操做,然而對於密集型的任務若是存在延遲,那麼玩家登錄、發送消息等會存在卡頓,
這對於rpg的遊戲來講,簡直就是災難。
2.3既然有卡頓了,那簡單啦,加個業務線程池,這個線程池的數量一般是:cpu。業務線程池執行咱們業務代碼邏輯,客戶端發送A消息,
咱們把A消息封裝成task,放在線程池裏最終執行。
好像能夠了?
咱們如今假設,客戶端先發了A消息,再發B消息,按照tcp和netty的處理機制,轉到遊戲這邊應該是A-->B的過程。可是咱們拋到線程池了,
如何保證線程池執行的有序性?阻塞隊列嗎?他們都不在一個thread裏。
2.4如何處理玩家消息的有序性?
客戶端與服務器的連接,至關於一個對話,有對話就必定有channel,有channel有必定有session(我封裝的xxSession來管理channel)。
針對同一個玩家用戶,session不變,session管理的channel不變,那麼channelId就不變。
每次客戶端不論是發送A消息,仍是發送B消息,他們的channelId都不變。因此在拋到線程池執行前,作個簡單的hash算法,保證
相同的channel都在同一個線程裏處理。
2.5還有嗎?
好比工會、氏族、搶購等業務,設計到公共數據的地方,玩家必然會有交互,如何保證數據最終的一致性呢?
有的朋友說加鎖,對,鎖是處理這種交互數據最簡單,也是最暴力的一種方式。這裏我引入了actor模型,我經過對比發現actor的模型
不是通常的好,他不只能夠共用線程池,同時還能讓全部的任務分片執行,不至於讓某個線程一直忙於處理某個集中型的任務。
若是對於actor不熟悉的同窗,能夠借鑑akka actor,我這裏用的是java actor。具體不細說。
2.6沒錯,上面的流程只是適用於slg,棋牌類型的遊戲,若是是針對rpg的場景類型呢?
解決方案就是加上玩家在場景的場景拷貝,以前2.4以玩家的channelId 進行hash索引,這裏以場景的sceneId爲單位便可。
3.跨服、多服的簡單解決方案
上面2步實現了單機最簡單的消息投遞方式,新的問題又來了,若是把網關服,用戶服獨立開,場景服務器獨立開,跨服等如何實現呢?
java多進程之間通信,看來rpc要派上用場了。遊戲這裏不比電商等業務,咱們全部的服務都是同java語言開發維護,因此一個簡單的chen-rpc就能夠搞定啦。
rpc具體的實現細節,不做過多討論。咱們實現的最終目標,遠程調用,就像本地調用同樣的方便便可。
4.遊戲後臺管理系統
簡單的前端框架xx抄過來,連ui都不用啦。
http服務,本身寫了一個,tomcat都省了,gm指令,web後臺登陸權限控制,運營客服線上操做等,恩,不用太複雜。
固然,運營讓你複雜,仍是要搞一搞的。
5.遊戲靜態數據的配置維護
策劃常常更改靜態表數據,對服務器來講,這種常駐內存的數據,
若是更改一次,服務器重啓一次,這樣不只僅是內網測試困難,線上怎麼辦呢?
5.1首先,策劃表數據配置通常都在excel中,這裏須要提供一個Excel解析工具,將excel數據,轉換成data.dat配置,或者json等,最終生成在服務器項目下的resource
資源包下。
5.2策劃更新維護時,經過4的遊戲後臺,上傳data.dat文件,同時從新reload靜態資源數據,將java內存值更改 。
6.動態數據的更新維護fixme
有靜態數據,那必然有要動態更改的數據,這種數據如何落地?會有緩存穿透嗎?若是線上有段代碼須要更新,怎麼辦?
6.1目前我接觸的幾款遊戲項目,選用的數據庫都是mysql,同時遊戲服務器內部有緩存。具體的緩存同步到數據庫方式,通常有兩種:
好了,orm開始登場啦。遊戲的數據類型簡單,表設定更容易,須要事務嗎?應該是不須要的。
因此,除了那些大的框架,好比hibernae,jpa,ibatis等,咱們能夠本身寫一個簡單的orm,具體參考:apache下的dbUtils
6.2java的一系列因素,決定了動態更新必定不是件容易的事。目前動態更新有多種,具體不做詳細介紹。可是,原理無外乎兩種:
7.尋路、視野
3d和2d目前我接觸的兩款遊戲設定不同,具體的我單獨分篇來介紹,這裏不過多說明。
8.遊戲壓測
這個我比較擅長了,目前也是主要幹這個事情,具體參考我上篇關於機器人壓測的介紹。
9.遊戲日誌系統
日誌系統很重要,不論是運營正常的數據需求,仍是咱們程序線上查找問題,日誌都是比較完美的解決方案。
具體也不細說了。
10.戰鬥系統+棋牌算法
10.1 slg回合制戰鬥
10.2 rpg即時性戰鬥
10.3 鬥地主等
單獨的文章來講明,具體不介紹了,每一個玩法也不盡相同。