在分布式架构时代,dubbo 作为RPC框架,以其高性能、易扩展、配置简单、易上手被越来越多的公司所青睐,在国内互联网公司中口碑一直很好。因为其高频使用,很多面试官会考察dubbo相关知识,框架原理很多人都能说出个一二来,但实用性不强。本文就日常工作中dubbo常见的错误及解决方案做了梳理。感兴趣的同学可以加收藏。
? 1、 服务注册不上怎么办?
•检查暴露服务的 Spring 配置有没有加载•在服务提供者机器上测试与注册中心的网络是否通畅(telnet 172.22.3.94 20880)•检查与注册中心的连接是否存在(netstat -anp | grep 172.22.3.94)•查看有没有错误日志
? 2、 RpcException: No provider available for the service 异常怎么办?
找不到服务,这时候可能有这么几种情况:
•Provider 服务没启动,或者注册中心(比如 ZooKeeper,Nacos,Consul)宕机了。•Dubbo 的服务配置有误差,必须保证服务名,组别(默认是 Dubbo ),version 三者都正确。•访问的环境有误:通常我们会有开发环境、测试环境、线上生产环境等多套环境。有时候发布的服务到了测试环境,而访问调用时却走了开发环境。
排查步骤:
•访问注册中心的 Ops 系统,查询对应的服务是否有提供者列表;同时检查调用者应用所在服务器的日志(一般每种注册服务的客户端都会有对应的日志记录),查看是否有地址信息的推送/拉取记录。•如无,则表明发布者发布服务失败,检查发布者的应用启动是否成功。•如有服务,则检查调用者应用所连接的注册中心,确认跟预期的环境要匹配。•如上述都没有问题,检查是否配置了路由过滤的规则等。
? 3、 出现 RpcException: Forbid consumer xxx access service XxxService from registry 异常怎么办?
•该异常表示有服务提供者注册到注册中心,但服务提供者与消费者未匹配。那服务的路由规则是什么?默认的路由规则是 服务名=[group/]serviceName[:version]。•检查两边应用的注册中心与服务相关配置是否完全一样:
•注册中心:dubbo.registry.address、dubbo.registry.group•服务:ServiceInterface、group、version
? 4、生产端的线程资源耗尽:Thread pool is EXHAUSTED
Dubbo 服务端的业务线程数是 200 个,如果多个并发请求量超过了 200,就会拒绝新的请求,抛出此错误。这种问题有这么几种解决办法:
•调整 Provider 端的 dubbo.provider.threads 参数的大小,调大一些即可。•调整 Consumer 端的 dubbo.consumer.actives 参数的大小,调小一些即可。•增加 Provider 服务实例的数量,分担压力
? 5、Dubbo 服务注册的地址与实际部署的机器地址不一样
某业务同学反馈,在 172.16.47.59 上面部署了一个应用,部署完结果在注册中心显示这个服务的IP不是在实际部署的机器上。之前没清理dubbo的cache文件显示在 172.16.50.196,清理缓存以后显示在 172.16.47.53 上面。(dubbo-2.5.3)
问题根源:NetUtils.getLocalHost() 调用的 InetAddress.getLocalHost() 返回了一个错误的IP地址。其原理是通过获取本机的 hostname,然后对此 hostname 做解析,从而获取IP地址。即机器的 hostname 映射的IP地址不是机器实际的IP地址。
解决方案:
•修改 hostname•在 /etc/hosts 中配置 hostname -> 本机IP地址
? 6、序列化失败:HessianRuntimeException
•检查服务方法的传入传出参数是否实现 Serializable 接口。•检查服务方法的传入传出参数是否继承了 Number、Date、ArrayList、HashMap 等 Hessian 特殊化处理的类。
? 7、启动时 Configuration problem: Unable to locate Spring NamespaceHandler for XML schema
表示 Spring 找不到 dubbo:... 配置的解析处理器。通常是 Dubbo 的 jar 包没有被引入,请添加对 Dubbo 的依赖;或者是 ClassLoader 隔离,查看是否有使用 OSGI 或其它热加载机制。
? 8、Curator 报 NoSuchMethodError: org.apache.zookeeper.server.quorum.flexible.QuorumMaj.(Ljava/util/Map;)V
Dubbo 应用使用 ZooKeeper 作为注册中心,启动时发生该异常。QuorumMaj类未定义单个Map参数的构造函数,而EnsembleTracker类却引用了它
? 9、 消费端发出请求,无法在指定的时间内获得对应的响应
•服务端处理比较慢,无法在指定的时间返回结果,消费端就自动返回一个超时的异常响应来结束此次调用。•服务端如果响应的比较快,但当客户端 Load 很高,负载压力很大的时候,会因为客户端请求发不出去、响应卡在 TCP Buffer 等问题,造成超时。因为客户端接收到服务端发来的数据或者请求服务端的数据,都会在系统层面排队,如果系统负载比较高,在内核态的时间占比就会加长,从而造成客户端获取到值时已经超时。•通常是业务处理太慢,可在服务提供方机器上执行:jstack [PID] > jstack.log 分析线程都卡在哪个方法调用上,这里就是慢的原因。如果不能调优性能,请调高 timeout 阈值。
排查和解决步骤:
•两边可能有 GC,检查服务端和客户端 GC 日志,耗时很长的 GC,会导致超时。超时的发生很可能意味着调用端或者服务端的资源(CPU,内存或者网络)出现了瓶颈,需要检查服务端的问题还是调用端的问题来排除GC抖动等嫌疑。•检查服务端的网络质量,比如重传率来排除网络嫌疑。•借助链路跟踪的分析服务(比如阿里的 ARMS,开源的 OpenTracing 系的实现 Zipkin、SkyWalking 等)来分析下各个点的耗时情况。
? 10、Dubbo 应用使用 ZooKeeper 作为注册中心,启动时报该异常。zookeeper.KeeperException$UnimplementedException: KeeperErrorCode = Unimplemented for {root.path}
问题根源:Curator/ZooKeeper的JAR版本不匹配ZooKeeper服务器安装的版本
? 11、启动时服务是否注册检查,这种情况一般在预发环境遇到,有些业务部门的服务没有部署预发环境,会导致我们的应用在预发环境启动不了,启动时需要取消检查。
代码语言:javascript复制//单个服务维度
<dubbo:reference id="stockService" interface="com.onlyone.stock.service.StockService" check="false" />
//全局维度
<dubbo:consumer check="false" />
? 12、调用远程接口,如果因为非正常原因而响应慢会阻塞业务线程,此时需要及早结束。可以配置超时时间
代码语言:javascript复制 <dubbo:reference id="memberService" interface="com.onlyone.bbs.service.MemberService" timeout="5000" />
? 13、dubbo默认有重试机制(2次),结合自己的业务是否需要重试,不必要的重试可能会导致脏数据。如果服务提供方响应速度慢,不断的重试,会额外加重系统负担。
代码语言:javascript复制<dubbo:reference id="privateMessageService" interface="com.onlyone.bbs.service.PrivateMessageService" retries="0" />
? 14、dubbo默认是随机路由方式,如果消费方只有一台机器,服务提供方有多台,1对多关系,可能会产生负载不均衡,导致大量请求压到一台机器,把一台机器压死,进而引发雪崩效应。可以调整路由策略,改为轮询方式。
代码语言:javascript复制<dubbo:reference id="***" interface="******" loadbalance="roundrobin" />
END