dubbo 搭建 学习教程 配置 附GitHub 源码 ( 三 )

原文链接:https://blog.csdn.net/weixin_40533111/article/details/83660571 作者四月天五月雨^_^,转载请注明出处,谢谢

声明

本文参考dubbo官网:http://dubbo.apache.org/en-us/docs/user/preface/architecture.html

基础架构,理论篇可参考:dubbo使用小全 分析 理解 附GitHub 源码 ( 一 )
简单搭建demo可参考:dubbo使用小全 分析 理解 附GitHub 源码 ( 二 )

本文在上篇的基础上继续写,展示dubbo的其他功能,都是些配置
dubbo配置有缺省值,优先级:具体服务>全局配置>缺省值

1.启动时检查

dubbo默认在启动时检查服务是否可用,不可用的话,应用启动失败,而有些场景比如:A应用依赖B的一些服务,B应用同时依赖A应用的一些服务,那么按照默认情况,启动谁都是错,需放弃启动时检查,

    @Bean
    public ConsumerConfig consumerConfig() {
        ConsumerConfig consumerConfig = new ConsumerConfig();
        consumerConfig.setTimeout(3000);
        //启动时检查,默认为true,当服务不可用或多个应用存在循环依赖,需关闭检测,以防启动失败,若后面时间中,服务恢复,dubbo的心跳检查会自动连上
        consumerConfig.setCheck(false);
        return consumerConfig;
    }

2.集群容错

在集群调用失败时,Dubbo 提供了多种容错方案,默认为 failover 重试,
在这里插入图片描述
1.invoker是provider的一个服务,封装和provider地址和具体接口service的信息
2.Directory是多个Invoker,类似List,Cluster将Directory中的多个Invoker做了统一管理,这样对外暴露的接口统一,调用者感知不到具体的服务提供者
3.Router根据规则可在(集群)服务中找到具体哪一台的机器上的服务进行调用
4.loadBalance负载均衡策略,Router路由就是通过这个策略选出具体的服务提供者,缺省为Failover,失败重试策略(一台调失败,则调另外一台,可配置providerConfig.setRetries(2);设置重试次数)
5.一些其他集群容错算法有:
Failfast Cluster
快速失败,只发起一次调用,失败立即报错。通常用于非幂等性的写操作,比如新增记录。
Failsafe Cluster
失败安全,出现异常时,直接忽略。通常用于写入审计日志等操作。
Failback Cluster
失败自动恢复,后台记录失败请求,定时重发。通常用于消息通知操作。
Forking Cluster
并行调用多个服务器,只要一个成功即返回。通常用于实时性要求较高的读操作,但需要浪费更多服务资源。可通过 forks=“2” 来设置最大并行数。
Broadcast Cluster
广播调用所有提供者,逐个调用,任意一台报错则报错 2。通常用于通知所有提供者更新缓存或日志等本地资源信息。

 /**
         * 设置集群容错策略,当失败了怎么滴,怎么滴
         */
        providerConfig.setCluster("failsafe");

3.负载均衡

常见的负载均衡算法有:
1.random(默认)
随机(默认),可按权重设置随机概率,
缺点:当调用者少时,在某个点碰撞的机会较大,但调用者多起来后,分布就越来越均匀,数学书上有个投硬币的故事,当基数趋于无穷大,概率就均匀了.
2.RoundRobin
按公约后的权重设置轮循比率
缺点:存在慢的机器积累请求的问题,当某台机器很慢,但没死掉,则请求调到这台,都卡在这了,这台没响应,请求一直都堆积在这
3.LeastActive
最少活跃调用数,相同活跃数的随机,活跃数指调用前后计数差。
使慢的提供者收到更少请求,因为越慢的提供者的调用前后计数差会越大。
4.ConsistentHash
一致性 Hash,相同参数的请求总是发到同一提供者。
当某一台提供者挂时,原本发往该提供者的请求,基于虚拟节点,平摊到其它提供者,不会引起剧烈变动。

  /**
         * 负载均衡策略,默认为random
         */
        providerConfig.setLoadbalance("roundrobin");

4.多协议

dubbo 允许配置多协议,在不同服务上支持不同协议或者同一服务上同时支持多种协议。
可根据服务性质具体配置,比如这个服务使用rmi协议,可传输视频,音频等大文件,对数据准确度要求不高等

@Service(timeout = 3000, cluster = "failfast", protocol = {"dubbo", "rmi"})
public class UserServiceImpl implements UserService {
    @Override
    public String getUser(Long id) {
        return "provider user " + id;
    }
}

全局配置不建议

  //注册多协议,此处是全剧配置,可在每个具体服务上单独配置,
        ProtocolConfig protocol = new ProtocolConfig();
        protocol.setName("dubbo");
        protocol.setPort(20880);
        ProtocolConfig protocol2 = new ProtocolConfig();
        protocol2.setName("rmi");
        protocol2.setPort(2083);
        List<ProtocolConfig> protocolConfigList = new ArrayList<>(2);
        protocolConfigList.add(protocol);
        protocolConfigList.add(protocol2);
        providerConfig.setProtocols(protocolConfigList);

5.多注册中心

dubbo支持同一服务注册到多注册中心,也支持不同服务注册到不同注册中心,终极使用:消费端也可以同时消费多注册中心的同包同名服务
注意:
1.同一注册中心(ip,端口)
2.服务版本version
3.分组group
4.同包同名
4者一致,才算是一个可用服务

provider全局配置声明注册中心:

 /**
     * 对spring声明bean名称,方便使用时注入
     * @return
     */
  @Bean(name = "hangzhouRegistry")
    public RegistryConfig registryConfig() {
        RegistryConfig registryConfig = new RegistryConfig();
        registryConfig.setAddress("multicast://224.5.6.7:1234");
        registryConfig.setId("hangzhou");
        registryConfig.setGroup("hangzhou");
        return registryConfig;
    }

    @Bean(name = "shanghaiRegistry")
    public RegistryConfig registryConfig2() {
        RegistryConfig registryConfig = new RegistryConfig();
        registryConfig.setAddress("multicast://224.5.6.7:12345");
        registryConfig.setId("shanghai");
        return registryConfig;
    }
    
    **具体服务:**
@Service(timeout = 3000, registry = "hangzhouRegistry", version = "1.0.0", group = "test1")
public class UserServiceImpl implements UserService {

consumer全局配置声明注册中心:

    @Bean
    public RegistryConfig registryConfig() {
        RegistryConfig registryConfig = new RegistryConfig();
        registryConfig.setAddress("multicast://224.5.6.7:1234");
        registryConfig.setClient("curator2");
        return registryConfig;
    }
    @Bean
    public RegistryConfig registryConfig2() {
        RegistryConfig registryConfig = new RegistryConfig();
        registryConfig.setAddress("multicast://224.5.6.7:12345");
        registryConfig.setClient("curator2");
        return registryConfig;
    }
        **具体服务:**
        @Controller
public class User {
        @Reference(registry = "hangzhouRegistry", group = "test1", version = "1.0.0")
//    @Reference(registry = "shanghaiRegistry", group = "test12", version = "1.0.0")
    private UserService userService;

6.服务分组

注意:
1.同一注册中心(ip,端口)
2.服务版本version
3.分组group
4.同包同名
4者一致,才算是一个可用服务

按功能对服务分组,配置参考第五条: 5.多注册中心

7.多版本

当一个接口实现,出现不兼容升级时,可以用版本号过渡,版本号不同的服务相互间不引用。
可以按照以下的步骤进行版本迁移:
1.在低压力时间段,先升级一半提供者为新版本
2.再将所有消费者升级为新版本
3.然后将剩下的一半提供者升级为新版本
版本使用
配置参考第五条: 5.多注册中心

8.异步调用

当有些耗时操作,可采用异步调用,使用dubbo内置的异步调用,比自己开线程更节省资源
异步分两种,需要返回结果的,可不需要结果的
首先provider

@Service(timeout = 30000, registry = "hangzhouRegistry", version = "1.0.0", group = "test1")
public class UserServiceImpl implements UserService {
    @Override
    public String getUser(Long id) {
        Preconditions.checkArgument(id != null);
        try {
            //模仿耗时,睡几秒
            if (id > 100) {
                TimeUnit.SECONDS.sleep(3);
            } else {
                TimeUnit.SECONDS.sleep(6);
            }
            return "provider user " + id;
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return null;
    }
}

注意: 因为耗时操作:需要把超时时间预留的大些

consumer

    @Reference(registry = "hangzhouRegistry", group = "test1", version = "1.0.0", async = true,timeout = 30000)
    private UserService userService;

  @RequestMapping(value = "getNameByAsync", method = {RequestMethod.GET}, produces = "application/json")
    @ResponseBody
    public String getNameByAsync() {
        String result = null;
        long beginTime = Instant.now().getEpochSecond();
        if (userService != null) {
            //此调用会立刻返回null
            userService.getUser(12L);
            System.out.println("send成功------");
            long sendTime = Instant.now().getEpochSecond();
            System.out.println("send耗时:" + (sendTime - beginTime));
            System.out.println("因为为dubbo为异步调用,并未等待,继续跑,此处可执行其他业务代码~~~~");
            try {
                //拿到调用者的future引用,当有结果了,会通知并设置到此future
                Future<String> future = RpcContext.getContext().getFuture();
                //当没有结果返回时,会wait在这,直到有结果,所以如果业务不需要返回值,这一步不用即可
                //客户端不需要启动多线程来支持并行,而是借助NIO的非阻塞完成
                String user = future.get();
                result = "异步调用成功------" + user;
                long waitTime = Instant.now().getEpochSecond();
                System.out.println("异步等待耗时:" + (waitTime - sendTime));
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
        } else {
            System.out.println("调用失败------");
            result = "调用失败------";
        }
        long endTime = Instant.now().getEpochSecond();
        System.out.println("总耗时为:" + (endTime - beginTime));
        return result;
    }

和手动多线程类似,dubbo使用nio非阻塞完成,当调用多个异步服务时,效率更高.

还有很多其他的配置,可参考官网

未完待续--------

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值