.Net下幾個服務框架介紹

在公司的服務多了之後,爲了調用上的方便,同時爲了之後的服務治理,通常都會使用一些服務框架,這裏主要介紹我知道的幾個服務框架,簡析一下這些服務框架的基本概念。
如下兩個服務框架,我已經見過有公司投入到生產環境,因此對於穩定性,應該不須要有太大的擔憂。 
 
    ServiceStack可能沒有用過,可是它的另外兩個組件,你們應該都用過,ServiceStack.Redis( Redis 訪問工具),ServiceStack.Text(Json序列化工具),ServiceStack就是一服務框架,能夠很方便的用他來建立服務,服務是基於http的,另外提供了客戶端調用, 數據的序列化方式包含Json , xml , 二進制,Protobuf ,而且建立出來的服務帶有必定的描述。
    1個http請求,有兩個東西很關鍵,請求路徑和參數,對於ServiceStack, 參數即對象,即它要傳遞的參數都封裝到一個類裏面, 另外在類上打標籤,標籤內容就是請求路徑,這樣客戶端在調用的時候,反射出請求路徑和參數,便可發起調用。 
    由於ServiceStack自己已經提供了demo, 因此這裏就不寫demo了, 你們能夠學習一下。 
 
    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個框架也是機緣巧合下看到的,博客園應該還有其餘優秀的服務框架只是我沒有發現而已,若是你有發現,不妨寫到評論區,你們一塊兒學習。 
    和Hessin的有些像,也是先定義服務接口,而後一式兩份,服務端經過繼承接口來實現具體的邏輯,對於客戶端,他是經過反射,提取出接口內的全部方法,以及方法參數及返回值信息,而後經過動態生成代碼的方式,生成一份代理類,再動態編譯,放入到容器中。 關於生成的那個代理類,全部方法都是一個統一的實現,即調用一個Invoke方法把方法和參數發給底層,底層組裝發送到服務端。這裏生成代碼的方式比較好玩,能夠學習一下。
    另外,這個框架同時集成了服務治理,服務註冊到Zookeeper, 客戶端經過Zoopeeper拿到具體的服務地址進行調用。 其實到這裏,這已經不只僅是一個服務框架,同時包含了服務治理功能。 
    我也僅僅是粗讀了代碼, 細節還沒理解透,想要詳細瞭解的能夠看源碼。 
 
  看介紹基本的功能都有,可是看做者對這個項目的介紹是說這個項目屬於研究性的,對於服務調用的客戶端,也是經過代碼生成的方式, 具體能夠參看代碼。
  另外再多介紹一下這位博友,他在博客園也有博客  http://www.cnblogs.com/chejiangyi/  ,其下開源了數個項目  http://git.oschina.net/chejiangyi 都是一些很不錯的項目,好比調度服務,配置服務,監控服務,對於上點規模的互聯網公司,這些服務都是須要的,更難得的是這些服務都是基於.Net的, 因此對於一些使用.Net開發的互聯網公司來講,有不錯的借鑑意義。
 
  這個是我最近發現的,該框架使用 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 ,把這些信息記錄到日誌中,經過分析,整個調用就串起來了,經過完整的數據就能夠繪製出整個服務的調用鏈路圖。 
 除了鏈路圖,由於咱們能夠攔截到每一個服務的調用,因此咱們能夠記錄服務調用耗時,再加上鍊路圖,整個的服務信息會更加完善。 
相關文章
相關標籤/搜索