zooland 我叫它動物園地,一個構思很長時間的一個項目。起初只是覺得各種通信框架都封裝的很好了,但是就是差些相容,防錯,高可用。同時在使用上,不希望有多餘的代碼,像普通介面一樣使用就可以了。 基於這些想法,看了很多資料,有了很多啟發;也開發出這樣一個版本,而且也在實際項目中應用起來了,算是小有成 ...
zooland 我叫它動物園地,一個構思很長時間的一個項目。起初只是覺得各種通信框架都封裝的很好了,但是就是差些相容,防錯,高可用。同時在使用上,不希望有多餘的代碼,像普通介面一樣使用就可以了。
基於這些想法,看了很多資料,有了很多啟發;也開發出這樣一個版本,而且也在實際項目中應用起來了,算是小有成就吧。但同時深知一個人的力量有限,希望得到整個社區幫助。幫助我完善它,讓它成為.net 平臺下一個不錯的選擇。
首先,介紹一下這個項目。
項目中沒有實現自己的通信層代碼,因為大廠為我們提供了 比如 thrift、grpc、HTTP、wcf、akka.net、netty.net 等等。
其次既然我都支持了這麼多種通信框架了,那麼他們在同一個項目中進行混用也是可以的。比如你的.net 項目內使用wcf 或 netty通信,這個時候elk或者搜索引擎為你提供了thrift的介面,那麼用這個框架會是不錯的選擇。
項目中 主要的精力放在了LoadBalace、調用錯誤隔離、重試、緩存,多種形式的Cluster、以及如何以最簡單的方式讓隊員通過直鏈的方式進行開發。
服務註冊和發現,現在還沒有很好的實現想法,希望社區能幫忙,當然有介面性能監控的能手,和調用鏈或熟悉dapper的能加入我,那麼我會更高興。
ioc上無賴選擇了Spring.net,希望spring.net 早點出.net core版本的,這樣我會很省心的去開發.net core 版的zooland;
autofac 我正在嘗試,希望能作為spring.net 的替代版本,可能是因為習慣了spring.net 感覺autofac我增加我的配置文檔的數量,這是我不喜歡的
ioc 我也不喜歡對框架內部侵入太多的,它會讓我覺得我的架構很臃腫,讓我覺得ioc 不過是虛擬工廠來生產真正的實例,而且還要讓我到處引用虛擬工廠的類庫,想想都覺得煩。
計劃還是有的:
準備在框架層加入過濾器,這樣CAS 做分散式事務的開源框架也能整合進來,緩存也能獨立成一個Filter 的實現
比較麻煩的是調用鏈,需要埋點,由於支持了多種通信框架,而基於dapper論文的追蹤訪問鏈條的方式,可能導致有些通信框架不支持,比較麻煩,一直在想,tcp/ip協議是不是也有想http一樣的,可以在訪問header裡面添加調用鏈的內容。也希望社區有好的辦法。當然能推動大廠們提供的通信框架的改進,那就更好了。
有代碼有真相,下麵是用於調用的代碼,對使用來說絕對easy
static void Main(string[] args) { var context = ContextRegistry.GetContext(); var helloServiceThrift = context.GetObject<RpcContractThrift.IHelloService>(); var helloServiceGrpc = context.GetObject<RpcContractGrpc.IHelloService>(); var helloServiceWcf = context.GetObject<RpcContractWcf.IHelloService>(); var helloServiceHttp = context.GetObject<RpcContractHttp.IHelloService>(); var helloServiceAkka = context.GetObject<RpcContractAkka.IHelloService>(); var helloServiceRemoting = context.GetObject<RpcContractRemoting.IHelloService>(); while (true) { Console.WriteLine("請選擇:wcf | grpc | thrift | http | akka | remoting"); var mode = Console.ReadLine().ToLower(); switch (mode) { case "wcf": CallWhile((helloword) => { WcfHello(helloServiceWcf, helloword); }); break; case "grpc": CallWhile((helloword) => { GrpcHello(helloServiceGrpc, helloword); }); break; case "thrift": CallWhile((helloword) => { ThriftHello(helloServiceThrift, helloword); }); break; case "http": CallWhile((helloword) => { HttpHello(helloServiceHttp, helloword); }); break; case "akka": CallWhile((helloword) => { AkkaHello(helloServiceAkka, helloword); }); break; case "remoting": CallWhile((helloword) => { RemotingHello(helloServiceRemoting, helloword); }); break; case "all": for (int i = 0; i < 3; i++) { Task.Run(() => { try { WcfHello(helloServiceWcf); } catch (Exception ex) { throw ex; } }); Task.Run(() => { try { GrpcHello(helloServiceGrpc); } catch (Exception ex) { throw ex; } }); Task.Run(() => { try { ThriftHello(helloServiceThrift); } catch (Exception ex) { throw ex; } }); Task.Run(() => { try { HttpHello(helloServiceHttp); } catch (Exception ex) { throw ex; } }); Task.Run(() => { try { AkkaHello(helloServiceAkka); } catch (Exception ex) { throw ex; } }); } break; } if (mode == "end") { break; } } } private static void ThriftHello(RpcContractThrift.IHelloService helloServiceThrift, string helloword = "world") { var callNameVoid = helloServiceThrift.CallNameVoid(); Console.WriteLine(callNameVoid); helloServiceThrift.CallName(helloword); Console.WriteLine("CallName called"); helloServiceThrift.CallVoid(); Console.WriteLine("CallVoid called"); var hello = helloServiceThrift.Hello(helloword); Console.WriteLine(hello); var helloResult = helloServiceThrift.SayHello(helloword + "perfect world"); Console.WriteLine($"{helloResult.Name},{helloResult.Gender},{helloResult.Head}"); helloResult.Name = helloword + "show perfect world"; var showResult = helloServiceThrift.ShowHello(helloResult); Console.WriteLine(showResult); } private static void GrpcHello(RpcContractGrpc.IHelloService helloServiceGrpc, string helloword = "world") { var callNameVoid = helloServiceGrpc.CallNameVoid(new RpcContractGrpc.Void()); Console.WriteLine(callNameVoid); helloServiceGrpc.CallName(new RpcContractGrpc.NameResult { Name = helloword }); Console.WriteLine("CallName called"); helloServiceGrpc.CallVoid(new RpcContractGrpc.Void()); Console.WriteLine("CallVoid called"); var hello = helloServiceGrpc.Hello(new RpcContractGrpc.NameResult { Name = helloword }); Console.WriteLine(hello.Name); var helloResult = helloServiceGrpc.SayHello(new RpcContractGrpc.NameResult { Name = $"{helloword} perfect world" }); Console.WriteLine($"{helloResult.Name},{helloResult.Gender},{helloResult.Head}"); helloResult.Name = helloword + "show perfect world"; var showResult = helloServiceGrpc.ShowHello(helloResult); Console.WriteLine(showResult.Name); } private static void WcfHello(RpcContractWcf.IHelloService helloServiceWcf, string helloword = "world") { var callNameVoid = helloServiceWcf.CallNameVoid(); Console.WriteLine(callNameVoid); helloServiceWcf.CallName(helloword); Console.WriteLine("CallName called"); helloServiceWcf.CallVoid(); Console.WriteLine("CallVoid called"); var helloWcf = helloServiceWcf.Hello(helloword); Console.WriteLine(helloWcf); var helloResultWcf = helloServiceWcf.SayHello($"{helloword} perfect world"); Console.WriteLine($"{helloResultWcf.Name},{helloResultWcf.Gender},{helloResultWcf.Head}"); helloResultWcf.Name = helloword + "show perfect world"; var showResultWcf = helloServiceWcf.ShowHello(helloResultWcf); Console.WriteLine(showResultWcf); } private static void HttpHello(RpcContractHttp.IHelloService helloServiceHttp, string helloword = "world") { var callNameVoid = helloServiceHttp.CallNameVoid(); Console.WriteLine(callNameVoid); helloServiceHttp.CallName(helloword); Console.WriteLine("CallName called"); helloServiceHttp.CallVoid(); Console.WriteLine("CallVoid called"); var helloWcf = helloServiceHttp.Hello(helloword); Console.WriteLine(helloWcf); var helloResultWcf = helloServiceHttp.SayHello($"{helloword} perfect world"); Console.WriteLine($"{helloResultWcf.Name},{helloResultWcf.Gender},{helloResultWcf.Head}"); helloResultWcf.Name = helloword + "show perfect world"; var showResultWcf = helloServiceHttp.ShowHello(helloResultWcf); Console.WriteLine(showResultWcf); } private static void AkkaHello(RpcContractAkka.IHelloService akkaServiceHttp,string helloword = "world") { var callNameVoid = akkaServiceHttp.CallNameVoid(); Console.WriteLine(callNameVoid); akkaServiceHttp.CallName(new RpcContractAkka.NameResult { Name = helloword }); Console.WriteLine("CallName called"); akkaServiceHttp.CallVoid(); Console.WriteLine("CallVoid called"); var hello = akkaServiceHttp.Hello(new RpcContractAkka.NameResult { Name = helloword }); Console.WriteLine(hello.Name); var helloResult = akkaServiceHttp.SayHello(new RpcContractAkka.NameResult { Name = $"{helloword} perfect world" }); Console.WriteLine($"{helloResult.Name},{helloResult.Gender},{helloResult.Head}"); helloResult.Name = helloword + "show perfect world"; var showResultWcf = akkaServiceHttp.ShowHello(helloResult); Console.WriteLine(showResultWcf.Name); } private static void RemotingHello(RpcContractRemoting.IHelloService remotingServiceHttp, string helloword = "world") { var callNameVoid = remotingServiceHttp.CallNameVoid(); Console.WriteLine(callNameVoid); remotingServiceHttp.CallName(helloword); Console.WriteLine("CallName called"); remotingServiceHttp.CallVoid(); Console.WriteLine("CallVoid called"); var hello = remotingServiceHttp.Hello(helloword); Console.WriteLine(hello); var helloResult = remotingServiceHttp.SayHello($"{helloword} perfect world"); Console.WriteLine($"{helloResult.Name},{helloResult.Gender},{helloResult.Head}"); helloResult.Name = helloword + "show perfect world"; var showResult = remotingServiceHttp.ShowHello(helloResult); Console.WriteLine(showResult); } private static void CallWhile(Action<string> map) { var helloword = "world"; while (true) { try { map(helloword); var mode = Console.ReadLine().ToLower(); helloword = mode; if (helloword == "end") { break; } } catch (Exception ex) { Console.WriteLine(ex.StackTrace); } } } }
目前只支持了spring.net ,有autofac的高手,歡迎加入
希望為一部分使用.net framework 的WCF做通信層框架,轉微服務架構,作為一個不錯的並且平滑的升級選擇。
新技術不要怕不穩定,源碼都有了,而且框架結構這麼簡單,大膽用,有問題了,可以聯繫技術支持啥。
奉上項目開源地址:
https://github.com/wutao0315/zooland
現在還沒有搞明白怎麼編譯好一個版本怎麼弄到nuget上,而且版本管理經驗也欠缺,也需要依賴社區了。
聯繫作者
mail:[email protected]
qq:1164636434
想加入我的,郵件給我吧,歡迎每一個熱愛編程的同學。