Dubbo随记

2 篇文章 0 订阅

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

配置

应用名application、协议protocol、注册中心registry、接口引用/暴露、bean

功能示例:demos/preflight-check.html

1 Dubbo并发控制-依赖隔离

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

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

核心参数:

协议: threadpool、threads;消费者:actives、connections;提供者:accepts、executes;

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就可以。

2.7.5版对消费者线程模型的优化提升30%QPS

https://dubbo.apache.org/zh/docs/v2.7/user/examples/consumer-threadpool/#m-zhdocsv27userexamplesconsumer-threadpool

http://dubbo.apache.org/zh-cn/docs/user/demos/consumer-threadpool.html

常用性能调优参数

协议dubbo:protocol

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

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

服务提供者

参数名作用范围默认值说明备注
threadsprovider200业务处理线程池大小 
iothreadsproviderCPU+1io线程池大小 
queuesprovider0

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

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

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

 
acceptesprovider0服务提供方最大可接受连接数0表示不限制
executesprovider0服务提供者每服务每个方法最大可并行执行请求数,超过后立即异常(ExceptionFilter)0表示不限制

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

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

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

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

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

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

(建议优先使用默认)

activesconsumer0每服务消费者每服务每个方法最大并发调用数,超过后等待至超时抛异常(ActiveLimitFilter)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。

5.5 利用telnet命令来查看Dubbo线程池状态、测试

官网/references/telnet.html

可以查看线程池的健康程度、最大线程数、活跃线程数、任务数等等。

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,xml配置文件实现Transactional;要么注解实现Transactional,xml配置文件实现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" />

    <!-- 本地spring-bean -->
    <bean id="dubboService" class="com.example.dubboservice.service.impl.DobboServiceImpl" />
</beans>

从配置中可以看到 id="dubboService" 是Spring的<Bean>,其支持Spring的所有特性(ioc、aop)。dubbo只是把这个Spring的Bean通过Rpc暴露成远程服务。ref可以引用Spring环境中的任意bean,只要Bean-name正确即可。

 

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会做特殊处理,自定义实现类中的属性值都会丢失

 

通过隐式参数传递信息

可以传递用户信息、JWT等给下游服务。

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")

RpcContext类

 

隐式参数+自定义DubboFilter/AOP 传递/接收用户信息

参考:www.jianshu.com/p/9c7ef3adb9cd

思路:发送方Filter在发送前将用户信息装入隐式参数。服务提供者Filter拦截请求,将隐式参数中用户信息装入ThreadLocal中。

 

URL:配置中心里获取的服务信息

RpcStatus

每一个服务有自己的RpcStatus对象,每一个方法也有自己的RpcStatus对象

//URL statistics. (API, Cached, ThreadSafe)
public class RpcStatus {

    //服务URL->RpcStatus
    private static final ConcurrentMap<String, RpcStatus> SERVICE_STATISTICS;
    //服务URL->方法名->RpcStatus
    private static final ConcurrentMap<String, ConcurrentMap<String, RpcStatus>> METHOD_STATISTICS ;
    //缓存
    private final ConcurrentMap<String, Object> values;
    //记录当前调用并发active
    private final AtomicInteger active;
    //记录总调用次数
    private final AtomicLong total ;
    //记录总失败次数
    private final AtomicInteger failed;
    //记录总用时
    private final AtomicLong totalElapsed;
    //记录失败调用的总用时
    private final AtomicLong failedElapsed;
    //记录最大一次用时
    private final AtomicLong maxElapsed;
    private final AtomicLong failedMaxElapsed;
    private final AtomicLong succeededMaxElapsed;
 
    //服务端可执行资源,Semaphore的大小取决于dubbo配置
    private volatile Semaphore executesLimit;
    private volatile int executesPermits;

}

 

异常处理

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初始化完成后再暴露服务。

整合sentinel限流熔断降级

http://dubbo.apache.org/zh-cn/blog/sentinel-introduction-for-dubbo.html

https://github.com/apache/dubbo-sentinel-support

https://github.com/alibaba/Sentinel/wiki/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6%E7%9A%84%E9%80%82%E9%85%8D#dubbo

过滤器Filter

官网介绍:http://dubbo.apache.org/zh-cn/docs/dev/impls/filter.html

实现com.alibaba.dubbo.rpc.Filter

// @Activate(group = {Constants.CONSUMER})
public class MyFilter implements Filter {
    public Result invoke(Invoker<?> invoker, Invocation invocation)
            throws RpcException {
        System.out.println("开始调用 MyFilter");
        //向下执行invoke,继续过滤器链
        Result result = invoker.invoke(invocation);
        System.out.println("结束调用 MyFilter");
        return result;
    }
}

两种配置方式:https://www.jianshu.com/p/d279349435cd

1  Filter上加@Activate,注册成dubbo默认过滤器

2 通过SPI加载过滤器,在dubbo的配置文件中为服务配置过滤器,这种相对第一种稍微繁琐,但是更加灵活。

3 实例

ActiveLimitFilter源码实例:https://my.oschina.net/LucasZhu/blog/1933991

ExecuteLimitFilter源码实例:https://blog.csdn.net/u013160932/article/details/81074322

4 过滤器分为消费者/提供者,针对发送/接收进行过滤

不同协议+序列化性能测试

https://blog.csdn.net/huangjin0507/article/details/52199669

更新本地服务列表

Dubbo消费者监听zk中服务节点信息,当服务节点发生变化,zk会提醒dubbo消费者重新拉取服务信息到本地。

Dubbo消费者RPC调用时使用本地服务列表。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值