博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
用SpringCloud Alibaba搭建属于自己的微服务(十六)~基础搭建~openfegin+ribbon的rpc调用高可用之重试机制
阅读量:4205 次
发布时间:2019-05-26

本文共 4596 字,大约阅读时间需要 15 分钟。

一.概述

服务之间的rpc调用要能达到高可用,重试机制是必不可少的.

二.重试机制

1.场景一

a.场景

(1).server-user调用server-basic.

(2).server-basic服务有节点A和节点B.
(3).server-user服务通过ribbon的算法拿到了节点A.
(4).server-basic服务节点A挂了.
(5).server-user发起调用.
(6).server-user调用连接超时,调用失败.

b.问题分析

server-basic服务有节点A和节点B,server-user服务从注册中心定时拉取注册表(比如30秒拉取一次),此时server-basic服务的节点A挂了,server-user调用server-basic服务时注册表未能及时更新,以为server-basic服务的节点A是健康,去调用了,结果就是握手失败,调用失败.这个时候如果server-user能够切换实例到节点B,进行重试,那么就解决了这个问题.

c.场景复现

(1)server-user服务关闭ribbon的重试机制,见ribbon相关配置,配置详解注释中已经说明.

server:  port: 1001  #服务端口spring:  application:    name: server-user #服务名称  cloud:    nacos:      discovery:        server-addr: 47.96.131.185:8848      config:        server-addr: 47.96.131.185:8848  #nacos config配置中心ip和端口        file-extension: yaml  #文件扩展名格式,针对于默认的{spring.application.name}-${profile}.${file-extension:properties}配置        enabled: true #开启或关闭配置中心        shared-dataids: mysql-user.yaml #自定义的配置文件dataid,以逗号分隔        refreshable-dataids: mysql-user.yaml #自定义的配置文件dataid实现自动刷新,以逗号分隔(其实就是热加载配置文件)ribbon:  #对所有操作请求都进行重试,默认false(false=只有get请求才会进行重试)  OkToRetryOnAllOperations: false  #响应超时时间  ReadTimeout: 3000  #请求连接的超时时间  ConnectTimeout: 2000  #对当前实例的重试次数,默认0  MaxAutoRetries: 0  #对切换实例的重试次数,默认1  MaxAutoRetriesNextServer: 0

(2)启动一个server-user服务,启动两个server-basic服务不同的端口,测试代码复用上一章节的ribbon负载均衡测试,这里贴出.

server-user服务的RibbonTestConsumerController.java

package com.ccm.server.user.controller;import com.ccm.common.exception.ServerException;import com.ccm.common.exception.result.ResultSet;import com.ccm.server.user.openfeign.ServerBasicFeign;import io.swagger.annotations.Api;import io.swagger.annotations.ApiOperation;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;/** * @Description ribbon负载均衡测试客户端 * @Author ccm * @CreateTime 2020/07/18 19:37 */@RestController@RequestMapping(value = "ribbonTestProducer")@Api(tags = "ribbon负载均衡测试服务端")public class RibbonTestConsumerController {
@Autowired private ServerBasicFeign serverBasicFeign; @ApiOperation(value = "ribbon负载均衡测试") @GetMapping(value = "test01") public ResultSet test01() {
ResultSet
feignVO = serverBasicFeign.test02(); if(feignVO.getCode() == 0) {
return ResultSet.success(feignVO.getData()); } throw new ServerException("调用外部服务失败"); }}

server-user服务的ServerBasicFeign.java

package com.ccm.server.user.openfeign;import com.ccm.common.exception.result.ResultSet;import org.springframework.cloud.openfeign.FeignClient;import org.springframework.web.bind.annotation.GetMapping;/** *  @Description 调用server-basic的feign层 *  @Author ccm *  @CreateTime 2020/07/17 9:46 */@FeignClient(name = "server-basic")public interface ServerBasicFeign {
@GetMapping(value = "openFeignTest/test01") ResultSet
test01(); @GetMapping(value = "ribbonTestProducer/test01") ResultSet
test02();}

server-basic服务的RibbonTestProducerController.java

package com.ccm.server.basic.controller;import com.ccm.common.exception.result.ResultSet;import io.swagger.annotations.Api;import io.swagger.annotations.ApiOperation;import org.springframework.beans.factory.annotation.Value;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;/** * @Description ribbon负载均衡测试服务端 * @Author ccm * @CreateTime 2020/07/18 19:37 */@RestController@RequestMapping(value = "ribbonTestProducer")@Api(tags = "ribbon负载均衡测试服务端")public class RibbonTestProducerController {
@Value("${server.port}") private String port; @ApiOperation(value = "ribbon负载均衡测试") @GetMapping(value = "test01") public ResultSet test01() {
return ResultSet.success("我是server-basic的数据,端口="+port); }}

启动服务

在这里插入图片描述
(3)服务启动成功后等待1分钟(保证server-user中当前的注册表为最新),然后关闭server-basic的其中一个节点,迅速使用swagger调用两次(保证server-user服务中注册表刷新前,一般是10秒左右刷新一次).

显然有一次调用失败,报了连接超时的错误,场景得到复现.

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

d.问题解决.

(1)阅读到这里,读者们早就发现了,默认情况下ribbon是有重试机制的,不需要我们去加入,相关的配置参数如下.

ribbon:  #对所有操作请求都进行重试,默认false(false=只有get请求才会进行重试)  OkToRetryOnAllOperations: false  #响应超时时间  ReadTimeout: 3000  #请求连接的超时时间  ConnectTimeout: 2000  #对当前实例的重试次数,默认0  MaxAutoRetries: 0  #对切换实例的重试次数,默认1  MaxAutoRetriesNextServer: 0

(2)配置建议

a.开启连接重试,关闭响应重试(原因:响应重试一般是被调用方代码执行时间较长,关闭响应重试可以保证代码不会重复执行).
b.关闭当前实例重试,开启切换重试实例(原因:当前实例失败了,第二次重试的失败的几率也会很高).
c.相关配置组合很多,要熟悉这一章节,必须自己手动去配置玩玩,看看不同的效果.

源码地址:

您的点赞、收藏、转发和关注是我持续创作的动力!

转载地址:http://nktli.baihongyu.com/

你可能感兴趣的文章