爱测未来性能-性能测试之dubbo

来源:互联网 发布:windows打开pages 编辑:程序博客网 时间:2024/05/16 15:44

Dubbo是一个分布式服务框架,致力于提供高性能和透明化的RPC远程服务调用方案,以及SOA服务治理方案,是阿里巴巴SOA服务化治理方案的核心框架,每天为2,000多个服务提供30多亿次访问量支持,最大单机支撑每天近1亿访问量,并被广泛应用于阿里巴巴集团的各成员站点。核心部分包含:


远程通讯:提供对多种基于长连接的NIO框架抽象封装,包括多种线程模型,序列化,以及“请求-响应”模式的信息交换方式。


集群容错:提供基于接口方法的透明远程过程调用,包括多协议支持,以及软负载均衡,失败容错,地址路由,动态配置等集群支持。


自动发现:基于注册中心目录服务,使服务消费方能动态的查找服务提供方,使地址透明,使服务提供方可以平滑增加或减少机器。


为了更好的认识dubbo,下面从产生背景、现实需求、架构、主要配置、参数优化、常见问题等方面对dubbo进行介绍:



一、产生背景


随着互联网的发展,网站应用规模的不断扩大,常规的垂直应用架构无法应对,分布式服务架构以及流动计算架构势在必行,亟需一个治理系统确保架构有条不紊的演进。





  • 单一应用架构

    • 当网站流量很小时,只需一个应用,将所有功能都部署在一起,以减少部署节点和成本。

    • 此时,用于简化增删改查工作量的数据访问框架(ORM)是关键。


  • 垂直应用架构

    • 当访问量逐渐增大,单一应用增加机器带来的加速度越来越小,将应用拆成互不相干的几个应用,以提升效率。

    • 此时,用于加速前端页面开发的 Web框架(MVC)是关键。


  • 分布式服务架构

    • 当垂直应用越来越多,应用之间交互不可避免,将核心业务抽取出来,作为独立的服务,逐渐形成稳定的服务中心,使前端应用能更快速的响应多变的市场需求。

    • 此时,用于提高业务复用及整合的分布式服务框架(RPC)是关键。


  • 流动计算架构

    • 当服务越来越多,容量的评估,小服务资源的浪费等问题逐渐显现,此时需增加一个调度中心基于访问压力实时管理集群容量,提高集群利用率。

    • 此时,用于提高机器利用率的资源调度和治理中心(SOA)是关键。


    二、现实需求



      

      在规模大服务化之前应用可能只是通过RMI或Hessian等工具,简单的暴露和引用远程服务,通过配置服务的URL地址进行调用,通过F5等硬件进行负载均衡。


     (1)当服务越来越多时,服务URL配置管理变得非常困难,F5硬件负载均衡器的单点压力也越来越大。此时需要一个服务注册中心,动态的注册和发现服务,使服务的位置透明。并通过在消费方获取服务提供方地址列表,实现软负载均衡和Failover,降低对F5硬件负载均衡器的依赖,也能减少部分成本。


     (2)当进一步发展,服务间依赖关系变得错综复杂,甚至分不清哪个应用要在哪个应用之前启动,架构师都不能完整的描述应用的架构关系。这时,需要自动画出应用间的依赖关系图,以帮助架构师清理关系。(3)接着,服务的调用量越来越大,服务的容量问题就暴露出来,这个服务需要多少机器支撑?什么时候该加机器?


      为了解决这些问题,第一步,要将服务现在每天的调用量,响应时间,都统计出来,作为容量规划的参考指标。其次,要可以动态调整权重,在线上,将某台机器的权重一直加大,并在加大的过程中记录响应时间的变化,直到相应时间到达阀值,记录此时的访问量,再以此访问量乘以机器数反推总容量。


三、架构




节点角色说明:

  • Provider:暴露服务的服务提供方。

  • Consumer:调用远程服务的服务消费方。

  • Registry:服务注册与发现的注册中心。

  • Monitor:统计服务的调用次调和调用时间的监控中心。

  • Container:服务运行容器。


调用关系说明:

  • 0.服务容器负责启动,加载,运行服务提供者。

  • 1.服务提供者在启动时,向注册中心注册自己提供的服务。

  • 2.服务消费者在启动时,向注册中心订阅自己所需的服务。

  • 3.注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。

  • 4.服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。

  • 5.服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。


 (1) 连通性:

  • 注册中心负责服务地址的注册与查找,相当于目录服务,服务提供者和消费者只在启动时与注册中心交互,注册中心不转发请求,压力较小。

  • 监控中心负责统计各服务调用次数,调用时间等,统计先在内存汇总后每分钟一次发送到监控中心服务器,并以报表展示。

  • 服务提供者向注册中心注册其提供的服务,并汇报调用时间到监控中心,此时间不包含网络开销。

  • 服务消费者向注册中心获取服务提供者地址列表,并根据负载算法直接调用提供者,同时汇报调用时间到监控中心,此时间包含网络开销。

  • 注册中心,服务提供者,服务消费者三者之间均为长连接,监控中心除外。

  • 注册中心通过长连接感知服务提供者的存在,服务提供者宕机,注册中心将立即推送事件通知消费者。

  • 注册中心和监控中心全部宕机,不影响已运行的提供者和消费者,消费者在本地缓存了提供者列表。

  • 注册中心和监控中心都是可选的,服务消费者可以直连服务提供者。


  (2) 健状性:

  • 监控中心宕掉不影响使用,只是丢失部分采样数据

  • 数据库宕掉后,注册中心仍能通过缓存提供服务列表查询,但不能注册新服务

  • 注册中心对等集群,任意一台宕掉后,将自动切换到另一台

  • 注册中心全部宕掉后,服务提供者和服务消费者仍能通过本地缓存通讯

  • 服务提供者无状态,任意一台宕掉后,不影响使用

  • 服务提供者全部宕掉后,服务消费者应用将无法使用,并无限次重连等待服务提供者恢复


   (3) 伸缩性:

  • 注册中心为对等集群,可动态增加机器部署实例,所有客户端将自动发现新的注册中心

  • 服务提供者无状态,可动态增加机器部署实例,注册中心将推送新的服务提供者信息给消费者


   (4) 升级性:

  • 当服务集群规模进一步扩大,带动IT治理结构进一步升级,需要实现动态部署,进行流动计算,现有分布式服务架构不会带来阻力:




  • Deployer:自动部署服务的本地代理。

  • Repository:仓库用于存储服务应用发布包。

  • Scheduler:调度中心基于访问压力自动增减服务提供者。

  • Admin:统一管理控制台。


四、主要配置


  • <dubbo:service/>服务配置,用于暴露一个服务,定义服务的元信息,一个服务可以用多个协议暴露,一个服务也可以注册到多个注册中心。

  • <dubbo:reference/>引用配置,用于创建一个远程服务代理,一个引用可以指向多个注册中心。

  • <dubbo:protocol/>协议配置,用于配置提供服务的协议信息,协议由提供方指定,消费方被动接受。

  • <dubbo:application/>应用配置,用于配置当前应用信息,不管该应用是提供者还是消费者。

  • <dubbo:module/>模块配置,用于配置当前模块信息,可选。

  • <dubbo:registry/>注册中心配置,用于配置连接注册中心相关信息。

  • <dubbo:monitor/>监控中心配置,用于配置连接监控中心相关信息,可选。

  • <dubbo:provider/>提供方的缺省值,当ProtocolConfig和ServiceConfig某属性没有配置时,采用此缺省值,可选。

  • <dubbo:consumer/>消费方缺省配置,当ReferenceConfig某属性没有配置时,采用此缺省值,可选。

  • <dubbo:method/>方法配置,用于ServiceConfig和ReferenceConfig指定方法级的配置信息。

  • <dubbo:argument/>用于指定方法参数配置。


Provider.xml





Consumer.xml




五、参数调优


Dubbo涉及的参数比较多,以下介绍几个比较重要参数:




注意表中参数与图中的对应关系


1、当consumer发起一个请求时,首先经过active limit(参数actives)进行方法级别的限制,其实现方式为CHM中存放计数器(AtomicInteger),请求时加1,请求完成(包括异常)减1,如果超过actives则等待有其他请求完成后重试或者超时后失败。


2、从多个连接(connections)中选择一个连接发送数据,对于默认的netty实现来说,由于可以复用连接,默认一个连接就可以。不过如果在压测,且只有一个consumer,一个provider,此时适当的加大connections确实能够增强网络传输能力。但线上业务由于有多个 consumer多个provider,因此不建议增加connections参数。


3、连接到达provider时(如dubbo的初次连接),首先会判断总连接数是否超限(acceps),超过限制连接将被拒绝。


4、连接成功后,具体的请求交给io thread处理。io threads虽然是处理数据的读写,但io部分为异步,更多的消耗的是cpu,因此iothreads默认cpu个数+1是比较合理的设置,不建议调整此参数。


5、数据读取并反序列化以后,交给业务线程池处理,默认情况下线程池为fixed,且排队队列为0(queues),这种情况下,最大并发等于业务线程池大小(threads),如果希望有请求的堆积能力,可以调整queues参数。如果希望快速失败由其他节点处理(官方推荐方式),则不修改 queues,只调整threads


 6execute limit(参数executes)是方法级别的并发限制,原理与actives类似,只是少了等待的过程,即受限后立即失败。


7tps,控制指定时间内(默认60s)的请求数。注意目前dubbo默认没有支持该参数,需要加一个META-INF/dubbo/com.alibaba.dubbo.rpc.Filter文件,文件内容为:tps=com.alibaba.dubbo.rpc.filter.TpsLimitFilter


从上面的分析,可以看出如果consumer*actives>provider*threadsqueues=0,则会存在部分请求无法申请到资源,重试也有很大几率失败。 当需要对一个接口的不同方法进行不同的并发控制时使用executes,否则调整threads就可以。


六、常见问题


  1. 出现RpcException: No provider available for remote service异常怎么办?


表示没有可用的服务提供者:1. 检查连接的注册中心是否正确;2. 到注册中心查看相应的服务提供者是否存在;3. 检查服务提供者是否正常运行。


 

  2. 出现调用超时com.alibaba.dubbo.remoting.TimeoutException异常怎么办?


通常是业务处理太慢,可在服务提供方执行:jstack PID > jstack.log 分析线程都卡在哪个方法调用上,这里就是慢的原因。如果不能调优性能,请将timeout设大。


 

  3. 出现java.util.concurrent.RejectedExecutionException或者Thread pool exhausted怎么办?


RejectedExecutionException表示线程池已经达到最大值,并且没有空闲连,拒绝执行了一些任务。Thread pool exhausted通常是minmax不一样大时,表示当前已创建的连接用完,进行了一次扩充,创建了新线程,但不影响运行。原因可能是连接池不够用,请调整dubbo.properites中的:



// 设成一样大,减少线程池收缩开销:

dubbo.service.min.thread.pool.size=200

dubbo.service.max.thread.pool.size=200



如果线程池已经有200,还不够,通常是业务处理占用线程时间过长,需优化业务,可通过运行:jstack 进程号 > jstack.txt,分析当前大多数线程都在干什么,从而分析出哪个地方是瓶颈,比如,如果大部分线程都在处理SQL,可能是数据库连接不够,或数据源配置错误,或SQL没走索引等。

 

  4. 服务提供者没挂,但在注册中心里看不到怎么办?


首先,确认服务提供者是否连接了正确的注册中心,不只是检查配置中的注册中心地址,而且要检查实际的网络连接。其次,看服务提供者是否非常繁忙,如压力测试,以至于没有CPU片段向注册中心发送心跳,这种情况,减小压力,将自动恢复。

 

  5. 如果服务注册不上怎么办?


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


(2) 检查有没有重复的dubbo.properties配置文件;


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


(4) 检查beanIdbeanName有没有重复;


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


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


(7) 检查与注册中心的连接是否存在:netstat -anp | grep XXX


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


以上若仍不行,开启远程调试:

 

(a) 在服务器JVM参数中加入:

-Xdebug -Xnoagent -Djava.compiler=NONE-Xrunjdwp:transport=dt_socket

address=7001,server=y,suspend=y

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


(b) dubbo源码的DefaultRegistryServiceregisterService()方法中设置断点; 


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



关于我们:

公众号:itest_forever



CSDN:http://blog.csdn.net/itest_2016

QQ群:274166295(爱测未来2群)、610934609(爱测未来3群)