04Dubbo使用场景

这里对dubbo的一些配置的使用场景做下介绍。

启动服务检查

Dubbo默认会在启动时检查依赖的服务是否可用,不可用时会抛出异常,组织Spring初始化完成,以便在上线时可以及早发现问题。通常是调用方在dubbo:reference标签里配置check属性。在前面的例子中,没有配置默认为true,这里停止服务提供者dubbo-order启动dubbo-user

    <dubbo:reference id="orderProvider"
                     interface="com.lucky.api.IOrderServices"/>
    public static void main(String[] args) throws IOException {
        ClassPathXmlApplicationContext context = new
                ClassPathXmlApplicationContext("order-consumer.xml");
        IOrderServices orderProvider = (IOrderServices) context.getBean("orderProvider");
//        OrderRequest request = new OrderRequest();
//        request.setName("lucky");
//        OrderResponse orderResponse = orderProvider.doOrder(request);
//        System.out.println(orderResponse.toString());

        System.in.read();
    }
Caused by: java.lang.IllegalStateException: Failed to check the status of the service com.lucky.api.IOrderServices. No provider available for the service com.lucky.api.IOrderServices from the url zookeeper://localhost:2181/com.alibaba.dubbo.registry.RegistryService?application=order-consumer&dubbo=2.5.3&interface=com.lucky.api.IOrderServices&methods=doOrder&owner=lucky&pid=25243&side=consumer&timestamp=1577761649285 to the consumer 10.100.171.172 use dubbo version 2.5.3
	at com.alibaba.dubbo.config.ReferenceConfig.createProxy(ReferenceConfig.java:420)
	at com.alibaba.dubbo.config.ReferenceConfig.init(ReferenceConfig.java:300)
	at com.alibaba.dubbo.config.ReferenceConfig.get(ReferenceConfig.java:138)
	at com.alibaba.dubbo.config.spring.ReferenceBean.getObject(ReferenceBean.java:65)
	at org.springframework.beans.factory.support.FactoryBeanRegistrySupport$1.run(FactoryBeanRegistrySupport.java:121)
	... 9 more

可以看到dubbo-user启动失败,抛出不能检测IOrderServices这个服务的状态。

order-consumer.xml配置文件里关闭服务检测选项,再次启动dubbo-user,服务可以正常启动。

    <dubbo:reference id="orderProvider" check="false"
                     interface="com.lucky.api.IOrderServices"/>

释放启动服务里的调用代码,这里应该会抛出dubbo-provider服务访问失败的错误。如下所示,是因为跳过了检测直接去调用,同时dubbo-provider服务没有启动,所以会出现以下错误。

    public static void main(String[] args) throws IOException {
        ClassPathXmlApplicationContext context = new
                ClassPathXmlApplicationContext("order-consumer.xml");
        IOrderServices orderProvider = (IOrderServices) context.getBean("orderProvider");
        OrderRequest request = new OrderRequest();
        request.setName("lucky");
        OrderResponse orderResponse = orderProvider.doOrder(request);
        System.out.println(orderResponse.toString());

        System.in.read();
    }
Exception in thread "main" com.alibaba.dubbo.rpc.RpcException: Forbid consumer 10.100.171.172 access service com.lucky.api.IOrderServices from registry localhost:2181 use dubbo version 2.5.3, Please check registry access list (whitelist/blacklist).
	at com.alibaba.dubbo.registry.integration.RegistryDirectory.doList(RegistryDirectory.java:579)
	at com.alibaba.dubbo.rpc.cluster.directory.AbstractDirectory.list(AbstractDirectory.java:73)
	at com.alibaba.dubbo.rpc.cluster.support.AbstractClusterInvoker.list(AbstractClusterInvoker.java:260)
	at com.alibaba.dubbo.rpc.cluster.support.AbstractClusterInvoker.invoke(AbstractClusterInvoker.java:219)
	at com.alibaba.dubbo.rpc.cluster.support.wrapper.MockClusterInvoker.invoke(MockClusterInvoker.java:72)
	at com.alibaba.dubbo.rpc.proxy.InvokerInvocationHandler.invoke(InvokerInvocationHandler.java:52)
	at com.alibaba.dubbo.common.bytecode.proxy0.doOrder(proxy0.java)
	at com.lucky.App.main(App.java:20)

设置为false的一些场景

  • 在开发测试阶段,并不需要启动的时候就检查,更需要的是服务的更快启动,所以这个时候可以选择关闭这个功能的。
  • 另外如果出现循环依赖调用的时候,就必须关闭这个功能了,因为这个时候必须有一个服务先启动起来。

另外这个check属性在很多标签里都可以配置。

  • dubbo:consumer:表示如果没有服务提供者的时候,会报错。可以统一关闭所有服务引用的检查,是消费端全局的一个配置。

在这两个标签里使用的时候,不是特别明白😂

  • dubbo:registry:连接注册中心,注册失败的时候会报错
  • dubbo:provider

多协议支持

dubbo支持的协议:dubbo、rmi、hessian、webservice、http、thrift。其中dubbo和rmi是基于tcp的,hessian、webservice、http是基于http的。

  • 不同的协议,在不同的场景的性能是不一样的,比如大数据量的时候适合使用短连接协议,小数据量适合使用长协议连接。
  • 在项目改造时,也会存在多协议共存的现象。项目最初使用的协议和需要改造使用的协议是不一样的,会同时存在。

hessian是一个http协议所以需要运行在容器里发布,配置使用的容器为jetty

使用hessian协议通信

  1. 引入hessian依赖

    <dependency>
        <groupId>com.caucho</groupId>
        <artifactId>hessian</artifactId>
        <version>4.0.38</version>
    </dependency>
    
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>servlet-api</artifactId>
        <version>2.5</version>
    </dependency>
    <dependency>
        <groupId>org.mortbay.jetty</groupId>
        <artifactId>jetty</artifactId>
        <version>6.1.26</version>
    </dependency>
    
    
  2. 配置文件增加hessian协议

    <dubbo:protocol name="hessian" port="8090" server="jetty"/>
    

    由于hessian是基于http协议的,所以需要运行在容器里发布,这里配置的容器是jetty。

  3. 为发布的服务指定协议

    <dubbo:service interface="com.lucky.api.IOrderServices"
               ref="orderServices" protocol="hessian"/>
    

    为需要发布的服务配置protocol属性。

  4. 启动服务查看启动日志

    2019-12-31 15:12:55,366 INFO [com.alibaba.dubbo.config.AbstractConfig] -  [DUBBO] Export dubbo service com.lucky.api.IOrderServices to url hessian://10.100.171.172:8090/com.lucky.api.IOrderServices?anyhost=true&application=order-provider&dubbo=2.5.3&interface=com.lucky.api.IOrderServices&methods=doOrder&owner=lucky&pid=26229&server=jetty&side=provider&timestamp=1577776375142, dubbo version: 2.5.3, current host: 127.0.0.1
    

    可以看出,IOrderServices服务已经通过hessian协议发布出去了

  5. 同样消费端,引入hessian依赖,同时指定reference标签使用的协议

    <dependency>
        <groupId>com.caucho</groupId>
        <artifactId>hessian</artifactId>
        <version>4.0.38</version>
    </dependency>
    
    <dubbo:reference id="orderProvider"
                 interface="com.lucky.api.IOrderServices" protocol="hessian"/>
    

    可以看到调用成功。

多个协议同时存在

上面的通信还是一个协议hessian。这里我们让发布端发布两种协议,修改配置文件。

  <dubbo:service interface="com.lucky.api.IOrderServices"
                   ref="orderServices" protocol="hessian,dubbo"/>

启动服务,查看启动日志如下,对于服务IOrderServices发布了两个不同的协议,这样我们在客户端,就可以根据需要来使用不同协议的服务。

2019-12-31 15:33:48,474 INFO [com.alibaba.dubbo.config.AbstractConfig] - [DUBBO] Export dubbo service com.lucky.api.IOrderServices to url hessian://10.100.171.172:8090/com.lucky.api.IOrderServices?anyhost=true&application=order-provider&dubbo=2.5.3&interface=com.lucky.api.IOrderServices&methods=doOrder&owner=lucky&pid=26259&server=jetty&side=provider&timestamp=1577777628194, dubbo version: 2.5.3, current host: 127.0.0.1

2019-12-31 15:33:49,243 INFO [com.alibaba.dubbo.config.AbstractConfig] - [DUBBO] Export dubbo service com.lucky.api.IOrderServices to url dubbo://10.100.171.172:20880/com.lucky.api.IOrderServices?anyhost=true&application=order-provider&dubbo=2.5.3&interface=com.lucky.api.IOrderServices&methods=doOrder&owner=lucky&pid=26259&side=provider&timestamp=1577777629241, dubbo version: 2.5.3, current host: 127.0.0.1

多注册中心

dubbo对于服务发布端支持同一服务向多注册中心同时注册,或者不同服务分别注册到不同的注册中心上去,对于消费端可以同时引用注册在不同注册中心上的同名服务。

同一个服务向多个注册中心注册

比如:中文站有些服务来不及在青岛部署,只在杭州部署,而青岛的其它应用需要引用此服务,就可以将服务同时注册到两个注册中心。

    <dubbo:registry id="zkOne" protocol="zookeeper" address="localhost:2181" />
    <dubbo:registry id="zkTwo" protocol="zookeeper" address="192.168.21.76:2181"/>
    
	 <dubbo:service interface="com.lucky.api.IOrderServices"
	               ref="orderServices" protocol="hessian,dubbo" registry="zkOne,zkTwo"/>

不同的服务向不同的注册中心注册

比如:CRM有些服务是专门为国际站设计的,有些服务是专门为中文站设计的

    <dubbo:registry id="zkOne" protocol="zookeeper" address="localhost:2181" />
    <dubbo:registry id="zkTwo" protocol="zookeeper" address="192.168.21.76:2181"/>
    
    <dubbo:service interface="com.lucky.api.IOrderServices"
                   ref="orderServices" protocol="hessian,dubbo" registry="zkOne"/>

    <dubbo:service interface="com.lucky.api.IOrderServices1"
                   ref="orderServices1" protocol="hessian,dubbo" registry="zkTwo"/>

消费端 相同的服务引用使用不同的注册中心

比如:CRM需同时调用中文站和国际站的PC2服务,PC2在中文站和国际站均有部署,接口及版本号都一样,但连的数据库不一样。

   <!-- 多注册中心配置 -->
    <dubbo:registry id="chinaRegistry" address="10.20.141.150:9090" />
    <dubbo:registry id="intlRegistry" address="10.20.154.177:9010" default="false" />
 
    <!-- 引用中文站服务 -->
    <dubbo:reference id="chinaHelloService" 
interface="com.alibaba.hello.api.HelloService"  registry="chinaRegistry" />
 
    <!-- 引用国际站站服务 -->
    <dubbo:reference id="intlHelloService" 
interface="com.alibaba.hello.api.HelloService"  registry="intlRegistry" />

多版本支持

在服务迭代升级的过程中,会出现不兼容升级,这个时候就需要使用版本号,来区分不同版本服务的调用。

  <dubbo:service interface="com.lucky.api.IOrderServices"
                   ref="orderServices" protocol="hessian,dubbo" version="1.0"/>
    <dubbo:service interface="com.lucky.api.IOrderServices"
                   ref="orderServices1" protocol="hessian,dubbo" version="2.0"/>
<dubbo:reference id="orderProvider"
                     interface="com.lucky.api.IOrderServices" protocol="hessian" version="1.0"/>

服务发布端,为dubbo:service标签配置不同的ref实现类,同时设置不同的版本号version,在服务消费端,使用该服务时,通过指定版本号就可以调用不同版本的服务了。

异步调用

这里说的异步调用应该是非阻塞的NIO调用。

hessian不支持异步调用,因为hessian是使用http协议,是短连接,所以不支持回调功能。

异步调用只支持dubbo协议,在消费端的dubbo:reference标签里配置async="true" 即,该引用服务下的所有方法均异步调用如下所示

    <dubbo:reference id="orderProvider"
                     interface="com.lucky.api.IOrderServices" protocol="dubbo" version="2.0"
                    async="true" timeout="6000"/>

同时也可以指定服务的某些特定方法使用异步调用,配置形式如下所示:

    <dubbo:reference id="orderProvider"
                     interface="com.lucky.api.IOrderServices" protocol="dubbo" version="2.0"
                    >
        <dubbo:method name="doOrder" async="true" timeout="6000"/>
    </dubbo:reference>

如上,还多添加了一个超时时间的配置,为了演示,这里在IOrderServices服务的doOrder模拟了下耗时代码如下,实际使用中服务端可以不做任何多余的修改配置:

    @Override
    public OrderResponse doOrder(OrderRequest request) {
        try {
            TimeUnit.SECONDS.sleep(5);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("曾经来过版本2" + request);
        OrderResponse response = new OrderResponse();
        response.setCode("1000");
        response.setMsg("处理成功版本2");
        return response;
    }

消费端的使用:

    public static void main(String[] args) throws IOException, ExecutionException, InterruptedException {
        ClassPathXmlApplicationContext context = new
                ClassPathXmlApplicationContext("order-consumer.xml");
        IOrderServices orderProvider = (IOrderServices) context.getBean("orderProvider");
        OrderRequest request = new OrderRequest();
        request.setName("lucky");
        orderProvider.doOrder(request);
        Future<OrderResponse> response = RpcContext.getContext().getFuture();
        System.out.println("aaaa");
        OrderResponse orderResponse = response.get();
        System.out.println(orderResponse.toString());

        System.in.read();
    }

服务只订阅

意思是说一个服务在启动和注册中心通信的时候,可以通过配置dubbo:registry标签的register来设置该服务只订阅注册中心,而不会将自身发布的服务注册到注册中心。

<dubbo:registry protocol="zookeeper" address="localhost:2181" register="false"/>

启动服务,对比不对此设置时的启动日志发现缺少如下内容,这个时候只是做了 发布服务和启动netty,而没有向 注册中心 zookeeper 注册:

2019-12-31 17:52:53,363 INFO [com.alibaba.dubbo.registry.zookeeper.ZookeeperRegistry] -  [DUBBO] Register: dubbo://10.100.171.172:20880/com.lucky.api.IOrderServices2?anyhost=true&application=order-provider&dubbo=2.5.3&interface=com.lucky.api.IOrderServices&methods=doOrder&owner=lucky&pid=26390&revision=2.0&side=provider&timestamp=1577785973357&version=2.0, dubbo version: 2.5.3, current host: 127.0.0.1

服务只注册

只注册正好跟前面的只订阅相反,这个时候可以向注册中心注册,但是,消费端却不能够读到服务。

应用场景

如果有两套环境,两个注册中心,有一个服务只在其中一个注册中心部署,另一个注册中心还没来得及部署,而两个注册中心的其他服务都需要依赖此服务。此时,可以让服务提供者方只注册服务到另一注册中心,而不从另一注册中心订阅服务。这样当该服务作为消费者调用其他服务的时候,只会从一个注册中心查找。

配置方式:

<dubbo:registry subscribe="false" address="localhost:2181"/>

负载均衡

在集群环境,dubbo为服务提供者提供了多种均衡策略。配置方式如下:

  <dubbo:service interface="com.lucky.api.IOrderServices"
                   ref="orderServices" protocol="dubbo" version="1.0" loadbalance="random"/>

在服务端的dubbo:service标签配置loadbalance属性。dubbo支持的均衡策略有以下几种:

  • Random LoadBalance

    随机,按权重设置随机概率。

    在一个截面上碰撞的概率高,但调用量越大分布越均匀,而且按概率使用权重后也比较均匀,有利于动态调整提供者权重。

  • RoundRobin LoadBalance

    轮循,按公约后的权重设置轮循比率。

    存在慢的提供者累积请求问题,比如:第二台机器很慢,但没挂,当请求调到第二台时就卡在那,久而久之,所有请求都卡在调到第二台上。

  • LastActive LoadBalance

    最少活跃调用数,相同活跃数的随机,活跃数指调用前后计数差。

    使慢的提供者收到更少请求,因为越慢的提供者的调用前后计数差会越大。

  • ConsistentHash LoadBalance

    一致性Hash,相同参数的请求总是发到同一提供者。

    当某一台提供者挂时,原本发往该提供者的请求,基于虚拟节点,平摊到其它提供者,不会引起剧烈变动。

连接超时

消费端在调用服务端时,会因为网络原因或者服务耗时等因素出现超时,可以配置timeout属性来设置超时时间,在异步特性里使用了该属性配置。

同时有一点比较重要的是,对于超时等这种属性配置优先级的选择规则如下:

在这里插入图片描述

集群容错

在集群环境,消费端调用服务端时服务端会存在出错的场景,那这个时候消费端如何处理。dubbo默认的是failover,重试机制。使用方式:

    <dubbo:service interface="com.lucky.api.IOrderServices"
                   ref="orderServices" protocol="dubbo" version="1.0" cluster="failover" retries="2"/>

dubbo:service 标签配置cluster属性,当为failover重试机制时,可以额外配置下重试的次数,默认为2,即会尝试三次,第一次不算,然后重试两次。

dubbo还支持如下容错机制:

  • Failover Cluster

    失败自动切换,当出现失败,重试其它服务器。(默认方式)

    通常用于读操作,但重试会带来更长延迟。

    可通过retries="2"来设置重试次数(不含第一次)。

  • Failfast Cluster

    快速失败,只发起一次调用,失败立即报错。

    通常用于非幂等性的写操作,比如新增记录。

  • Failsafe Cluster

    失败安全,出现异常时,直接忽略。

    通常用于写入审计日志等操作。

  • Failback Cluster

    失败自动恢复,后台记录失败请求,定时重发。

    通常用于消息通知操作。

  • Forking Cluster

    并行调用多个服务器,只要一个成功即返回。

    通常用于实时性要求较高的读操作,但需要浪费更多服务资源。

    可通过forks="2"来设置最大并行数。

  • Broadcast Cluster

    广播调用所有提供者,逐个调用,任意一台报错则报错。(2.1.0开始支持)

    通常用于通知所有提供者更新缓存或日志等本地资源信息。

日志管理

dubbo 也可以将日志信息记录或者保存到文件中的

  • 使用accesslog输出到log4j

    <dubbo:protocol accesslog="true" name="dubbo" port="20880"/>
    
  • 输出到文件

    <dubbo:protocol accesslog="http://localhost/log.txt" name="dubbo" port="20880"/>
    

在这里插入图片描述

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值