dubbo java环境下出现这种错误怎么解决?

dubbo java环境下出现这种错误怎么解决?,第1张

往service里注入失败了。

改成:ref="CarServiceImpl"

Dubbo分布式服务框架 服务注册不上:

(1) 检查dubbo的jar包有没有在classpath中,以及有没有重复的jar包

(2) 检查有没有重复的dubboproperties配置文件

(3) 检查暴露服务的spring配置有没有加载

(4) 检查beanId或beanName有没有重复

(5) 查看有没有错误日志:

cat ~/output/logs/webxlog

(6) 在服务提供者机器上测试与注册中心的网络是否通:

telnet 17222394 9090

(7) 检查与注册中心的连接是否存在:

netstat -anp | grep 17222394

(8) 如果是预发布机,检查hosts文件有没有正确绑定:

cat /etc/hosts

(9) 实在不行,开启远程调试:

– (a) 在服务器JVM参数中加入:-Xdebug -Xnoagent -Djavacompiler=NONE -Xrunjdwp:transport=dt_socket,address=7001,server=y,suspend=y

注意线上只有7001和8080可以被线下访问,调试端口需用这两个之一,因注册是启动时行为,启动时必需挂起suspend=y

– (b) 在dubbo源码的DefaultRegistryService的registerService()方法中设置断点。

– (c) 在Eclipse的Debug按钮下拉菜单Debug Configurations中的Remote Java Applications中新增远程调试,并设置IP和端口,以及增加dubbo的源码,进行远程Debug调试。

        大家在平时开发和测试阶段定位一些bug的时候,需要调用本地启动的dubbo服务debug。如果与服务器、其他同事共用一个注册中心的话,就会调用到别人的服务或者自己本地的服务被别人调用到,造成一些调用失败或者其他异常。

       解决如上问题有大致几种解决方案:

       1、dubbo直连;

       2、dubbo group 服务分组;

       3、dubbo version 版本过渡;

        在开发以及测试环境下,经常需要绕过注册中心,只测试指定服务的提供者,这时候可  以使用点对点直连的方式。点对点直连方式,将以服务接口为单位,忽略注册中心的提供者表。A接口配置点对点,不影响B接口从注册中心获取列表。

      消费者应用,在注入的提供者api上添加 @Reference(version = "100", url = "dubbo://ip:port") 即可!

      此时,如果提供者不希望本地的服务被别人调用到,设置:dubboregistryregister=false,默认值是true。该属性含义: 是否向此注册中心注册服务,如果设为false,将只订阅,不注册。

        通过服务分组实现环境隔离,不用绕过注册中心,大家可以共用一个注册中心。服务注册分组,使跨组的服务不会相互影响,也无法相互调用,适用于环境隔离。

      场景:服务A希望调用到本地的服务B(此时,B服务正常的调用远程服务C),而不是远程服务B。

      本地服务B的配置设置如下:                                                                                                          //应用全局配置                                                                              dubboprovidergroup=local-group   //设置本地B所提供的dubbo服务均在local-group分组下如图:

       //针对某个Api进行配置

      也可以针对某个api单独做分组,例如:@Service(version = "100",group = "local-group")服务A:在注入的B dubbo服务的api上加 @Reference(version = "100", group = "local-group")  即可。

      服务分组的几个属性解释:

1、dubboregistrygroup=local-group 

          该值自行定义,确保唯一即可,该属性含义:服务注册分组,跨组的服务不会相互影响,也无法相互调用,适用于环境隔离。 该配置不推荐配置,配置之后服务在dubbo admin上默认无法查看,也调用不到该服 务。不同环境,通过zookeeper做数据隔离。

            

      2、dubboprovidergroup=local-group  

       该属性含义:服务分组,当一个接口有多个实现,可以用分组区分。该配置使当前服务所有的提供者都在local-group下。也可以只针对某个api做配置@Service(version ="100",group ="local-group");推荐后者!

     3、dubboconsumergroup=local-group 

           该配置使当前服务只消费local-group分组下的提供者,建议只针对某个api进行配置即可,例如: @Reference(version ="100", group ="local-group")

            当一个接口的实现,出现不兼容升级时,可以用版本号过渡,版本号不同的服务相互间不引用。dubboproviderversion=10 //服务版本, 建议使用两位数字版本,如:10 ,通常在接口不兼容时版本号才需要升级。

 dubboconsumerversion=10 //消费10版本的提供者

 可全局配置,亦可配置到某个api服务上,此时优先级大于全局配置。

 提供者服务示例:@Service(version ="your version")

 消费者api服务示例: @Reference(version ="your version")

Dubbo是 Alibaba 开源的分布式服务框架远程调用框架,在网络间传输数据,就需要通信协议和序列化。

Dubbo支持dubbo、rmi、hessian、http、webservice、thrift、redis等多种协议,但是Dubbo官网是推荐我们使用Dubbo协议的,默认也是用的dubbo协议。

先介绍几种常见的协议:

缺省协议,使用基于mina117+hessian321的tbremoting交互。

连接个数:单连接

连接方式:长连接

传输协议:TCP

传输方式:NIO异步传输

序列化:Hessian二进制序列化

适用范围:传入传出参数数据包较小(建议小于100K),消费者比提供者个数多,单一消费者无法压满提供者,尽量不要用dubbo协议传输大文件或超大字符串。

适用场景:常规远程服务方法调用

1、dubbo默认采用dubbo协议,dubbo协议采用单一长连接和NIO异步通讯,适合于小数据量大并发的服务调用,以及服务消费者机器数远大于服务提供者机器数的情况

2、他不适合传送大数据量的服务,比如传文件,传视频等,除非请求量很低。

配置如下:

<dubbo:protocol name="dubbo" port="20880" />

<dubbo:protocol name=“dubbo” port=“9090” server=“netty” client=“netty” codec=“dubbo”

serialization=“hessian2” charset=“UTF-8” threadpool=“fixed” threads=“100” queues=“0” iothreads=“9”

buffer=“8192” accepts=“1000” payload=“8388608” />

3、Dubbo协议缺省每服务每提供者每消费者使用单一长连接,如果数据量较大,可以使用多个连接。

<dubbo:protocol name="dubbo" connections="2" />

4、为防止被大量连接撑挂,可在服务提供方限制大接收连接数,以实现服务提供方自我保护

<dubbo:protocol name="dubbo" accepts="1000" />

Java标准的远程调用协议。

连接个数:多连接

连接方式:短连接

传输协议:TCP

传输方式:同步传输

序列化:Java标准二进制序列化

适用范围:传入传出参数数据包大小混合,消费者与提供者个数差不多,可传文件。

适用场景:常规远程服务方法调用,与原生RMI服务互操作

RMI协议采用JDK标准的javarmi实现,采用阻塞式短连接和JDK标准序列化方式 。

基于Hessian的远程调用协议。

连接个数:多连接

连接方式:短连接

传输协议:HTTP

传输方式:同步传输

序列化:表单序列化

适用范围:传入传出参数数据包大小混合,提供者比消费者个数多,可用浏览器查看,可用表单或URL传入参数,暂不支持传文件。

适用场景:需同时给应用程序和浏览器JS使用的服务。

1、Hessian协议用于集成Hessian的服务,Hessian底层采用Http通讯,采用Servlet暴露服务,Dubbo缺省内嵌Jetty作为服务器实现。

2、Hessian是Caucho开源的一个RPC框架: http://hessiancauchocom ,其通讯效率高于WebService和Java自带的序列化。

基于http表单的远程调用协议。参见:[HTTP协议使用说明]

连接个数:多连接

连接方式:短连接

传输协议:HTTP

传输方式:同步传输

序列化:表单序列化

适用范围:传入传出参数数据包大小混合,提供者比消费者个数多,可用浏览器查看,可用表单或URL传入参数,暂不支持传文件。

适用场景:需同时给应用程序和浏览器JS使用的服务。

基于WebService的远程调用协议。

连接个数:多连接

连接方式:短连接

传输协议:HTTP

传输方式:同步传输

序列化:SOAP文本序列化

适用场景:系统集成,跨语言调用

序列化是将一个对象变成一个二进制流就是序列化, 反序列化是将二进制流转换成对象

为什么要序列化?

Dubbo序列化支持java、compactedjava、nativejava、fastjson、dubbo、fst、hessian2、kryo,其中默认hessian2。其中java、compactedjava、nativejava属于原生java的序列化。

hessian2序列化:hessian是一种跨语言的高效二进制序列化方式。但这里实际不是原生的hessian2序列化,而是阿里修改过的,它是dubbo RPC默认启用的序列化方式。

json序列化:目前有两种实现,一种是采用的阿里的fastjson库,另一种是采用dubbo中自己实现的简单json库,但其实现都不是特别成熟,而且json这种文本序列化性能一般不如上面两种二进制序列化。

java序列化:主要是采用JDK自带的Java序列化实现,性能很不理想。

在前面的一篇中分析了Dubbo是如何降级的,除了降级,有时限流也是一种很有效的解决高并发的性能问题,那在本篇中开始分析Dubbo是如何限流的。我们知道限流主要是通过控制连接数来实现的,防止某一片段内请求处理过大,导致重要服务的失效。

服务端连接控制

限制当前提供者在使用dubbo协议最多接受10个消费者链接

或者

并发控制

限制 comfooBarService 的每个方法,服务端并发执行(或占用线程池线程数)不能超过10个:

限制 comfooBarService 的 sayHello 方法,服务器并发执行(或占用线程池线程数)不能超过10个。

actives限流

该限流方式与前两种不同,其可以设置在提供端,也可以设置在消费者端。可以设置为接口级别,也可以设置为方法级别。

根据消费者与提供者建立的连接类型,其意义也不同。

长连接 : 表示当前的长连接最多可以处理的请求个数。与长连接的数量没有问题。

短连接 :表示当前服务可以同时处理的短连接数量。

类级别

方法级别

connections限流

可以设置在提供端,也可以设置在消费者端。限定连接的个数。对于短连接,和actives相同。但对于长连接,表示长连接的个数。

一般情况下,会使connections与actives联用,让connections限制长连接的个数,让actives限制长连接中可以处理的请求个数。

限制客户端服务使用连接不能超过10个

如果 <dubbo:service> 和 <dubbo:reference> 都配置了connections, <dubbo:reference> 优先。

延迟连接

延迟连接仅可以设置在消费者端,并且不能设置为方法级别。仅作用于Dubbo服务暴露协议。将长连接的建立推迟到消费者真正调用提供者时。 可以减少长连接的数量。

我们已经讲解了如何设置控制链接数的,那么它们底层是如何实现的呢?

实际上上面的逻辑都是一个个Filter,所有的Filter会连接成一个过滤器链,每次请求都会经过整个链路中的每一个Filter。那它是在什么时候构造成一个过滤器链的呢。

在服务暴露的时候会调用 buildInvokerChain , 将真正执行的 invoker 放到过滤链的尾部,再执行 protocolexpert(buildInvokerChain(invoker, )) 方法来进行服务暴露。

在服务引用的时候会调用 protocolrefer() 方法先生成 Invoker ,再调用 buildInvokerChain(protocolrefer(type, url), ) 来生成消费类型的调用链。

ExecuteLimitFilter

它用于限制每个服务中每个方法的最大并发数,有接口级别和方法级别的配置方式。

其基本原理:在框架中使用一个ConcurrentMap缓存了并发数的计数器,为每个请求URL生成一个IdentityString,并以此为key;再将每个IdentityString生成一个RpcStatus对象,将此作为value。RpcStatus对象用于记录对应的并发数。在调用开始之前,会通过URL获得RpcStatus对象,把对象中的并发数计数器原子+1,在finally中再将原子减1。只要在计数器+1的时候,发现当前计数器比设置的并发数大时,就会抛出异常。

TpsLimitFilter

TpsLimitFilter的限流是基于令牌的,即一段时间内只分配N个令牌,每次请求都会消耗一个令牌,耗完为止,后面再来的请求都会被拒绝。

具体的逻辑是在 DefaultTPSLimiter#isAllowable ,会用这个方法判断是否触发限流。

在DefaultTPSLimiter内部用一个ConcurrentHashMap缓存每个接口的令牌数,key是interface+group+version,value是一个StatItem对象,它包装了令牌刷新时间间隔、每次发放的令牌数等。首先判断当前时间减去上次发放令牌的时间是否超过了时间间隔,超过了就重新发放令牌,之前剩余的令牌会被直接覆盖掉。然后,通过CAS的方式减去1令牌,减掉后小于0就会触发限流。

ActiveLimitFilter

和服务提供者的 ExecuteLimitFilter 相似,它是消费者端的过滤器,限制的是客户端的并发量。

但是它与 ExecuteLimitFilter 有所不同,它不会直接抛出异常。而是当到达阈值的时候,会先加锁抢占当前接口的RpcStatus对象,然后通过wait方法进行等待,等待是有时间的,因为请求是有 timeout 属性的。然后如果某个Invoker在调用结束后,并发把计数器减-1并触发一个notify,此时会有一个在wait状态的线程被唤醒并继续执行,判断现在是否超时,如果超时则抛出异常。如果当前并发数仍然超出阈值,则继续执行wait方法;如果没有超出阈值在,则跳出循环,CAS+1,并调用invoke方法,调用结束后CAS-1,最后通过notify唤醒另外一个线程。

参考文章:

Dubbo之限流TpsLimitFilter源码分析

Dubbo服务限流

Dubbo源码分析----过滤器之ActiveLimitFilter

简单说,分布式是以缩短单个任务的执行时间来提升效率的,而集群则是通过提高单位时间内执行的任务数来提升效率。

  例如:

  如果一个任务由10个子任务组成,每个子任务单独执行需1小时,则在一台服务器上执行改任务需10小时。

  采用分布式方案,提供10台服务器,每台服务器只负责处理一个子任务,不考虑子任务间的依赖关系,执行完这个任务只需一个小时。(这种工作模式的一个典型代表就是Hadoop的Map/Reduce分布式计算模型)

  而采用集群方案,同样提供10台服务器,每台服务器都能独立处理这个任务。假设有10个任务同时到达,10个服务器将同时工作,10小后,10个任务同时完成,这样,整身来看,还是1小时内完成一个任务!

  以下是摘抄自网络文章:

  一、集群概念

  1 两大关键特性

  集群是一组协同工作的服务实体,用以提供比单一服务实体更具扩展性与可用性的服务平台。在客户端看来,一个集群就象是一个服务实体,但事实上集群由一组服务实体组成。与单一服务实体相比较,集群提供了以下两个关键特性:

  · 可扩展性--集群的性能不限于单一的服务实体,新的服务实体可以动态地加入到集群,从而增强集群的性能。

  · 高可用性--集群通过服务实体冗余使客户端免于轻易遇到out of service的警告。在集群中,同样的服务可以由多个服务实体提供。如果一个服务实体失败了,另一个服务实体会接管失败的服务实体。集群提供的从一个出 错的服务实体恢复到另一个服务实体的功能增强了应用的可用性。

  2 两大能力

  为了具有可扩展性和高可用性特点,集群的必须具备以下两大能力:

  · 负载均衡--负载均衡能把任务比较均衡地分布到集群环境下的计算和网络资源。

  · 错误恢复--由于某种原因,执行某个任务的资源出现故障,另一服务实体中执行同一任务的资源接着完成任务。这种由于一个实体中的资源不能工作,另一个实体中的资源透明的继续完成任务的过程叫错误恢复。

  负载均衡和错误恢复都要求各服务实体中有执行同一任务的资源存在,而且对于同一任务的各个资源来说,执行任务所需的信息视图(信息上下文)必须是一样的。

  3 两大技术

  实现集群务必要有以下两大技术:

  · 集群地址--集群由多个服务实体组成,集群客户端通过访问集群的集群地址获取集群内部各服务实体的功能。具有单一集群地址(也叫单一影像)是集群的一个基本特征。维护集群地址的设置被称为负载均衡器。负载均衡器内部负责管理各个服务实体的加入和退出,外部负责集群地址向内部服务实体地址的转换。有的负载均衡器实现真正的负载均衡算法,有的只支持任务的转换。只实现任务转换的负载均衡器适用于支持ACTIVE-STANDBY的集群环境,在那里,集群中只有一个服务实体工作,当正在工作的服务实体发生故障时,负载均衡器把后来的任务转向另外一个服务实体。

  · 内部通信--为了能协同工作、实现负载均衡和错误恢复,集群各实体间必须时常通信,比如负载均衡器对服务实体心跳测试信息、服务实体间任务执行上下文信息的通信。

  具有同一个集群地址使得客户端能访问集群提供的计算服务,一个集群地址下隐藏了各个服务实体的内部地址,使得客户要求的计算服务能在各个服务实体之间分布。内部通信是集群能正常运转的基础,它使得集群具有均衡负载和错误恢复的能力。

  二、集群分类

  Linux集群主要分成三大类(高可用集群, 负载均衡集群,科学计算集群)

高可用集群(High Availability Cluster)

负载均衡集群(Load Balance Cluster)

科学计算集群(High Performance Computing Cluster)

  具体包括:

  Linux High Availability 高可用集群

  (普通两节点双机热备,多节点HA集群,RAC, shared, share-nothing集群等)

  Linux Load Balance 负载均衡集群

   (LVS等)

  Linux High Performance Computing 高性能科学计算集群

   (Beowulf 类集群)

  三、详细介绍

  1 高可用集群(High Availability Cluster)

  常见的就是2个节点做成的HA集群,有很多通俗的不科学的名称,比如"双机热备","双机互备","双机"。

  高可用集群解决的是保障用户的应用程序持续对外提供服务的能力。 (请注意高可用集群既不是用来保护业务数据的,保护的是用户的业务程序对外不间断提供服务,把因软件/硬件/人为造成的故障对业务的影响降低到最小程度)。

  2 负载均衡集群(Load Balance Cluster)

  负载均衡系统:集群中所有的节点都处于活动状态,它们分摊系统的工作负载。一般Web服务器集群、数据库集群和应用服务器集群都属于这种类型。

  负载均衡集群一般用于相应网络请求的网页服务器,数据库服务器。这种集群可以在接到请求时,检查接受请求较少,不繁忙的服务器,并把请求转到这些服务器上。从检查其他服务器状态这一点上看,负载均衡和容错集群很接近,不同之处是数量上更多。

  3 科学计算集群(High Performance Computing Cluster)

  高性能计算(High Perfermance Computing)集群,简称HPC集群。这类集群致力于提供单个计算机所不能提供的强大的计算能力。

  31 高性能计算分类   

  311 高吞吐计算(High-throughput Computing)

  有一类高性能计算,可以把它分成若干可以并行的子任务,而且各个子任务彼此间没有什么关联。象在家搜寻外星人( SETI@HOME -- Search for Extraterrestrial Intelligence at Home )就是这一类型应用。这一项目是利用Internet上的闲置的计算资源来搜寻外星人。SETI项目的服务器将一组数据和数据模式发给Internet上参加SETI的计算节点,计算节点在给定的数据上用给定的模式进行搜索,然后将搜索的结果发给服务器。服务器负责将从各个计算节点返回的数据汇集成完整的 数据。因为这种类型应用的一个共同特征是在海量数据上搜索某些模式,所以把这类计算称为高吞吐计算。所谓的Internet计算都属于这一类。按照 Flynn的分类,高吞吐计算属于SIMD(Single Instruction/Multiple Data)的范畴。

  312 分布计算(Distributed Computing)

  另一类计算刚好和高吞吐计算相反,它们虽然可以给分成若干并行的子任务,但是子任务间联系很紧密,需要大量的数据交换。按照Flynn的分类,分布式的高性能计算属于MIMD(Multiple Instruction/Multiple Data)的范畴。

  四、分布式(集群)与集群的联系与区别

  分布式是指将不同的业务分布在不同的地方;而集群指的是将几台服务器集中在一起,实现同一业务。

  分布式中的每一个节点,都可以做集群。 而集群并不一定就是分布式的。

  举例:就比如新浪网,访问的人多了,他可以做一个群集,前面放一个响应服务器,后面几台服务器完成同一业务,如果有业务访问的时候,响应服务器看哪台服务器的负载不是很重,就将给哪一台去完成。

  而分布式,从窄意上理解,也跟集群差不多, 但是它的组织比较松散,不像集群,有一个组织性,一台服务器垮了,其它的服务器可以顶上来。

  分布式的每一个节点,都完成不同的业务,一个节点垮了,那这个业务就不可访问了。

在分布式集群架构下,负载均衡很重要。集群本来就是为了分担压力,负载均衡做的不好,就会失去了集群的意义。

1按照权重随机分配

按照权重随机分配,即是不均等随机事件。比如一块不均匀的硬币,字面30%概率,花面70%概率。这种就是不均等的随机事件。

从数学上看,即是一个区间0-10,然后均等随机产生0-10的随机数。然后在这个区间上划分,0-3,3-6,6-10分别把这个三个区间看做三个随机事件,那么这个三个随机事件的概率即是30%,30%,40%。

列子:

权重分别为[2,4,8],权重和为14,那么前面三个权重为2,4,8的三个事件就对应[0,2,6,14]这个三个区间。比如6-14表示权重为8的随机事件的概率为8/14。所以当产生一个随机数时,通过遍历权重数组,减等,当小于0时,他就落在那个权重事件上。比如:随机数5落在2-6之间,2-6对应的是权重为4这个事件,所以他属于权重为4的这个随机事件。

2轮询

当多线程出现时,使用原子类的整数去取莫轮询节点。

注意:sequences是成员变量,每次调用函数所有的权重都回归最初。

3Hash方式

使用某种hash算法,同一请求总是会hash到同一台机子上。

传统的hash算法,存在当hash区间变化时,同样的值hash后的位置不一样了。而一致性hash算法把请求,节点都hash后,放到一个圆环上,按照顺时针转动到的第一个节点为结果。这样就减少了结果的变化。还可以通过增加虚拟节点的方式均衡hash后的概率问题,当然增加节点需要交叉增加。

1怎么保证服务器少的情况下,hash的结果变化不大。

把消费者,提供者都去hash,hash的结果映射到一个环上。然后,要判断的那个消费者访问那个提供者的时候,进行顺时针的转动。遇到的第一个提供者节点就是。

2怎么保证概率的问题

交叉的防止虚拟节点,只要节点够多,那就近似是想等的。

详见: 一致性hash详解释

4最少访问原则

如果有多台机子的最少活跃数相同,在这几个中使用第一种按权重随机的方式

最少活跃调用数,相同活跃数的随机,活跃数指调用前后计数差。

使慢的提供者收到更少请求,因为越慢的提供者的调用前后计数差会越大。

比如:同样是进行了10个请求,在一分钟内,A只处理了两个,B处理了5个。那么A的机会就更少,那么就会保证的系统整体的速度。

周末看到社区的协议迁移开始被提交了pr,还没merge,打算拜读一下

看到 HttpRemoteInvocation 被更改了,这里是要把 json-rpc 协议转换为 http 协议

HTTP 请求本身也可以看做是 RPC 的一种具体形式。HTTP 请求也一样是可以从本地发一个信号到服务器,服务器上执行某个函数,然后返回一些信息给客户端。

经常用的一些数据通过HTTP协议来传输,thrift,grpc,xml-rpc,json-rpc都是通过HTTP传输的。也就说json-rpc是依赖http协议传输的,所以新建一个公共的代理协议,凡是用http协议传输的数据格式都设置这个协议,是比较好的方案。

根据dubbo的类机构继承图,是沿用SPI机制实现的 AbstractProxyProtocol

这里比较重要的是 protocolBindingRefer 方法。,构建一个DubboInvoker对象,根据dubbo的动态代理不断找到调用方的目标对象,添加到invoke当中,但这里没有指定要传输的格式,所以在dubbo序列化的时候还是会走默认的hessian协议,需要对协议中传入的格式进行校验

基本思路:将参数中的service(传输格式传入)设置到dubbo的代理,拿到代理之后添加到invoke的责任链当中,返回一个dubbo的代理对象给调用方

DABAN RP主题是一个优秀的主题,极致后台体验,无插件,集成会员系统
网站模板库 » dubbo java环境下出现这种错误怎么解决?

0条评论

发表评论

提供最优质的资源集合

立即查看 了解详情