異構(兼容dubbo)SOA系統架構(.net)優化升級


前面一片文章已經提到我司的異構(兼容dubbo)SOA系統架構,解決了不少技術痛點,也還算比較完善,也順利推廣開來。

但作為項目的開發者,自己產品的問題心里是清楚的,離自己滿意還是有不小的距離。

在推廣的同時,我緊張的進入了下一個版本的開發,讓它更加完善。

原來的版本號是1.0,現在版本升級為1.1且已經開發完成並發布(內部),本次升級主要內容如下:

1、修正了一些bug
2、簡化了SOA使用
  強化IOC的作用,解耦對象關聯性
  使用公司內部Nuget管理SOA及相關依賴
  簡化方法調用及方法參數(盡量只保留必須的參數)
3、性能提升、cpu和線程資源占用適當下降
  高效異步線程,減少應用程序啟動時間
  高效對象復用節省內存和cpu消耗
4、穩定性提升
  增加故障轉移(出錯的節點將會在負載均衡列表中移除,避免服務異常zookeeper未及時通知導致的大量報錯)
  優化zookeeper連接狀態檢測和維護(連接中斷及時重新連接)
  增加服務端優雅下線機制
5、強化配置
  增加了很多可選配置滿足業務和性能需要
  可以對單個服務單獨個性化配置
6、強化日志
  對SOA內部幾乎每個組件和每個服務都可以配置單獨的日志
  可以開啟所有日志也可以選擇性的開啟部分日志
 
以上開發測試工作耗了三個多月,當然這里面包含一些基礎建設工作,其意義不只是SOA受益,比如內部Nuget、日志、IOC容器優化,

 一、1.1版本使用控制台做服務端的例子
1、使用Nuget安裝Fang.SOA
所有引用(含ZooKeeper和Thrift)一鍵搞定
2、其實要安裝的東西還是挺多的,如果沒有Nuget就會讓人崩潰
3、不要被太多組件(dll)嚇到,大部分dll很小的,都是獨立的功能
注:大家可以看到以上截圖是9月初的,開發完成時間實際是11月中旬;也就是說9月初設計完成且基本目標已經完成並調試通過,其后又經歷漫長的兩個多月不斷得修改bug和優化;一路過來痛並快樂着,看着離自己的目標一步步越來越近。
4、服務端的代碼非常簡單
    class Program
    {
        static IContainer _container;
        static void Main(string[] args)
        {
            IContainer container = _container = new SimpleContainer()
                .SOALoadSettings();//加載appSettings配置
            CreateHelloWorld(container);//HelloWorld服務
            container.SOAStart();//啟動所有服務
            Console.ReadLine();
        }
        /// <summary>
        /// HelloWorld服務
        /// </summary>
        /// <param name="container"></param>
        private static void CreateHelloWorld(IContainer container)
        {
            string serviceName = "com.fang.HelloWorld$Iface";//服務名
            var service = new HelloWorldImp();//服務實現邏輯
            container.SOAProvider<HelloWorldService.Iface>(serviceName, service);//注冊服務
        }
    }

哈哈,簡單吧。

除了簡單還有什么?是不是也非常的流暢啊

你沒看錯,以上區區幾個行代碼就完成了SOA服務的發布工作

注:如果要在同一個應用程序中注冊(發布)多個服務依次注冊即可

5、對比1.0版本少的東西

5.1 ZKInit方法沒有了

這是一個重大變化,原來是要先把zooKeeper連接上才可以"發布"服務的

現在沒有這個必須前提了,zooKeeper連接異步化了,需要zooKeeper的時候從IOC容器中獲取,如果容器沒有,再異步連接zooKeeper並保存到IOC容器中,以后需要的時候隨時取。

5.2 增加了container(IOC容器)

這也是一個重大變化,現在SOA配置是依賴容器的,實際所有的參數都是從容器獲取,程序初始化的時候給需要的每個參數在容器里面注入了默認值,如果需要配置覆蓋默認值即可

上面的SOALoadSettings就是容器擴展方法,用於把appSettings中SOA相關節點的數據加載容器中

其實幾乎SOA各大組件、運行需要對象、對象緩存服用很多都是用該容器實現的

5.3 1.0版本中ZKConsumer一哥的位置被無情的拋棄了

1.0版本中ZKConsumer幾乎是.net SOA直接交互的唯一一個類

后來隨着SOA系統完善,我發現ZKConsumer擔不起一哥這個角色就拋棄了它,啟用與SOA"毫無關系"的IContainer(容器接口)

這會是以后的趨勢,我們"不再需要牢記"每個系統個性化的業務名詞(類),我們使用IContainer通用對象的擴展方法來定義簡單Api

我們使用一個系統的方法就變成了引用該系統的Nuget包(dll),引用該系統的命名空間,然后在IContainer下找該系統的Api(擴展方法)來用即可

啟動一個系統就變成了給該系統配置容器,可以通過文件配置也可以通過代碼配置

5.4 有人可能說還少一堆配置,這全都默認值可不行
那些配置可以在appSettings中配置,每個服務還可以單獨配置,提供了一堆IContainer的擴展方法來配置
把1.0例子中的配置全加上后的代碼如下:
        private static void CreateHelloWorld(IContainer container)
        {
            string serviceName = "com.fang.HelloWorld$Iface";//服務名
            var service = new HelloWorldImp();//服務實現邏輯
            string serviceIp = "192.168.109.166";//發布服務使用ip
            int servicePort = 5000;//發布服務使用端口
            string group = "kg";//應用程序分組
            string serviceVersion = "1.0.0";//服務版本
            int serviceTimeOut = 5000; //服務超時閾值(單位Millisecond)
            int alertElapsed = 3000; //服務執行耗時監控報警閾值(單位Millisecond)
            int alertFailure = 10; //服務每分鍾出錯次數監控報警閾值
            container.SOAServiceHost(serviceIp, servicePort, serviceName)
                .SOAServiceGroup(group, serviceName)
                .SOAServiceVersion(serviceVersion, serviceName)
                .SOAServiceTimeout(serviceTimeOut, serviceName)
                .SOAAlertelapsed(alertElapsed, serviceName)
                .SOAAlertfailure(alertFailure, serviceName);
            container.SOAProvider<HelloWorldService.Iface>(serviceName, service);//注冊服務
        }

有人說,你這代碼更多了,是對1.0版的退化嗎?

其一、並不是每個服務都有那么多個性化的配置,提供必須參數的簡單api提高使用體驗

其二、配置多元化了,代碼配置不再是不二選擇,必須寫的代碼更少了

 
二、日志配置
1、日志配置是本次升級的主要內容之一
一個容器擴展方法SOALog就可以搞所有SOA的日志記錄,增加日志后的代碼如下:
        static void Main(string[] args)
        {
            IContainer container = _container = new SimpleContainer()
                .SOALoadSettings()//加載appSettings配置
                .SOALog();//開啟所有日志
            CreateHelloWorld(container);//HelloWorld服務
            container.SOAStart();//啟動所有服務
            Console.ReadLine();
        }

2、開啟日志默認效果如下:

這是我本地15號至今一直在跑的本地測試服務,日志文件稍微有點大,但是日志性能還是比較可靠的,全日志下幾乎不影響高並發的執行耗時
對於每個服務都有單獨的日志
默認按天分文件,當然也可以不記錄文件,輸出到控制台或者數據庫等,這樣的話就要配置了,配置一個日志工廠到容器中,超出本文范疇不再展開
 
3、能不能只開啟部分日志
當然可以,提供了一堆日志配置方法(容器擴展方法),SOALog只是他們的總司令而已
呵呵,這么多款日志配置,總有一款適合你。
 
三、1.1版客戶端的例子
1、直接上代碼(nuget安裝引用同服務端)
    public class HelloWorldTest
    {
        static IContainer _container;
        public static void Test()
        {
            IContainer container = _container = new SimpleContainer()
                .SOALoadSettings()//加載appSettings配置
                .SOALog();
            Subcribe(container);//訂閱com.fang.HelloWorld
            string str = null;
            do
            {
                str = Console.ReadLine();
                if (string.Equals(str, "Exit", StringComparison.CurrentCultureIgnoreCase))
                    return;
                Console.WriteLine("callService");
                CallService();//調用服務
            } while (true);
        }
        private static void Subcribe(IContainer container)
        {
            string serviceName = "com.fang.HelloWorld$Iface";//服務名
            string serviceGroup = "kg";//服務分組
            container.SOAConsumer<HelloWorldService.Iface>(serviceName, serviceGroup, zooKeeper);
        }
        private static void CallService()
        {
            if (_container == null)
                return;
            string results = null;
            using (var resource = _container.SOAService<HelloWorldService.Iface>())
            {
                if (resource == null)
                    return results;
                HelloWorldService.Iface service = resource.Service;
                if (service == null)
                {
                    Console.WriteLine("service is null");
                    return results;
                }
                else
                {
                    var socket = resource.Socket;
                    Console.WriteLine(string.Concat(socket.Host, ":", socket.Port.ToString(), "為您服務"));
                }
                try
                {
                    results = service.sayHello("Word");
                }
                catch (Exception ex)
                {
                    var socket = resource.Socket;
                    if (socket != null)
                        Console.WriteLine(string.Concat(socket.Host, ":", socket.Port.ToString(), "出錯"));
                    Console.WriteLine(ex.Message);
                }
            }
        }
    }

注:1.1客戶端還是滿滿的容器擴展方法,簡潔的Api,和服務端一樣可以使用容器配置服務的個性化的參數(這里就不展開了)

 

2、執行效果如下:

CallService
192.168.109.166:3459為您服務
Hello word

CallService
192.168.109.166:3458為您服務
Hello word

CallService
192.168.109.166:3457為您服務
Hello word

CallService
192.168.109.166:3456為您服務
Hello word

CallService
192.168.109.166:3459為您服務
Hello word

CallService
192.168.109.166:3458為您服務
Hello word

CallService
192.168.109.166:3457為您服務
Hello word

我本地跑着4個服務,按輪詢提供服務

 
五、暢想將來版本
前面基本把本次升級的內容展示出來,算是我比較滿意的版本,其性能和穩定性已經不輸java的dubbox。
但是我還有繼續優化的沖動,也整理幾點尚未實現但是我很期待的功能
1、完全容器配置支持
  就是類似dubbo一樣在spring容器中配置一下就可以了
2、DI支持
  把服務工廠Aop封裝為服務接口,直接DI服務接口對象到需要的地方,執行方法最開始獲取一個真實對象,執行方法結束回收
3、多種容錯算法和多種負載均衡算法可供配置
 
   等我完成手頭其他更緊急的工作,將准備啟動下一版本的開發
 
 


免責聲明!

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



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