1. 程式人生 > >線上bug的解決方案--帶來的全新架構設計

線上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原始碼的,可以留言哦~!