你管这个叫Dubbo?(二)

hexiaox810
发布于 2022-6-2 16:39
浏览
0收藏

 

Dubbo服务导出
「当第三方框架想和Spring整合时,有哪些方式?」

  1. 实现BeanFactoryPostProcessor接口(对BeanFactory进行扩展)
  2. 实现BeanPostProcessor接口(对Bean的生成过程进行扩展) 

你管这个叫Dubbo?(二)-鸿蒙开发者社区
Dubbo也不例外,当Dubbo和Spring整合时,会往容器中注入2个BeanPostProcessor,作用如下

ServiceAnnotationBeanPostProcessor,将@Service注解的类封装成ServiceBean注入容器 ReferenceAnnotationBeanPostProcessor,将@Reference注解的接口封装成ReferenceBean注入容器 

你管这个叫Dubbo?(二)-鸿蒙开发者社区

所以服务导出和服务引入肯定和ServiceBean和ReferenceBean的生命周期有关。

你管这个叫Dubbo?(二)-鸿蒙开发者社区

「ServiceBean实现了ApplicationListener接口,当收到ContextRefreshedEvent事件时(即Spring容器启动完成)开始服务导出。」

服务导出比较重要的2个步骤就是

  1. 将服务注册到zk(我们后面的分析,注册中心都基于zk哈)
  2. 将服务对象包装成Invoker,并保存在一个map中,key为服务名,value为Invoker对象
    「当收到请求时,根据服务名找到Invoker对象,Invoker对象根据方法名和参数反射执行方法,然后将结果返回。」

这里留个小问题,反射执行方式效率会很低,那么在Dubbo中还有哪些解决方案呢?

从图中可以看到AbstractProxyInvoker被其他Invoker进行代理了,而这些Invoker是用来执行Filter的,一个Invoker代理类执行一个Filter,层层进行代理

「如下图为Dubbo收到请求层层调用的过程」 

你管这个叫Dubbo?(二)-鸿蒙开发者社区

Dubbo服务引入

你管这个叫Dubbo?(二)-鸿蒙开发者社区
 前面我们已经推断出来服务导出和ReferenceBean有关。我们来看看具体在哪个阶段?ReferenceBean实现了FactoryBean接口,并重写了getObject方法,在这个方法中进行服务导出。因此我们推断服务导出的时机是ReferenceBean被其他对象注入时

public Object getObject() {
    return get();
}

接下来就是从注册中心获取服务地址,构建Invoker对象,并基于Invoker对象构建动态代理类,赋值给接口。

最终能发起网络调用的是DubboInvoker,而这个Invoker被代理了很多层,用来实现各种扩展功能。

服务降级

第一个就是服务降级,什么是服务降级呢?

「当服务可不用时,我们不希望抛出异常,而是返回特定的值(友好的提示等),这时候我们就可以用到服务降级。」

dubbo中有很多服务降级策略,简单举几个例子

force: 代表强制使用 Mock 行为,在这种情况下不会走远程调用 fail: 只有当远程调用发生错误时才使用 Mock 行为

假如有如下一个controller,调用DemoService获取值,但是DemoService并没有启动

@RestController
public class DemoController {

    @Reference(check = false, mock = "force:return mock")
    private DemoService demoService;

    @RequestMapping("hello")
    public String hello(@RequestParam("msg") String msg) {
        return demoService.hello(msg);
    }

}

可以看到直接返回mock字符串(也并不会发生网络调用)

将@Reference的mock属性改为如下,再次调用

@RestController
public class DemoController {

    @Reference(check = false, mock = "fail:return fail")
    private DemoService demoService;

    @RequestMapping("hello")
    public String hello(@RequestParam("msg") String msg) {
        return demoService.hello(msg);
    }

}

会发起网络调用,调用失败,然后返回fail。

「dubbo中的服务降级只用了MockClusterInvoker这一个类来实现,因此相对于Hystrix等功能很简单,实现也很简单,如下图。」 

你管这个叫Dubbo?(二)-鸿蒙开发者社区

  1. 当Reference不配置mock属性或者属性为false时,表示不进行降级,直接调用代理对象即可
  2. 以属性以force开头时,表示直接进行降级,都不会发生网络调用
  3. 其他请求就是在进行网络失败后才进行降级

集群容错

过了服务降级这一层,接下来就到了集群容错了。 

你管这个叫Dubbo?(二)-鸿蒙开发者社区

dubbo中有很多集群容错策略

你管这个叫Dubbo?(二)-鸿蒙开发者社区

Failover Cluster:失败自动切换,当出现失败,重试其它服务器。通常用于读操作,但重试会带来更长延迟。

Failfast Cluster:快速失败,只发起一次调用,失败立即报错。通常用于非幂等性的写操作,比如新增记录。

Failsafe Cluster:失败安全,出现异常时,直接忽略。通常用于写入审计日志等操作。

Failback Cluster:失败自动恢复,后台记录失败请求,定时重发。通常用于消息通知操作。

Forking Cluster:并行调用多个服务器,只要一个成功即返回。通常用于实时性要求较高的读操作,但需要浪费更多服务资源。可通过 forks=”2″ 来设置最大并行数。

Broadcast Cluster:广播调用所有提供者,逐个调用,任意一台报错则报错 。通常用于通知所有提供者更新缓存或日志等本地资源信息。

「读操作建议使用 Failover 失败自动切换,默认重试两次其他服务器。写操作建议使用 Failfast 快速失败,发一次调用失败就立即报错。」

不知道你发现没?「换集群容错策略就是换DubboInvoker的代理类」

集群容错相关的代理类都有一个共同的属性RegistryDirectory,这个是一个很重要的组件,它用List保存了服务提供者对应的所有Invoker。

「更牛逼的是这个List是动态变化的,当服务提供者下线时,会触发相应的事件,调用方会监听这个事件,并把对应的Invoker删除,这样后续就不会调用到下线的服务了。当有新的服务提供者时,会触发生成新的Invoker。」

当一个服务的多个Invoker摆在我们面前时,该选择哪个来调用呢?这就不得不提到负载均衡策略了。

你管这个叫Dubbo?(二)-鸿蒙开发者社区

「我们只需要通过合适的负载均衡策略来选择即可」

和服务端类似类似,最终能发送网络请求的Invoker还会被Filter对应的Invoker类所代理,一个Filter一个代理类,层层代理。

如下图为Dubbo发送请求时层层调用的过程

你管这个叫Dubbo?(二)-鸿蒙开发者社区

好了,Dubbo一些比较重要的扩展点就分享完了,整个请求响应的基本过程也串下来了!

 

文章转自公众号:Java识堂

分类
标签
已于2022-6-2 16:39:29修改
收藏
回复
举报
回复
    相关推荐