• .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 ,把这些信息记录到日志中,通过分析,整个调用就串起来了,通过完整的数据就可以绘制出整个服务的调用链路图。 
     除了链路图,因为我们可以拦截到每个服务的调用,所以我们可以记录服务调用耗时,再加上链路图,整个的服务信息会更加完善。 
     
     
     
  • 相关阅读:
    JUC回顾之-可重入的互斥锁ReentrantLock
    java基础知识回顾之java Thread类学习(十二)-- 线程中断
    mknod命令
    一个公益水塘引发的纠纷
    对cgic的理解——name选项
    linux的fwrite()使用方法,当前时间写入文本的程序
    /etc/resolv.conf文件详解
    关于函数strtok和strtok_r的使用要点和实现原理
    shell视频
    进程一些命令pstree,ps,pstack,top
  • 原文地址:https://www.cnblogs.com/beyondbit/p/6019954.html
Copyright © 2020-2023  润新知