簡介
在公司的服務多了以後,為了調用上的方便,同時為了以後的服務治理,一般都會使用一些服務架構,這裡主要介紹我知道的幾個服務架構,簡析一下這些服務架構的基本概念。
可投入生產環境使用的
以下兩個服務架構,我已經見過有公司投入到生產環境,所以對於穩定性,應該不需要有太大的擔心。
ServiceStack https://github.com/ServiceStack/ServiceStack
ServiceStack可能沒有用過,但是它的另外兩個組件,大家應該都用過,ServiceStack.Redis( Redis 訪問工具),ServiceStack.Text(Json序列化工具),ServiceStack就是一服務架構,可以很方便的用他來建立服務,服務是基於http的,另外提供了用戶端調用, 資料的序列化方式包含Json , xml , 二進位,Protobuf ,並且建立出來的服務帶有一定的描述。
1個http請求,有兩個東西很關鍵,請求路徑和參數,對於ServiceStack, 參數即對象,即它要傳遞的參數都封裝到一個類裡面, 另外在類上打標籤,標籤內容就是請求路徑,這樣用戶端在調用的時候,反射出請求路徑和參數,即可發起調用。
因為ServiceStack本身已經提供了demo, 所以這裡就不寫demo了, 大家可以學習一下。
Hessian https://sourceforge.net/projects/hessiancsharp/
Hessian是一個序列化工具,同時也是一個服務架構,提供有多語言的實現,包括.net,這個組件在.Net領域貌似不怎麼有名,可能是很久沒有更新了。
使用Hessian的時候,首先需要定義介面,然後一式兩份,服務端來實現這些介面, 用戶端引用這些介面,然後用戶端使用了RealProxxy類做代理, 所有介面調用最終會調用代理類裡面的Invoke方法, 在Invoke方法裡面擷取要調用的方法的名稱, 參數等內容,經過序列化發送到服務端一個統一的url上, 這個url會以hessian結尾, 所以需要在web.config中配置一個handle來攔截請求, 攔截到請求後,還原序列化參數, 然後通過反射發起調用。
這裡調用可以參考這篇部落格 http://www.cnblogs.com/lxsfg/archive/2008/08/27/1277777.html
其他的服務架構還有很多, 比如thrift,JSON-RPC 但是因為沒有用過, 所以這裡不做評論。
部落格園內的一些服務架構
以下三個架構是我在瀏覽部落格園的時候發現的,並且都是開源的,對於學習服務架構是個不錯的項目,另外我不經常上部落格園,下面3個架構也是機緣巧合下看到的,部落格園應該還有其他優秀的服務架構只是我沒有發現而已,如果你有發現,不妨寫到評論區,大家一起學習。
Rabbit.Rpc http://www.cnblogs.com/ants/p/5605754.html
和Hessin的有些像,也是先定義服務介面,然後一式兩份,服務端通過繼承介面來實現具體的邏輯,對於用戶端,他是通過反射,提取出介面內的所有方法,以及方法參數及傳回值資訊,然後通過動態產生代碼的方式,產生一份代理類,再動態編譯,放入到容器中。 關於產生的那個代理類,所有方法都是一個統一的實現,即調用一個Invoke方法把方法和參數發給底層,底層組裝發送到服務端。這裡產生代碼的方式比較好玩,可以學習一下。
另外,這個架構同時整合了服務治理,服務註冊到Zookeeper, 用戶端通過Zoopeeper拿到具體的服務地址進行調用。 其實到這裡,這已經不僅僅是一個服務架構,同時包含了服務治理功能。
我也僅僅是粗讀了代碼, 細節還沒理解透,想要詳細瞭解的可以看源碼。
Dyd.BaseService.ServiceCenter http://git.oschina.net/chejiangyi/Dyd.BaseService.ServiceCenter
看介紹基本的功能都有,但是看作者對這個項目的介紹是說這個項目屬於研究性的,對於服務調用的用戶端,也是通過代碼產生的方式, 具體可以參看代碼。
另外再多介紹一下這位博友,他在部落格園也有博
客 http://www.cnblogs.com/chejiangyi/ ,其下開源了數個項目 http://git.oschina.net/chejiangyi 都是一些很不錯的項目,比如調度服務,佈建服務,監控服務,對於上點規模的互連網公司,這些服務都是需要的,更可貴的是這些服務都是基於.Net的, 所以對於一些使用.Net開發的互連網公司來說,有不錯的借鑒意義。
Redola.Rpc http://www.cnblogs.com/gaochundong/p/redola_yet_another_csharp_rpc_framework.html
這個是我最近發現的,該架構使用了Actor模型,序列化使用了protobuf-net,傳輸方式是基於tcp , tcp架構使用的他自己的Cowboy.WebSockets ,看介紹也實現了服務中心,但是因為我對Actor模型並不理解,所以這裡就不畫蛇添足了, 有興趣的同學可以看作者的部落格。
我自己寫的服務架構
看了這麼多的服務架構,自己手癢也寫了一個,僅僅是一個服務調用的且是實驗性質的,可以作為一個參考。
架構的原理和Hession類似,先要定義介面,然後服務端實現介面, 這裡我取了個巧,我直接讓Web API中的Controller繼承了介面,所以就不需要專門定義一個Handle來攔截請求,同時也不影響Web Api的訪問,所以你即使使用了這個架構,也不妨礙你直接用http的方式進行訪問。用戶端的調用方式和Hession類似,也是需要定義代理,然後收集參數,
首先定義介面
有了介面,接下來就是實現,這裡我使用的是Web API, 我們定義一個Controller, 這個Controller除了繼承APIController, 還繼承了介面,在這個Controller裡,實現介面具體的邏輯。
同時把這個介面所在的dll複製到用戶端,這裡要介紹一個功能,就是RealProxy, 這是.Net內建的代理類,同時也是Hession採用的機制。
using System;using System.Linq;using System.Reflection;using System.Runtime.Remoting.Messaging;using System.Runtime.Remoting.Proxies;using Newtonsoft.Json;using RestSharp;namespace SimleRPC{ public class SimpleProxy : RealProxy { private readonly Uri _uri; public SimpleProxy(Type type, Uri uri) : base(type) { this._uri = uri; } public override IMessage Invoke(IMessage msg) { //msg參數包含調用方法的資訊,這裡通過封裝,使資訊更豐富一些 IMethodCallMessage methodMessage = new MethodCallMessageWrapper((IMethodCallMessage)msg); MethodInfo methodInfo = (MethodInfo)methodMessage.MethodBase; ParameterInfo[] paramsInfo = methodInfo.GetParameters(); //擷取方法調用參數 //拼裝path 類名即controller名, 方法名即action名 這樣就表示出具體的url string path = "/api/" + methodInfo.DeclaringType.Name + "/" + methodInfo.Name; //請求類型,post or get bool isHttpGet = methodInfo.CustomAttributes.Any(customAttributeData => customAttributeData.AttributeType.Name == "HttpGetAttribute"); var client = new RestClient(_uri); var request = new RestRequest(path, isHttpGet ? Method.GET : Method.POST); //構建參數 //web api對於傳參的一切規則 參考 http://www.cnblogs.com/babycool/p/3922738.html http://www.cnblogs.com/landeanfen/p/5337072.html 兩篇部落格 if (isHttpGet) { //這裡預設get請求的參數都是基本類型 for (int i = 0; i < paramsInfo.Length; i++) { request.AddParameter(paramsInfo[i].Name, methodMessage.Args[i]); } } else { //對於post請求,要麼沒有參數(當然基本沒有這種情況),要麼只有一個參數(這些是受web api的限制) if (paramsInfo.Length > 0) { request.AddJsonBody(methodMessage.Args[0]); } } // 發送請求 拿到結果 IRestResponse response = client.Execute(request); var content = response.Content; Type returnType = methodInfo.ReturnType; //擷取調用方法傳回型別,根據類型還原序列化結果 object returnValue; if (IsBaseType(returnType)) { returnValue = Convert.ChangeType(content, returnType); } else { returnValue = JsonConvert.DeserializeObject(content, returnType); //如果是一個對象,則用json進行還原序列化 } return new ReturnMessage(returnValue, methodMessage.Args, methodMessage.ArgCount, methodMessage.LogicalCallContext, methodMessage); } /// <summary> /// 判斷是否是基礎類型(int long double), string 是參考型別,但是也歸到基礎類型裡面 /// </summary> /// <param name="type"></param> /// <returns></returns> private static bool IsBaseType(Type type) { if (type == typeof(string) || type.IsPrimitive) return true; return false; } }}
所有的方法調用都會調用Invoke方法,在Invoke方法內,可以拿到調用方法的具體資訊,比如參數,傳回值類型等。 然後通過反射和拼裝,組成一個Http請求,這裡我預設介面類名即Controller的名字, 介面方法名即Action的名字。
最後再通過RestSharp把請求發送出去。 最後根據http結果還原序列化為方法傳回值需要的值。
其實對於服務端來首,Web API是否繼承了介面都不重要,如果不繼承,則介面的簽名要和Web API中方法的簽名保持一致。
通過我寫的Demo,方法是可以調的通的, 如果有人對這個感興趣,可以再多測試一些情況。
最後
現在很多的互連網公司都有自己的RPC架構,有些是採用開源的,有些因為曆史問題,自己寫的,對於通訊方式,有基於Http的,也有基於TCP的, 還有兩種協議都相容的。 序列化方式也是多種多樣, 我上面只列舉了5個,其實在github上搜尋,還有很多優秀的RPC。
RPC僅是項目發展過程中一個階段。 有了RPC以後,可以在此基礎上做很多的事情,比如:
服務治理 所有的服務在啟動的時候註冊到服務中心,用戶端在啟動的時候,從註冊中心擷取真實的地址,直接調用,不經過Nginx等代理,這裡可以在擷取真真實位址上做一些許可權限制,比如哪些用戶端能用,哪些用戶端不能用,能用多少個,這裡可以參考dubbo。
Http請求路徑 現在微服務很流行, 前端一個請求,可能要經過後端好幾個服務,可以在http頭上加上RequestId和RequestIndex, 把這些服務串起來,例如 A->B->C,A服務調用B服務的時候,如果發現http head裡面沒有RequestId, 則可以通過GuId產生一個,同時RequestIndex加1 ,B服務調用C服務端時候, 因為RequestId已經有了,就直接傳遞下去,同時RequestIndex加1 ,把這些資訊記錄到日誌中,通過分析,整個調用就串起來了,通過完整的資料就可以繪製出整個服務的調用鏈路圖。
除了鏈路圖,因為我們可以攔截到每個服務的調用,所以我們可以記錄服務調用耗時,再加上鏈路圖,整個的服務資訊會更加完善。
以上就是.NET下幾個服務架構介紹的內容,更多相關內容請關注topic.alibabacloud.com(www.php.cn)!