前面一片文章已經提高我們公司的異構(相容dubbo)SOA系統架構,解決了不少技術痛點,也還算比較完善,也順利推廣開來。 但是作為項目的開發者,自己產品的問題心裡是清楚的,離自己滿意還是有不小的距離。 在推廣的同時,我緊張的進入了下一個版本的開發,讓它更加完善。 原來的版本號是1.0,現在版本升級為 ...
前面一片文章已經提高我們公司的異構(相容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
![](http://images2015.cnblogs.com/blog/248830/201611/248830-20161118162452842-450151643.jpg)
![](http://images2015.cnblogs.com/blog/248830/201611/248830-20161118162717295-1978340514.jpg)
![](http://images2015.cnblogs.com/blog/248830/201611/248830-20161118162959435-812632299.jpg)
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服務 Console.ReadLine(); }
2、開啟日誌預設效果如下:
![](http://images2015.cnblogs.com/blog/248830/201611/248830-20161118181938623-2099482576.jpg)
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("callDemo"); 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、多種容錯演算法和多種負載均衡演算法可配置 待我完成手頭其他更緊急的工作,將啟動下一版本的開發