自定义Filter引起的 Failed to invoke the method 问题解决

  • 一:问题的表现和最终结论
    • 1 问题的表现:
    • 2 最终结论:
  • 二:解决过程详述
    • 1 看日志
    • 2 问题溯源
    • 3 问题定位
    • 4 错误分析,解决问题
  • 三:总结
    • 1 知识点汇总
    • 2 心得

一:问题的表现和最终结论

1 问题的表现:

出问题的项目,使用的分布式服务框架是dubbo。正常时启动项目需要启动多个服务,这里暂时定义为 server-task,server-application,server-pay 三个服务。在不知道哪一次的代码迭代后,出现了问题。服务在启动时都很顺利,没有明显报错,但是 server-application,server-pay 这两个服务都无法正常调用 server-task 服务下的 TaskRpcService的方法,且报出如下错误:

Internal server error: Failed to invoke the method getTaskInfo in the service com.test.server-task.ITaskRpcService. No provider available for the service com.test.server-task.ITaskRpcService from registry 127.0.0.1:2181 on the consumer xxx.xxx.x.xxx using the dubbo version 2.8.4. Please check if the providers have been started and registered.

乍一看,以为是 server-task 挂了或者服务启动过程有问题。在此假设的基础上,尝试重启task服务,发现问题确实解决了,调用server-task 服务下的 TaskRpcService 的方法时,不再报错。

然而,一旦其他两个服务有任意一个重启,或所有服务重启,问题会重新重现,仍然无法正常调用 server-task 服务下的 TaskRpcService 的方法,此时,又需要再次重启 server-task服务。每次项目有改动,需要启动服务时,都要对 server-task服务进行单独照顾,很麻烦。。。。同时,一直不处理,也担心会有其他的隐患。虽然最终服务还是可以正常跑起来,但是作为技术人(小白),不整的通透,怎么会进步嘞?

所以,在本地跑服务,开始了改BUG的道路。。。。

2 最终结论:

在我们项目中有一个自定义的Filter类,这里命名为 CustomFilter 类,实现了dubbo 的Fitler接口,dubbo服务会在启动时执行RegistryDirectory中的refreshInvoker方法,构建一个Filter链,同时为消费者所调用的服务创建一个 methodInvokerMap,这个 methodInvokerMap 会在消费者调用服务提供者时,生成invoker。正是构建Filter链时,这个CustomFilter 类中成员变量使得CustomFilter无法初始化导致链构建失败,methodInvokerMap为null,导致报 Failed to invoke the method 的错误。

二:解决过程详述

1 看日志

出了问题,第一反应便是查看日志。关键性的报错内容如下:

com.alibaba.dubbo.rpc.cluster.support.AbstractClusterInvoker.checkInvokers(AbstractClusterInvoker.java:251)
com.alibaba.dubbo.rpc.cluster.support.FailoverClusterInvoker.doInvoke(FailoverClusterInvoker.java:55)
com.alibaba.dubbo.rpc.cluster.support.AbstractClusterInvoker.invoke(AbstractClusterInvoker.java:227)
com.alibaba.dubbo.rpc.cluster.support.wrapper.MockClusterInvoker.invoke(MockClusterInvoker.java:72)
com.alibaba.dubbo.rpc.proxy.InvokerInvocationHandler.invoke(InvokerInvocationHandler.java:52)

2 问题溯源

根据日志中的报错信息,首先找到 checkInvokers 方法,如下所示:

invokers==null 或者 invokers.size() == 0,导致出现了日志中的报错信息。根据日志中的信息,继续追查上一级FailoverClusterInvoker.doInvoker。FailoverClusterInvoker.doInvoker如下所示:

在FailoverClusterInvoker的doInvoker方法中,invokers仍然是外部传入的。继续追查上一级AbstractClusterInvoker.invoke。AbstractClusterInvoker.invoke如下:

可以看出invokers由invocation经list()方法产生。

dubbo中 invocation 和 invoker 是什么?

这里简单介绍一下invocation和invoker的定义:

Invocation:是会话域,它持有调用过程中的变量,比如方法名,参数等。其接口如下:

Invoker:是实体域,它是 Dubbo 的核心模型,其它模型都向它靠扰,或转换成它,它代表一个可执行体,可向它发起 invoke 调用,它有可能是一个本地的实现,也可能是一个远程的实现,也可能一个集群实现。

继续往list()方法中看:

可以看出有两处影响了invokers,分别为doList(invocation)和router.route()方法。对于router的作用,简单查阅了大佬们的文章,具体如下图:

看Router的介绍,可以分析出invokers大概率是在doList()时为 null 或 size为0 。

继续跟进doList(),并进入其子类:RegistryDirectory。

可以看出,invokers是从methodInvokerMap中获得。

那么是否是因为methodInvokerMap的原因导致的呢?

跑DEBUG验证一下:

果然是 methodInvokerMap==null 搞的鬼。

正常情况下methodInvokerMap是这样的:

到这里,可确定是TaskRpcService(开头出问题的service)的methodInvokerMap为null,导致问题出现。

那么methodInvokerMap什么时候生成呢?
作为一个不懂dubbo奥秘的小白,就通过以下内容断定 methodInvokerMap 的生成方法:

  1. 百度了methodInvokerMap,有如下说法:
    这个map存储的key是dubbo方法名,value是提供者的访问方式。methodInvokerMap是通过refreshInvoker方法生成的。
  2. 又进行了一番百度,得知,methodInvokerMap所在的类–>RegistryDirectory,有如下作用:
    1. 获取 invoker 列表
    2. 监听注册中心的变化
    3. 刷新 invokers。
      a. 获取 invoker 列表,RegistryDirectory 实现的父类抽象方法 doList,其目的就是得到 invoker 列表,而其内部的实现主要是做了层方法名的过滤,通过方法名找到对应的 invokers。(这里的doList就是我们追溯问题时遇到的那个)
      b. 监听注册中心的变化,通过实现 NotifyListener 接口能感知到注册中心的数据变更,这其实是在服务引入的时候就订阅的。RegistryDirectory 定义了三种集合,分别是 invokerUrls 、routerUrls 、configuratorUrls 分别处理相应的配置变化,然后对应转化成对象。)
      c. 刷新 Invoker 列表,其实就是根据监听变更的 invokerUrls 做一波操作,其方法名为refreshInvoker(invokerUrls) ,会根据配置更新 invokers。(监听到注册中心变化后,对第二条作用中提到的invokerUrls进行操作)
  3. 在RegistryDirectory类中搜索methodInvokerMap,查看到底是在哪里赋过值。

    通过以上3条证据,可以肯定,有且仅有 refreshInvoker 方法会为methodInvokerMap赋值

3 问题定位


通过反复的启动项目进行debug,发现问题在执行toInvokers()方法后 newUrlInvokerMap == null ,其原因为 toInvokers 内部执行时抛出异常,具体如下:

这里,可以确定问题出在 protocol.refer() 方法。

查看protocol接口,根据其SPI注解,可以找到实现类 DubboProtocol:


跟进====>

这里没有直接进入DubboProtocol,而是先进入了ProtocolFIiterWrapper的refer()方法,如下图所示:

然后进入DubboProtocol.refer()方法,执行完后,执行ProtocolFIiterWrapper的buildInvokerChain()方法。

这里,需要进行说明:
Protocol存在两个wrapper类,分别为:
1 com.alibaba.dubbo.rpc.protocol.ProtocolListenerWrapper、
2 com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper。

在dubbo中存在wrapper类的类会被wrapper实例包装后返回,因此在protocol.refer方法调用的时候,会先经过wrapper类

ListenerInvokerWrapper依然不是真正的调用者,它主要是监听了invoker的创建与销毁事件,它维护的invoker为经过ProtocolFilterWrapper转换过的Invoker,该Invoker在执行前需要先经过filter链的处理

在上图中,buildInvokerChain()方法,看字面意思,就是创建一个链

继续跟进----->




最终,方法执行到上图中红框位置边报错,错误逐层抛出,最终导致了调用远程服务时报错。

4 错误分析,解决问题


变量 EXTENSION_INSTANCES 为一个 ConcurrentHashMap,由其源码和报错位置的debug截图可知,报错是clazz.newInstance()为null。即 CustomerFilter 无法在dubbo启动,调用refreshInvoker方法 为 ITaskRpcService 进行相关操作时,进行初始化。

但是这里有个问题,clazz是个Class类,在报错之前已经被拿到了,说明 CustomerFilter 已经被加载,但是被加载的类不能初始化,why?看看代码再说。CustomFilter 的代码简化版如下:

类在初始化时,对内部代码的加载顺序为:

CustomerFilter 的成员变量是由dubbo提供的 ServiceBean 创建的。那么,是否可能是 ServiceBean 还没有被加载或初始化,导致成员变量初始化失败,最终使得 CustomerFilter 初始化失败。

将上图中三个成员变量注释掉,重新启动服务,没报错,可以正常调用 server-task 服务。

成了!

三:总结

1 知识点汇总

1.1 正常的dubbo消费者调用provider的服务,其流程如何?

dubbo中的消费者去调用服务提供者时,其大致流程如下所示:

因为问题发生在消费者调用server-task服务时,由刚刚展示的源码可以看到invoker并没有生成,而是为null,那么问题发生的阶段很可能就在上图中protocol->Invoker阶段。后续对于问题的分析理解,也是验证了这个推测。

1.2 dubbo中invocation和invoker的大致定义;

1.3 dubbo消费者调用服务部分流程;

1.4 dubbo中 RegistryDirectory 的作用概述;

1.5 dubbo中ProtocolFIiterWrapper;

1.6 dubbo中 SPI 机制;

1.7 JAVA类初始化时内部加载顺序;

2 心得

对于一个dubbo才接触2个月的小菜鸡,在团队的帮助下最终解决了这么一个技术性问题,实在是很开心,哈哈哈~

自定义Filter引起的 Failed to invoke the method 问题解决相关推荐

  1. dubbo 服务注册成功后出现 Failed to invoke the method * in the *

    记录一下实际开发中出现的问题 问题描述 真实环境中需要部署新功能,需要重启之前的项目,但在重启过程中发现大量的端口处于 time wait ,导致端口被占用,项目启动失败.重新修改端口后启动成功并注册 ...

  2. com.alibaba.dubbo.rpc.RpcException: Failed to invoke the method list in the service com.dream.servic

    在启动项目的时候dubbo出现以下错误(大概是这样,一开始只是提示dubbo出错): DEBUG [http-bio-8080-exec-3] - DispatcherServlet with nam ...

  3. Failed to invoke the method subscribe in the service com.alibaba.dubbo.registry.RegistryService

    1 异常信息 今天在写 dubbo 文章的时候遇到一个问题,倒是折腾了几分钟,百思不得其解,最后终于发现了.异常信息如下: com.alibaba.dubbo.rpc.RpcException: Fa ...

  4. Dubbo:com.alibaba.dubbo.rpc.RpcException: Failed to invoke the method 问题的解决

    QUESTION:Dubbo:com.alibaba.dubbo.rpc.RpcException: Failed to invoke the method 问题的解决? ANSWER: 一.原因: ...

  5. [TODO]com.alibaba.dubbo.rpc.RpcException: Failed to invoke the method

    异常信息如下: 2018-10-30 20:00:50.230 ERROR  java.util.concurrent.ExecutionException: com.alibaba.dubbo.rp ...

  6. bubbo调用Failed to invoke remote method异常解决

    bubbo调用服务异常: com.alibaba.dubbo.rpc.RpcException: Failed to invoke remote method: getPlanFlowInfo, pr ...

  7. com.alibaba.dubbo.rpc.RpcException: Failed to invoke remote method解决方法

    com.alibaba.dubbo.rpc.RpcException: Failed to invoke remote method解决方法 参考文章: (1)com.alibaba.dubbo.rp ...

  8. SpringBoot项目中的全局异常处理器 Failed to invoke @ExceptionHandler method

    SpringBoot项目中的全局异常处理器 Failed to invoke @ExceptionHandler method 参考文章: (1)SpringBoot项目中的全局异常处理器 Faile ...

  9. com.alibaba.dubbo.rpc.RpcException: Failed to invoke the method XXX in the service

    问题log com.alibaba.dubbo.rpc.RpcException: Failed to invoke the method getExpressGoldOrderCount in th ...

最新文章

  1. java-number2
  2. jdbctemplate 开启事务_来,讲讲Spring事务有哪些坑?
  3. 解决h5py\_init_.py:26:FutureWarning: Conversion of the second argument of issubdtype from `float`^……
  4. rust(16)-数组
  5. 一个ioc例子jdk和spring版本导致问题
  6. affine工程难点、亮点汇总
  7. Visual Studio 2017正式版离线安装及介绍
  8. 大学生如何成功就业。
  9. 计算机网络技术专业的规划,计算机网络技术专业建设规划
  10. Mike Krueger 加入Mono团队
  11. Java读带有BOM的UTF-8文件乱码原因及解决方法(转)
  12. openssl、gmssl的简单介绍
  13. Learning Instagram 学习Instagram Lynda课程中文字幕
  14. 微信的9个隐藏功能,我不允许还有人不知道!
  15. 数据库实验一——数据定义
  16. select、poll、epoll、多线程实现并发请求处理
  17. Win11删除文件时提示需要管理员权限
  18. Excel quot;定位条件quot;使用技巧(1)快速在空格,批量写入公式。
  19. 关于@hide的理解
  20. 三分钟让闲置电脑变云主机

热门文章

  1. 如何在 fibos 上创建快照和使用快照启动节点
  2. 计算机系毕业祝福语,搞笑开心的毕业祝福语
  3. 600多万行的代码,苦撑12年的“乱项目”长这样
  4. 辰视智能携手大族机器人亮相深圳工业展暨22届SIMM深圳机械展
  5. 项目中项目评估概述及原则
  6. Object Detection in 20 Years A Survey 论文阅读笔记
  7. 2015年西北工业大学机试第八题
  8. 如何打开墨子平台的基础数据管理工具
  9. php吓人,网友分享最细思极恐的真实经历,截图太可怕…
  10. 数据存储单位的换算单位