Dubbo

1、为什么拆分微服务

拆分的原因有两点:

        1)便于快速需求变更和灵活上线。

        2)便于水平扩展。

拆分的问题影响不大:

        1)微服务的部署运维需要大量机器,可以使用rancher管理docker镜像,进行部署发布管理;

        2)分布式事务和服务雪崩问题,我们的微服务之间没有调用,都是给前端调的,所以也不存在这个问题。

2、工作原理与流程

        dubbo的技术架构分10层,分别是:

        Service\config\proxy\registry\cluster\monitor\protocol\exchange\transport\serialize。

 

        dubbo的工作流程是:

        privider到服务注册中心暴露服务接口;

        服务注册中心将服务地址列表推送给订阅了这某个服务的consumer;

        Consumer通过服务目录,选择一个privider进行调用;

        privider和consumer都接入monitor进行监控。

3、Config配置

服务提供者:

在服务提供者中,通过配置文件配置注册到服务注册中心的信息,具体包括:

spring.application.name应用名称

Spring.dubbo.server是否服务端

spring.dubbo.registry注册中心地址

spring.dubbo.protocol.name协议名称

spring.dubbo.protocol.port协议端口

之后,在需要发布的service类上,添加注解@Service(version=“1.0.0”)就可以了。

服务消费者:

服务消费者,通过配置文件配置注册到服务注册中心的信息,包括:

spring.application.name 应用名称

spring.dubbo.registry注册中心地址

之后,在需要调服务接口的地方,添加服务的引用,即:

@Reference(version = "1.0.0")

CityDubboService cityDubboService;

此外:

为了能让服务消费者中,能够使用服务的对象类,所以需要在服务提供者里把发布的服务打成jar包,然后给服务消费者用。

4、Proxy动态代理

        dubbo支持jdk\javassist两种动态代理,默认使用javassist。

        JDKProxy和JavassistProxy比较:

        1)JDKProxy只支持接口实现类的动态代理;

        2)JavassistProxy还支持非接口实现类的动态代理。

5、Registry负载均衡

        Dubbo支持多种负载均衡策略,可用于多个provider的选择。

        在Reference注解的参数里,配置loadBalanace:

        1)Random:表示完全随机

        2)RoundRobin:表示一个一个换着来,轮循

        3)ConsistentHash:相同参数的请求,发到同一个provider。

6、Cluster高可用重试

        Dubbo支持多种高可用策略,可用于服务挂了之后的选择:

        在Reference注解的参数里,配置cluster:

        1)Failover:挂了以后,读另一个

        2)Failback:挂了以后,重发

        3)Forking:并发调多个Provider,效率高,只要有一个返回就行

        4)Broadcast:广播,一个一个调所有的Provider.

        另外,还可以配置retries,来明确失败了以后,重试几次。

7、Protocol通信协议

        dubbo支持多种通信协议,包括dubbo、rmi、hessian、thrift等等,一般我们用两种:

        dubbo协议:主要用于高并发且数据量小的场景,consumer多,privider少,每次传输数据小于100K。采用NIO建立consumer和privider之间的长连接。

        rmi协议:主要用于数据量大的场景,一旦数据量大了,dubbo协议的效率就低了,用rmi协议效率提高不少。

8、Serialize序列化协议

        Dubbo支持多种序列化协议,包括hessian2\fastJson\JDK自带的等,一般用hessian2的序列化、反序列化效率最高。

9、SPI原理

        Service provider interface,是用来实现dubbo接口多个实现的扩展。

        dubbo内部有很多扩展点,也就是一个接口对应多个实现类,我们都使用@SPI给注解出来了。同时,在resources的META-INF文件夹下,建一个dubbo.internal文件夹,里面放一个接口全限定名的文件,里面标出xxxx= xxxx.xxxx.ddd.ccImpl,方便调用。

        dubbo在使用ExtentionLoader加载扩展点时,会根据扩展点的配置,选择当前使用哪一个实现类,选择的方式包括:

        1)在@SPI的参数里面,标出使用哪个实现类;

        2)在某个实现类上,加@Adaptive注解。

10、Filter

        Dubbo支持使用过滤器,Filter也是Dubbo的一个扩展点,支持多种Filter,Filter会在Provider方法前执行。

        Dubbo自定义Filter可以通过实现Filter接口来实现,方法有两种:

        1)第一种,在实现类上加@Activate来加载,这种定义的Filter会变成Dubbo的原生filter调用链的一部分。

        2)第二种,直接在consumer的@Reference注解里,或者provider的@Service注解里面,配置参数filter。这种情况,我们不光可以配置使用哪个filter,还可以指定filter的执行顺序。默认情况下,dubbo原生的filter会先执行,然后再执行自定义的filter,通过配置,我们可以改变这种顺序,比如:

        ——配置成filter1,default,filter2,意思是先执行filter1,再执行dubbo原生filter,再执行filter2

        ——配置成filter1,filter2,-token,意思是先执行dubbo原生filter,再执行filter1和filter2,但是dubbo原生中的tokenFilter不执行,被减掉了。

11、链路跟踪

        所谓链路跟踪,就是跟踪dubbo微服务的调用链路,由于dubbo微服务可能一层调一层,调好多层,所以需要知道到底是谁调了谁。

        链路跟踪的方法可以借助Filter实现,声明一个Filter,给所有的provider和consumer调用,在这个Filter当中通过UUID生成一个唯一的全局TraceId,这个TraceId会从头传到尾不变化,这样就知道了这条调用链路。

@Activate(group = {"provider","consumer"},order = -9999)

public class TraceFilter implements Filter {    

        @Override    

        public Result invoke(Invoker invoker, Invocation invocation) throws RpcException {        

                String traceId= invocation.getAttachment("traceId");        

                if(StringUtils.isBlank(traceId)){            

                        traceId = UUID.randomUUID().toString();        

                }       

                RpcContext.getContext().setAttachment("traceId", traceId);        

                System.out.println(invoker.getInterface()+" Method: "+invocation.getMethodName()+" TraceId:"+traceId);        

                return invoker.invoke(invocation);    

        }

}

12、服务降级

        dubbo自带了一套服务降级的方法,只要在consumer的@Reference注解里配置mock,然后实现一个Mock类就可以自动降级了。

13、如何保证微服务调用的幂等性

        与消息中间件类似,当consumer调用provider时,有时可能由于通信故障或者超时,导致没调用成功,就会重试调用。这时provider就会收到两条请求,我们要保证服务调用的幂等性。

        与消息中间件类似,保证幂等性的方法,是通过业务层面来保证,常规的办法就是:

        1)为每一次执行请求增加一个唯一的ID,我们在操作时,先去数据库里查一下是不是已经执行过了,如果已经执行过了,那就不执行。

        2)引入Redis,同样也为每一次执行请求增加一个唯一ID,在我们操作时,查看Redis里有没有这个ID的纪录,如果没有,往Redis里面插一条这个ID的记录,执行服务调用;如果有,则不执行。

14、如何保证微服务执行的顺序性

        要保证微服务执行的顺序性,需要依赖dubbo的一致性哈希负载均衡策略。

        由于dubbo服务是分布式部署的,请求有可能发送到多个provider,执行的顺序就乱了。而使用一致性哈希负载均衡策略,参数一样的请求都会发送给同一个provider执行,这样就保证了服务调用的顺序性。

        如果这个provider内部是用多线程来执行的,那我们为了保证多线程不会影响执行顺序,还可以将请求先放到一个队列里,强行排队执行。

15、如何设计一个微服务框架

        一个完整的微服务框架至少需要包含如下几个部分:

        1)服务注册中心,保存服务目录,让consumer能够获取provider的情况;

        2)服务代理,通过动态代理代理consumer和provider,实现服务之间的调用;

        3)因为是分布式的,所以需要支持负载均衡策略,如loadBalance和ribbon;

        4)为保证高可用,还需要支持故障重试,和服务降级;

        5)服务之间通信,是通过RPC走,还是走restful,如果走RPC,那可以用netty通信;如果走restful,那就直接走httpClient调。

        6)如果走RPC,还需要序列化对象;而restful走的是json;

        7)看需不需要服务网关,统一服务的入口,如果要的话,还可以参与gateway或者zuul。

你可能感兴趣的:(Dubbo)