線上bug的解決方案--帶來的全新架構設計
緣由
本人從事遊戲開發很多年一直都是遊戲伺服器端開發。
因為個人原因吧,一直在小型公司,或者叫創業型團隊工作吧。這樣的環境下不得不逼迫我需要什麼都會,什麼做。
但是自我感覺好像什麼都不精通。。。。。
好了好像偏題了!
迴歸正題
現在公司是做手遊開發,java伺服器 + U3D做客戶端的mmo手遊,仿魔獸世界!
做軟體的都知道一個蛋疼的事情,那就是線上Bug。但是做服務的人更清楚另一個蛋疼的事情,就是線上更新,不停服更新。
知道的人,想想都蛋疼,當然不知道的,那就只能自己想象了。
線上經常出問題大家都是能理解的。bug肯定是有的。做服務的同僚應該都知道,不到維護的時間是不能停止服務區更新的除非是非常重大的bug。
這裡面遊戲伺服器更為嚴格,因為你無故維護,維護一次可能就會流失一批玩家。所以這一直是一個梗。
本人經過三個星期的研究和測試,最終發現一個可以解決這種一出現bug,卻能線上更新,且不影響效能的觸發方式。
通過這樣一個方式,主程式,加資料庫,通過指令碼實現邏輯模組;
這樣就有一個指令碼的實現形式,指令碼如果實現的不好,那麼效能消耗就很大了。
我的做法是把邏輯部分的方法抽象出來。放到指令碼去實現。通過指令碼把實現指令碼邏輯程式碼在註冊會邏輯模組。
這樣的做法能保證我們有邏輯模組有bug的時候及時的修改邏輯,再次註冊指令碼已到達熱更新效果。保證伺服器執行的穩定性。
我們開始吧。
首先我要說一下我這裡使用的是C#語言作為講解。java也是一樣的道理。
不在贅述,如果需要程式碼實現的可以留言!
這裡可能牽涉到我之前的一些文章包含的類容,比如指令碼載入器,日誌模組,http監聽模組。
我們先建立一個控制檯專案叫TestApp
在新建一個類庫專案 TestApp.Scripts
基本工作已經完成了。
接下來,我們在TestApp下面新建一個類IMainManager
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 7 8 /** 9 * 10 * @author 失足程式設計師 11 * @Blog http://www.cnblogs.com/ty408/12 * @mail [email protected] 13 * @phone 13882122019 14 * 15 */ 16 namespace TestApp 17 { 18 /// <summary> 19 /// 20 /// </summary> 21 public interface IMainManagerScript 22 { 23 24 void Test(); 25 26 } 27 }
我們在TestApp下面新建一個類MainManager
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 7 8 /** 9 * 10 * @author 失足程式設計師 11 * @Blog http://www.cnblogs.com/ty408/ 12 * @mail [email protected] 13 * @phone 13882122019 14 * 15 */ 16 namespace TestApp 17 { 18 /// <summary> 19 /// 20 /// </summary> 21 public class MainManager : IMainManagerScript 22 { 23 24 public static MainManager instance = new MainManager(); 25 26 public static MainManager GetInstance() 27 { 28 return instance; 29 } 30 31 public IMainManagerScript IScript; 32 33 public void Test() 34 { 35 IScript.Test(); 36 } 37 38 } 39 }
接下來我們在TestApp.Scripts 新建一個檔案
1 using Net.Sz.Framework.Log; 2 using Net.Sz.Framework.Script; 3 using System; 4 using System.Collections.Generic; 5 using System.Linq; 6 using System.Text; 7 using System.Threading.Tasks; 8 9 10 /** 11 * 12 * @author 失足程式設計師 13 * @Blog http://www.cnblogs.com/ty408/ 14 * @mail [email protected] 15 * @phone 13882122019 16 * 17 */ 18 namespace TestApp.Scripts 19 { 20 /// <summary> 21 /// 22 /// </summary> 23 public class MainManagerScript : BaseScript, IMainManagerScript 24 { 25 26 public void Test() 27 { 28 Logger.Info("我是test"); 29 } 30 31 public override void InitScript() 32 { 33 MainManager.GetInstance().IScript = this; 34 Logger.Info("MainManagerScripttest InitScript"); 35 } 36 37 } 38 }
1 using Net.Sz.Framework.Log; 2 using System; 3 using System.Collections.Generic; 4 using System.Linq; 5 using System.Text; 6 using System.Threading.Tasks; 7 8 namespace TestApp 9 { 10 class Program 11 { 12 static void Main(string[] args) 13 { 14 //Logger.LOGCONSOLE = true;//不在控制檯列印資訊 15 //Logger.LOGLEVEL = Logger.ENUM_LOGLEVEL.INFO;//不顯示debug訊息 16 Logger.Info("==================Start============================"); 17 18 Net.Sz.Framework.Script.ScriptManager.GetInstance().LoadCSharpFile(new string[] { "../../../TestApp.Scripts/" }); 19 20 MainManager.GetInstance().Test(); 21 22 Logger.Info("==================End============================"); 23 Console.ReadLine(); 24 } 25 } 26 }View Code
我們先嚐試執行一次
也許上面的列印太亂,我們看看簡潔版本的
上面我們看樣看出來,功能是沒有問題的。
如果你稍微注意了,或者看過我之前的文章的話,會發現我的這個指令碼沒有實現IBaseScript介面,而只繼承了BaseScript抽象類。
因為這樣的指令碼不需要放到指令碼儲存器裡面,只需要執行init函式,把指令碼自身反註冊到主程式函式體裡面!
現在就是牽涉更新的事情。
更新有一個問題,當服務一旦部署後需要更新那就是的再次執行載入指令碼方法。如果你使用windows服務執行的,更新勢必是一個問題。
這裡我只介紹一種方式,http監聽方式。
要開啟http監聽方式,需要一個Net.Sz.Framework.Netty.Http.IHttpHandler的實現類
1 using Net.Sz.Framework.Log; 2 using System; 3 using System.Collections.Generic; 4 using System.Linq; 5 using System.Text; 6 using System.Threading.Tasks; 7 8 9 /** 10 * 11 * @author 失足程式設計師 12 * @Blog http://www.cnblogs.com/ty408/ 13 * @mail [email protected] 14 * @phone 13882122019 15 * 16 */ 17 namespace TestApp 18 { 19 /// <summary> 20 /// 21 /// </summary> 22 public class ReloadScriptHandler : Net.Sz.Framework.Netty.Http.IHttpHandler 23 { 24 public void Action(Net.Sz.Framework.Netty.Http.HttpSession session, string method, string bindpath, Dictionary<string, string> parms) 25 { 26 Logger.Info("收到請求"); 27 28 Net.Sz.Framework.Script.ScriptManager.GetInstance().LoadCSharpFile(new string[] { "../../../TestApp.Scripts/" }); 29 MainManager.GetInstance().Test(); 30 31 session.writeSuccess(); 32 session.AddBodyLine("OK"); 33 session.WriteFlush(); 34 } 35 } 36 }
接下來我們在主函式加入下面程式碼
Dictionary<string, Net.Sz.Framework.Netty.Http.IHttpHandler> handlers = new Dictionary<string, IHttpHandler>(); handlers.Add("ReloadScript", new ReloadScriptHandler());//開啟對http監聽,監聽模組為 ReloadScript Net.Sz.Framework.Netty.NettyPool.GetInstance().AddHttpBind("127.0.0.1", 9527, handlers);
執行起來,看看,
可以看出,開啟了http監聽,reloadscript
然後我們修改一下MainManagerScript檔案的Test方法
public void Test() { Logger.Info("我是test 修改過的版本"); }
在瀏覽器輸入:http://127.0.0.1:9527/reloadscript
執行時成功的。這樣的架構方式,很適合的是遊戲開發,某些功能塊很容易出bug,如果用指令碼儲存器訪問比較耗費效能。
這樣反向註冊功能塊指令碼到功能塊,既能實現bug的熱更新,也不會影響效能消耗。
如果有疑問可以留言哦。如果你覺得這純粹是扯淡,也歡迎留言。
不要問我,邏輯部分都是原始碼方伺服器上安全嗎?
難道你打包就安全了?
反編譯,脫殼反混淆的工具一大堆。
上面是C#版本的,如果想要原始碼,
或者是java原始碼的,可以留言哦~!