Dubbo随记

https://github.com/cyfonly/dubbo-read

 

1 Dubbo并发控制

https://www.cnblogs.com/cyfonly/p/8987043.html

http://ifeve.com/dubbo-para-control/

Dubbo调用模型

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

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

dubbo协议是单一长连接,所以保证服务提供者开放的链接数,满足消费者的需求

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

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

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

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

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

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

 

常用性能调优参数

协议dubbo:protocol

name provider dubbo 服务通过什么协议暴露  
port provider 20880 当前协议的服务通过本机哪个端口暴露,调用服务都从这个接口进入  

dubbo协议:适合小数据量(建议小于100K)大并发的服务调用,以及消费者机器远大于生产者机器数的情况,不适合传输大数据量的服务比如文件、视频等,除非请求量很低。

服务提供者

参数名 作用范围 默认值 说明 备注
threads provider 200 业务处理线程池大小  
iothreads provider CPU+1 io线程池大小  
queues provider 0

线程池队列大小,当线程池满时,排队等待执行的队列大小,

建议不要设置,当线程程池时应立即失败,

重试其它服务提供机器,而不是排队,除非有特殊需求

 
acceptes provider 0 服务提供方最大可接受连接数 0表示不限制
executes provider 0 服务提供者每服务每个方法最大可并行执行请求数 0表示不限制

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

<dubbo:protocol name="dubbo" accepts="1000" />
服务消费者
connections consumer 0

对每个提供者的最大连接数,

rmi、http、hessian等短连接协议表示限制连接数,

Dubbo等长连接协表示建立的长连接个数

Dubbo协议默认共享一个长连接

(建议优先使用默认)

actives consumer 0 每服务消费者每服务每个方法最大并发调用数 0表示不限制

<dubbo:service connections=”0”>或<dubbo:reference connections=”0”>表示该服务使用JVM共享长连接。(缺省) 
<dubbo:service connections=”1”>或<dubbo:reference connections=”1”>表示该服务使用独立长连接。 
<dubbo:service connections=”2”>或<dubbo:reference connections=”2”>表示该服务使用独立两条长连接。

一个连接可以同时处理10个、100个并发都是没有问题的

2 Dubbo性能优化

https://blog.csdn.net/lzwglory/article/details/69289395

3 Dubbo分布式服务框架常见问题解答汇总

https://blog.csdn.net/tanga842428/article/details/52249105

4 细节问题

     4.1 springboot消费者、提供者扫描包,扫描使用@Reference/@Service的包。

           配置文件中spring.dubbo.scan

     4.2 服务提供未能注册,则消费者报com.alibaba.dubbo.rpc.RpcException或java.lang.NullPointerException

           此情况不会执行Mock降级

     4.3 服务降级:reference标签里,有一个参数mock。服务端响应超时后,会降级到Mock

https://www.jianshu.com/p/ce8de35986cf

该参数有四个值,false,default,true,或者Mock类的全类名。分别代表如下含义:

  • false,不调用mock服务。

  • true,当服务调用失败时,使用mock服务(需要实现接口的Mock类)。

  • default,当服务调用失败时,使用mock服务。

  • force,强制使用Mock服务(不管服务能否调用成功)。(使用xml配置不生效,使用ReferenceConfigAPI可以生效)

4.4 在DubboAdmin中也可以设置消费者降级,为指定消费者点击“容错”,调用失败返回null

4.5 服务提供者,消费者,引用接口API的包路径要一致,所以最好把API接口单独打JAR包

4.6 2.5版dubbo 服务端同时使用 dubbo.@Service、spring.@Transactional,事务会失效

5 DubboAdmin

   5.1  可以下载原始DubboAdmin,是war项目,在webapps\dubbo-  admin-2.x.x\WEB-INF目录下,找到dubbo.properties,修改zk注册中心地址后Tomcat运行即可,端口默认8080

          https://blog.csdn.net/qq_28988969/article/details/79866111

下载:https://github.com/apache/incubator-dubbo/releases(dubbo-2.6.1以前版本Source中有)

          https://github.com/apache/incubator-dubbo/tree/dubbo-2.6.0 

  5.2 dubbo-2.6.1以后的版本提供了新的管理工具incubator-dubbo-ops,在Dubbo官网“运维管理”中有安装使用说明

  5.3 消费者页面上有服务的屏蔽/容错功能。容错:设置服务提供者报错后返回NULL,屏蔽:消费者不远程调用直接降级返回NULL。

6 dubbo+springboot 引起注解事务失效、无法注册问题

https://blog.csdn.net/linzhiqiang0316/article/details/81138589

springboot中集成spring事务的时候,遇到了一个大坑。如果(springboot+dubbo)中添加 @Service、@Transactional 两个注解的时候,就不能进行dubbo服务注册了。spring-boot-starter-dubbo依赖dubbo2.5,老版本不支持注解的事务,于是提高到dubbo2.6.2版本(2018年)

1,首先提升dubbo的版本到2.6以后,再就是需要明确接口名称。

@EnableAspectJAutoProxy,@EnableTransactionManagement,spring.aop.proxy-target-class=true,maven 添加spring-boot-starter-aop依赖

2,好多文章说要么注解实现dubbo,配置文件实现Transactional;要么注解实现Transactional,配置文件实现dubbo,不能同时注解两个,应该是老版本原因,现在可以同时支持了。

3,添加dubbo2.6.2的zk依赖

<!--spring-boot-dubbo依赖-->

<dependency>

<groupId>io.dubbo.springboot</groupId>

<artifactId>spring-boot-starter-dubbo</artifactId>

<version>1.0.0</version>

<exclusions>

<!--去除com.alibaba依赖-->

<exclusion>

<groupId>com.alibaba</groupId>

<artifactId>dubbo</artifactId>

</exclusion>

</exclusions>

</dependency>

 

<!--添加2.6.2的dubbo依赖-->

<dependency>

<groupId>com.alibaba</groupId>

<artifactId>dubbo</artifactId>

<version>2.6.2</version>

</dependency>

 

<!--zookeeper客户端相关的curator依赖-->

<dependency>

<groupId>org.apache.curator</groupId>

<artifactId>curator-framework</artifactId>

<version>2.8.0</version>

</dependency>

 

<!--添加zookeeper依赖-->

<dependency>

<groupId>org.apache.zookeeper</groupId>

<artifactId>zookeeper</artifactId>

<version>3.4.5</version>

</dependency>

配置dubbo-xml

当xml中错误提示  http://code.alibabatech.com/schema/dubbo 或 http://dubbo.apache.org/schema/dubbo uri is not regist 时请核对maven中依赖的JAR是否缺失

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
    xsi:schemaLocation="http://www.springframework.org/schema/beans        http://www.springframework.org/schema/beans/spring-beans-4.3.xsd        http://dubbo.apache.org/schema/dubbo        http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
 

<!-- 提供方应用信息,用于计算依赖关系 -->
    <dubbo:application name="dubbo-service"  />

    <!-- 注册中心暴露服务地址 -->
    <dubbo:registry address="zookeeper://localhost:2181" />

    <!-- 用dubbo协议在20880端口暴露服务 -->
    <dubbo:protocol name="dubbo" port="20880" />

    <!-- 声明需要暴露的服务接口 -->
    <dubbo:service interface="com.example.dubboservice.service.DubboService" ref="dubboService" />

    <!-- 和本地bean一样实现服务 -->
    <bean id="dubboService" class="com.example.dubboservice.service.impl.DobboServiceImpl" />
</beans>

7 请尽量在Provider端为Consumer配置一些默认属性。依据Dubbo配置的优先级,若某一个Consumer自定义配置后其会优先使用自定义配置。没有自定义的Consumer会采用Provider设置的默认配置

   如:timeout,retries,loadbalance,active 这些都是消费者属性,但是服务提供者可以为每个消费者配置默认配置。

8 版本过渡自然迭代发布

当一个接口实现,出现不兼容升级时,可以用版本号过渡:

利用dubbo该特性,我们能够实现一些功能的灰度发布,实现步骤如下:

  1. 接口旧的实现定义version="1.0.0",接口新的实现version="2.0.0"
  2. Consumer端定义version="*"

这样定义Provider和Consumer后,新旧接口实现各承担50%的流量;

 

retries重试

默认是重试两次(有其他提供者重试其他,没有则继续重试当前提供者)。调用响应超时/报错时启动重试。重试一定要注意幂等性设计,或是修改类接口不能重试。

响应已超时重试为例:响应超时后消费者端会执行重试,但是第一次请求的服务提供者若没异常会继续执行。此时可能会有两个消费者线程同时执行,所以关键的业务消费一定要做好幂等性。

 

Mock服务降级类

本地伪装通常用于服务降级,例如某验权服务,当服务提供方全部挂掉后无法连接、响应超时、抛出异常,客户端不抛出异常,而是通过 Mock 数据,取代远程返回结果。

经测试mock与retries有兼容问题,mock不会等待全部重试完成后返回,而是第一次请求失败/超时就直接mock降级返回,此时浏览器已经返回了降级的信息。但是服务端仍在自己继续重试。

 

服务端幂等性设计

超时后如果重试,一定要在服务提供者端做幂等设计。或是选择性的取消重试。

 

记录处理日志

如果想记录每次请求信息,可开启访问日志,类似于Ngnix的访问日志。注意:此日志量比较大,请注意磁盘容量。使用方式(如果配置局部,全局访问日志就会失效):
配置全局:

<dubbo:provider accesslog="/app/dubbo-demo.log"/>

配置局部:

  1. <dubbo:service interface="com.alibaba.dubbo.demo.DemoService" ref="demoService" accesslog="/app/demo.log"/>

  2. <dubbo:service interface="com.alibaba.dubbo.demo.TestService" ref="testService" accesslog="/app/test.log"/>

日志格式样式:

[2017-11-22 10:23:20] 172.18.1.205:56144 -> 172.18.1.205:20886 - com.alibaba.dubbo.demo.DemoService:1.0.0 sayHello(java.lang.String) ["afei"]

 

方法参数和返回值POJO必须实现Serializable接口

方法参数对象要实现序列化接口,否则会出现异常 或 执行mock降级

参数及返回值自定义实现List、Map、Number、Date、Calendar等接口,只能用JDK自带的实现,因为hessian会做特殊处理,自定义实现类中的属性值都会丢失

 

RpcContext

url->View 

 

通过隐式参数传递信息

RpcContext 是一个 ThreadLocal 的临时状态记录器,可以通过 RpcContext 的 setAttachment() 和 getAttachment() 在Consumer和Provider之间进行参数的隐式传递,例如Controller层拦截登录token,把根据token得到的memberId传给dubbo服务就能使用隐式参数传递的方式,setAttachment(String key, String value)设置的 KV 对,在完成一次远程调用会被清空,即多次远程调用要多次设置。使用方式:

1.服务端set:

RpcContext.getContext().setAttachment("CRT_MEMBER_ID", "13828886888");

2.客户端get:

RpcContext.getContext().getAttachment("CRT_MEMBER_ID")

 

异常处理

dubbo处理异常的逻辑依次执行:

1 如果是checked异常,直接抛出

2 方法签名上有声明,直接抛出

3 异常类与接口类在同一个JAR包,直接抛出

4 JDK自带异常,直接抛出

5 dubbo自身异常[RpcException],直接抛出

6 其他包装成RuntimeException抛出

 

例如JAVA异常:普通的JDK异常,例如:RuntimeException,IOException等。Dubbo都会将异常正常传递给消费者,消费者可以捕获到对应的异常。

下图是消费者端接收到的服务端抛出的异常信息。可以看到是服务端代码DubboServiceImpl中抛出异常。

自定义异常https://blog.csdn.net/shanchahua123456/article/details/86746417 

RPCException:dubbo框架跑出的异常,例如:超时

 

本地存根

在消费者方充当提供者的代理,可以在sub代理中增加验证/缓存等功能,以减少RPC远程调用 

http://dubbo.apache.org/zh-cn/docs/user/demos/local-stub.html

 

XML与properties冲突

同时配置XML与properties时,properties失效

 

Spring 初始化死锁

老版本的Spring可能出现。解决方法是配置<dubbo:provider deplay= -1>,使dubbo在Spring初始化完成后再暴露服务。

 

 

posted @ 2018-11-01 23:54  sw008  阅读(217)  评论(0编辑  收藏  举报