SpringCloud2.0.1--Ribbon 重试监听

在SpringCloud中,通常使用的是客服端发现作为负载均衡。SpringCloud全家桶中提供了Ribbon作为客户端负载的优秀框架。
服务器之间的调用直接使用Feign进行调用。Feign默认使用了Ribbon作为负载的实现。
通常来说,进行服务拆分后,每个服务之间都需要支持幂等性,因为可能由于网络的原因,一个接口可能会被重试多次,如果没有做好幂等性控制的话,容易出现数据重复等异常情况。
比如将Ribbon的连接和读取时间设置为2s,最大调用次数为4次,则有如下配置:

ribbon.ConnectTimeout=2000
ribbon.ReadTimeout=2000
ribbon.MaxAutoRetriesNextServer=1
ribbon.MaxAutoRetries=1
ribbon.OkToRetryOnAllOperations=true

在接口调用过程中,所有的异常都会自动重试,直到4次调用都失败后,才会抛出异常。这时可以使用try catch就非常简单的捕获到了异常信息。
但是如果前三次调用都失败了,第四次成功的话,try catch就获取不到中间的异常信息了,微服务之间应该是高可用的,因为都是内网的调用,出现异常的情况是比较少的,所以需要将所有失败的情况记录下来,以便及时发现问题。
首先,添加自己的LoadBalancedRetryFactory

@Configuration
public class RibbonConfiguration {
    @Bean
    public LoadBalancedRetryFactory loadBalancedRetryPolicyFactory(final SpringClientFactory clientFactory) {
        return new DefaultRibbonLoadBalanceRetryFactory(clientFactory);
    }
}

其次添加 DefaultRibbonLoadBalanceRetryFactory

public class DefaultRibbonLoadBalanceRetryFactory extends RibbonLoadBalancedRetryFactory {
    public DefaultRibbonLoadBalanceRetryFactory(SpringClientFactory clientFactory) {
        super(clientFactory);
    }

    @Override
    public org.springframework.retry.RetryListener[] createRetryListeners(String service) {
        return new RetryListener[]{new RibbonRetryListener()};
    }
}

最后是重试监听的实现:RibbonRetryListener


public class RibbonRetryListener implements RetryListener {

    private Logger logger = LoggerFactory.getLogger(getClass());

    @Override
    public <T, E extends Throwable> boolean open(RetryContext context, RetryCallback<T, E> callback) {
        return true;
    }

    @Override
    public <T, E extends Throwable> void close(RetryContext context, RetryCallback<T, E> callback, Throwable throwable) {

    }

    @Override
    public <T, E extends Throwable> void onError(RetryContext context, RetryCallback<T, E> callback, Throwable throwable) {
        String service = ((LoadBalancedRetryContext) context).getServiceInstance().getServiceId();
        logger.error(service + "微服务调用错误:", throwable);
    }
}

这样,所有的失败调用都会log出来,这里可以根据实际业务情况落表或者进行报警处理。

测试使用

这里使用用户服务和订单服务作为测试,首先需要启动config-server,eureka-server两个基础服务。
用户服务中提供接口:


    @RequestMapping("/retryListener")
    @ResponseBody
    public String testRetryListener() {
        try {
            return orderApi.testRetry();
        } catch (Exception e) {
            logger.error("", e);
            return "error:" + e.getMessage();
        }
    }

这里实现非常简单,只是调用order的接口而已。
订单服务则模拟失败的情况,访问的次数不为3的倍数,则休眠2.1s(因为用户服务配置超时时间为2s)。

    private AtomicLong counter = new AtomicLong(1);

    /**
     * 每次請求計數器加一,当请求的次数不为3的倍数时,休眠2.1s返回
     *
     * @return
     * @throws InterruptedException
     */
    @ResponseBody
    @RequestMapping("/testRetry")
    public String testRetry() throws InterruptedException {
        if (counter.incrementAndGet() % 3 != 0) {
            Thread.sleep(2100);
        }
        return "port:" + port;
    }

访问接口:http://localhost:8300/retryListener 可以看到返回了:port:8100数据,查看控制台:
这里写图片描述

异常数据完美记录下来了。

文章中的代码已提交到:
github:https://github.com/cmlbeliever/SpringCloudBucket
码云:https://gitee.com/cmlbeliever/springcloud
工程中包含了微服务的常用实现方式, 欢迎star与fork

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值