Dubbo-Retry超时重试导致数据重复问题

2019-10-21  本文已影响0人  若水_28a8

使用dubbo的重试机制造成了不小的困恼,就希望dubbo能在数据写入操作不进行重试,读取操作进行重试,是否可有相应的配置实现?发现了一篇文章,也是处理重试方面的问题的。转载记录下

原文地址:https://kute.github.io/2018/08/06/Dubbo-Retry%E8%B6%85%E6%97%B6%E9%87%8D%E8%AF%95%E9%98%B2%E6%AD%A2%E6%95%B0%E6%8D%AE%E9%87%8D%E5%A4%8D%E5%B0%8F%E8%AE%B0.html

一、背景

dubbo 服务调用过程中配置了重试,对于 非幂等性接口 ,由于 网络 或者 服务端处理速度较慢,发生超时,重试导致 接口被多次调用进行业务逻辑处理,发生脏数据等问题

二、方案

1、在配置了重试机制的基础上,修改 单个方法的 “重试” 的配置 + (调用方异常捕获 或者 配置降级策略)

dubbo默认未提供 方法 级别 的注解(xml配置是有的),只有 @Service @Reference,重试次数是对 整个service 中的所有方法生效,通过修改某些对于 幂等性 要求较高的“方法”级别的重试配置(如 取消重试,减少重试),避免因重试带来的脏数据问题

问题 1:

对于某些关键服务调用若配置超时不重试,可能引起 数据丢失问题,需要添加 降级

处理: 如:扔到队列,异步消费,消费时进行数据一致性校验,如 数据 是否真正入库配置 降级措施

1.1、服务调用方 添加 parameters 参数,设置 重试次数

如下 ICityService接口服务的方法 findCity 的重试次数 设置为 2,而 此服务的重试次数默认为5。 (类似的对于超时时间 都可以 这么设置:parameters = {“#myMethod#.#property#”, “#propertyValue#”})

1.2、设置 集群容错模式

单独设置 非幂等方法的容错模式为:failfast(快速失败),只调用一次,调用超时则立即失败,然后调用方(consumer) 进行异常捕获,提供降级逻辑。

1.3、服务降级(consumer)

服务降级 是在 业务调用方 实际调用失败后(或者 强制直接走降级)执行 降级策略,以保障服务可用性。

服务降级 可以 配置 在整个 Service 上,也可以单独为 Service 的 某个方法 配置降级策略

基本方法:配置 <dubbo:reference /> 或者 @Reference 的mock 属性, 示例如下

a. 为整个Service 配置降级策略

其中降级处理类如下:

b. 单独设置某个方法的降级策略

这里 对于 findCity 方法的降级处理类 直接用了 ICityServiceMock ,如果我们只是对部分方法 有降级的需求,那么可以提供一个 模板类(适配器),降级处理类继承模板类,然后只实现必要的方法

1.4、调用方(consumer)异常捕获

try{…}catch(..){…} 或者 自定义 切面 或者 filter 处理异常 对于 异常,参见:其他

2、在服务调用前后添加唯一标识进行判断

客户端:每次进行rpc调用前,生成唯一ID(UUID),传递到服务端

服务端:首先判断 以 UUID 为key在redis中是否存在,不存在 则可以执行正常逻辑;若存在,则认为是重试(重复调用)

2.1、通过redis实现

客户端:

对有调用duubo rpc的方法添加切面,以注解声明的接口类以及调用的方法名 为 key,值为UUID.randomUUID(),存于 RpcContext 发送到 服务端。

服务端:通过在对dubbo方法添加切面,判断 redis中是否 存在 以 此UUID为key的缓存,若存在则判定为 重复调用,直接返回,否则 存于redis并设置过期时间

伪码如下:

客户端:

服务端:

代码简单实现:

为客户端提供的注解:

切面:

客户端使用注解:

服务端提供注解:

切面:

服务端使用:

三、其他

1、provider(服务提供方)设置tps以及tps.interval :控制请求频率

2、dubbo异常处理(ExceptionFilter) 顺序

如果是checked异常则直接抛出

如果是unchecked异常但是在接口上有声明,也会直接抛出

如果异常类和接口类在同一jar包里,直接抛出

如果是JDK自带的异常,直接抛出

如果是Dubbo的异常,直接抛出

其余的都包装成RuntimeException然后抛出(避免异常在Client出不能反序列化问题)

3、数据库唯一索引

对于 非幂等 接口,如果可以 借助 数据库唯一索引 保证接口幂等,但是 还是存在 接口调用资源浪费。  

三、参考

1、改造Dubbo,使其可以对接口方法进行注解配置

2、https://my.oschina.net/roccn/blog/871032

上一篇下一篇

猜你喜欢

热点阅读