14.dubbo本地存根、本地伪装、延迟暴露、并发控制、连接控制

来源:互联网 发布:js放大镜效果代码 编辑:程序博客网 时间:2024/06/06 10:43

1.本地存根

消费者进行一次远程调用之后可以把这一次调用生成的远程对象的proxy进行缓存,再次调用时使用这个缓存的proxy来调用。

写一个存根类,用来传入proxy缓存对象。存根类和远程调用的类实现同一个接口。当远程调用类调用出错时还可以用存根类返回一个容错数据

(1)提供方

暴露的接口实现

package com.tyf.d_zk_provider;//暴露接口实例public class modelServiceImpl implements modelService {//暴露的方法public String serviceTest(String data) {System.out.println("提供方调用");return "提供方计算结果";    }}
暴露的接口实现的proxy存根类

package com.tyf.d_zk_provider;//存根类,需要传入一个暴露方法的proxy,这个proxy是消费者上一次调用生成的远程对象的proxy//这个存根类会保存在消费者端public class sub_modelServiceImpl implements modelService {//传入proxyprivate final modelService service;    public sub_modelServiceImpl(modelService service) {        this.service = service;    }//和暴露实例相同的方法public String serviceTest(String data) {//先尝试用上次调用生成的proxy来执行        try {            return service.serviceTest(data);        } catch (Exception e) {        System.out.println("使用proxy存根调用失败,返回容错数据");            return "容错数据";        }}}
配置文件在发布服务时指定服务的存根类

<!-- 暴露服务、开启存根 -->     <dubbo:service interface="com.tyf.d_zk_provider.modelService"              ref="modelService"             stub="com.tyf.d_zk_provider.sub_modelServiceImpl"/><bean id="modelService" class="com.tyf.d_zk_provider.modelServiceImpl"  />

(2)消费者

不做任何改变直接多次调用即可

2.本地伪装

dubbo本地伪装通常用于服务降级。通常服务提供方暴露的接口可能在被消费者调用的时候会因为一些网络或者其他因素而调用失败而抛出RpcException异常。抛出异常后可能会影响整个调用链的后续调用这里可以给暴露的接口在消费者端开启mock。分两种情况

假如只是想忽略异常:在引用服务的时候设置mock为return null。即调用发生异常时直接忽略异常调用结果直接返回null值。

假如想忽略异常的同时返回容错数据:在引用服务的时候mock设置为一个bean,这个bean实现了暴露的接口方法来返回一个容错数据

下面展示第二种

(1)提供者工程关闭下测试消费者本地调用

消费者

在引用服务的时候设置接口的mock具体实现。关闭服务检查,这里不开启服务提供者,消费者会自动走mock的实现

配置文件

    <!-- 引用提供者接口,同时设置本地伪装 -->    <dubbo:reference id="modelService"           interface="com.tyf.d_zk_provider.modelService"          mock="com.tyf.d_zk_provider.mock_modelService"         check="false"         />

调用本地伪装服务结果

       // 获取远程服务代理           modelService service = (modelService)context.getBean("modelService");           // 远程调用           service.serviceTest("data");

(2)提供者被调用时抛出RpcException异常时触发消费者本地调用

提供者

暴露的接口方法返回一个person对象

//暴露接口实例public class modelServiceImpl implements modelService {//暴露的方法public person serviceTest(String data) {System.out.println("提供方调用");return new person("name", "age");    }}

person类。在不实现序列化接口情况下上面的调用会抛出RpcException异常

消费者

mock实现

//服务提供方接口的本地实现,在服务提供方调用抛出异常之后调用本地public class mock_modelService implements modelService {//返回容错数据public person serviceTest(String data) {//System.out.println("提供者的本地伪装调用");return new person("容错数据", "容错数据");}}

配置文件
    <!-- 引用提供者接口,同时设置本地伪装 -->    <dubbo:reference id="modelService"           interface="com.tyf.d_zk_provider.modelService"          mock="com.tyf.d_zk_provider.mock_modelService"         check="false"         />
调用结果
       // 获取远程服务代理           modelService service = (modelService)context.getBean("modelService");           // 远程调用           person p = service.serviceTest("data");           System.out.println(p.getName()+p.getAge());



3.延迟暴露

一方面假如应用需要预加载缓存或者其他预热活动。另一方面防止spring死锁。
延迟到spring加载完毕之后暴露服务<dubbo:service deplay="-1">延迟5秒暴露服务<dubbo:service deplay="5000">


applicationContext.getBean():1.同步singletonObject判断bean是否存在2.如果bean不存在就同步beanDefinitionMap将bean初始化3.再次同步singletonObjects将bean写入bean实例缓存。

spring初始化线程:1.同步beanDefinitionMap初始化bean2.同步singletonObjects将bean写入bean实例缓存。

按照spring初始化过程,当解析到dubbo:service标签是时就已经在zk上面暴露了服务。这个时候假如有一个请求调用这个方法,且方法中有applicationContext.getBean()时就会和spring的初始化线程对singletonObjects和beanDefinitionMap造成死锁。

解决办法

1.不使用getBean全部使用ioc注入的方式获取bean

2.如果一个暴露的服务需要调用getBean可以dubbo配置放在spring最后加载

3.大量使用getBean的话可以将dubbo服务单独隔离容器

4.延迟暴露服务<dubbo:service deplay="-1">

4.并发控制

提供方并发控制:
<!-- 暴露服务,提供方调用时线程池容量不超过10 -->     <dubbo:service interface="com.tyf.d_zk_provider.modelService"  ref="modelService" >        <dubbo:method name="serviceTest" executes="10" />    </dubbo:service>
消费者端并发控制:
    <!-- 引用提供者接口,消费者端调用时线程池容量不超过10 -->    <dubbo:reference id="modelService"  interface="com.tyf.d_zk_provider.modelService" >        <dubbo:method name="serviceTest" actives="10" />    </dubbo:reference>
如果 <dubbo:service> 和 <dubbo:reference> 都配了actives那么<dubbo:reference> 优先
如果同时设置了负载均衡策略为leastactives那么每次调用时选择并发数最小的那个提供者来调用
    <!-- 引用提供者接口,消费者端调用时线程池容量不超过10 -->    <dubbo:reference id="modelService"  interface="com.tyf.d_zk_provider.modelService" loadbalance="leastactive">        <dubbo:method name="serviceTest" actives="10" />    </dubbo:reference>

5.连接控制

提供者连接控制:
    <!-- 使用dubbo协议暴露服务的提供者接收的连接数不超过10个 -->    <dubbo:protocol  name="dubbo" port="20880" accepts="10"/>  

消费者连接控制:
    <!-- 引用提供者接口,消费者端连接数不超过10 -->    <dubbo:reference id="modelService"  interface="com.tyf.d_zk_provider.modelService" connections="10">    </dubbo:reference>