美文网首页
springcloud 超时,重试配置相关

springcloud 超时,重试配置相关

作者: guessguess | 来源:发表于2021-07-13 19:56 被阅读0次

先来看看ribbon的相关配置,以及用法。
以下是springboot项目中,ribbon中的配置。

ribbon:
  # 同一实例最大重试次数,不包括首次调用。默认值为0
  MaxAutoRetries: 1
  # 同一个微服务其他实例的最大重试次数,不包括第一次调用的实例。默认值为1
  MaxAutoRetriesNextServer: 1
  # 是否所有操作(GET、POST等)都允许重试。默认值为false
  OkToRetryOnAllOperations: false  
  #响应超时(毫秒)      默认一秒
  ReadTimeout: 1000 
  #连接超时(毫秒)
  ConnectTimeout: 1000 

先来看看这些配置是如何使用的。
下面先写几个demo。分别是注册中心,以及客户端A,客户端B.
其中客户端A主要是作为服务的提供方。而客户端B是作为服务的调用方。

代码示例

1.注册中心

代码相关

@SpringBootApplication
@EnableEurekaServer //开启eureka服务功能
public class Application {
    public static void main(String args[]) {
        SpringApplication.run(Application.class,args);
    }
}

maven配置

<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.gee</groupId>
    <artifactId>my-eureka</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.6.RELEASE</version>
    </parent>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Finchley.SR2</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

application.yml

spring:
  application:
    name: erueka-server

server:
  port: 8761
  
eureka:
  client:
    register-with-eureka: false
    fetch-registry: false

2.服务A

maven配置

<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.gee</groupId>
    <artifactId>my-eureka-client-A</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.6.RELEASE</version>
    </parent>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Finchley.SR2</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

启动类

@SpringBootApplication
@EnableEurekaClient
@EnableDiscoveryClient
public class ApplicationA {
    public static void main(String args[]) {
        SpringApplication.run(ApplicationA.class,args);
    }
}

接口,给与服务B使用

@RestController
public class HelloController {
    
    @GetMapping("/test/get")
    public String get() throws InterruptedException {
        System.out.println("get");
        Thread.sleep(2000);
        return "get";
    }
    
    @PostMapping("/test/post")
    public String post() throws InterruptedException {
        System.out.println("post");
        Thread.sleep(2000);
        return "post";
    }
}

application.yml配置文件

spring:
  application:
    name: clientA

server:
  port: 8081
  
eureka:
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      default-zone: http://localhost:8761/eureka/

3.服务B

maven配置文件

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.gee</groupId>
  <artifactId>my-eureka-client-B</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.6.RELEASE</version>
    </parent>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Finchley.SR2</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>

            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
 
</project>

启动类

@SpringBootApplication
@EnableEurekaClient
@EnableDiscoveryClient
@EnableFeignClients
public class ApplicationB {
    public static void main(String args[]) {
        SpringApplication.run(ApplicationB.class,args);
    }
}

feign

@FeignClient(value = "clientA")
public interface ClientA {
    @GetMapping("/test/get")
    public String get();
    
    @PostMapping("/test/post")
    public String post();
}

测试用的controller

@RestController
public class HelloController {
    
    @Autowired
    private ClientA clientA;
    
    @GetMapping("/test/get")
    public String get() {
        return clientA.get();
    }
    
    @PostMapping("/test/post")
    public String post() {
        return clientA.post();
    }
}

application.yml配置文件

spring:
  application:
    name: clientB

server:
  port: 8082
  
eureka:
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      default-zone: http://localhost:8761/eureka/
      


ribbon:
  # 同一实例最大重试次数,不包括首次调用。默认值为0
  MaxAutoRetries: 1
  # 同一个微服务其他实例的最大重试次数,不包括第一次调用的实例。默认值为1
  MaxAutoRetriesNextServer: 1
  # 是否所有操作(GET、POST等)都允许重试。默认值为false
  OkToRetryOnAllOperations: false
  ReadTimeout: 1000  #响应超时(毫秒)      默认一秒
  ConnectTimeout: 1000 #连接超时(毫秒)

ribbon配置相关

注册中心的配置不变
客户端A的配置也不变
客户端B的配置也不变,客户端b的配置如下

ribbon:
  # 同一实例最大重试次数,不包括首次调用。默认值为0
  MaxAutoRetries: 5
  # 同一个微服务其他实例的最大重试次数,不包括第一次调用的实例。默认值为1
  MaxAutoRetriesNextServer: 0
  # 是否所有操作(GET、POST等)都允许重试。默认值为false
  OkToRetryOnAllOperations: false
  ReadTimeout: 1000  #响应超时(毫秒)      默认一秒
  ConnectTimeout: 1000 #连接超时(毫秒)

启动注册中心,以及客户端B,A。 A启动后暂停。
访问:http://127.0.0.1:8082/test/get
结果如下图

客户端B运行结果

由于A未启动。B去调用A的接口必然会超时。


访问的结果如图

从浏览器的响应时长来看,该接口的时间约为6秒 = (第一次访问 + 5次重试) * ConnectTimeout = 6秒

现在我们将配置修改一下 再次运行
将同个微服务中的实例切换次数改为1.

  MaxAutoRetriesNextServer: 1

再次运行
访问:http://127.0.0.1:8082/test/get
结果如下图

访问的结果如图
从浏览器的响应时长来看,该接口的时间约为12秒。
由于注册中心中只有一个A实例。哪怕切换次数再多次都还是A。
12秒的过程大概如下:
访问接口:
1.第一次调用A服务的接口失败,最多等1秒。
2.随后在该A实例中,继续重试5次,最多等5秒。
3.负载均衡,切换到其同一个微服务中的其他A服务(由于注册中心只有一个A, 必然还是此前的A实例)
4.第一次访问A服务的接口失败,最多等1秒
5.随后在该A实例中,继续重试5次,最多等5秒。
这样子算下来大概就是12秒了。

针对响应超时其实跟连接超时也是一样的结果。只不过一个是规定时间内没有连接到服务端会进行重试,一个是服务端在规定时间内没有写入数据会进行重试。

从上述的实验结果来看:
1.整个接口的最大重试次数为:
1 + MaxAutoRetries + MaxAutoRetriesNextServer * (1 + MaxAutoRetries)
接口正常响应的最大时间:
最大重试次数 * (ReadTimeout + ConnectTimeout)

熔断器与ribbon的配置

先调整服务B,添加熔断器组件

添加熔断器

添加依赖

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>

修改启动类

@SpringBootApplication
@EnableEurekaClient
@EnableDiscoveryClient
@EnableFeignClients
@EnableCircuitBreaker
public class ApplicationB {
    public static void main(String args[]) {
        SpringApplication.run(ApplicationB.class,args);
    }
}

添加fallback的类

@Component
public class HystrixClientA implements ClientA{

    @Override
    public String get() {
        return "hys get";
    }

    @Override
    public String post() {
        return "hys post";
    }

}

修改clientA

@FeignClient(value = "clientA", fallback = HystrixClientA.class)
public interface ClientA {
    @GetMapping("/test/get")
    public String get();
    
    @PostMapping("/test/post")
    public String post();
}

先验证Hystrix的熔断时间小于超时时间的情况下

application.yml添加配置
hystrix的超时时间为500毫秒,而ribbion的最大响应时间为(1+1)2 = 41000ms=4秒。
明显hystrix的时间会小于ribbon的超时时间。

ribbon:
  # 同一实例最大重试次数,不包括首次调用。默认值为0
  MaxAutoRetries: 1
  # 同一个微服务其他实例的最大重试次数,不包括第一次调用的实例。默认值为1
  MaxAutoRetriesNextServer: 1
  # 是否所有操作(GET、POST等)都允许重试。默认值为false
  OkToRetryOnAllOperations: false
  ReadTimeout: 1000  #响应超时(毫秒)      默认一秒
  ConnectTimeout: 1000 #连接超时(毫秒)

feign:
  hystrix:
    enabled: true
  
hystrix:
  command:
    default:
      execution:
        timeout:
          enabled: true
        isolation:
          thread:
            timeoutInMilliseconds: 500

先将注册中心启动,随后先启动,再关闭A服务,再启动B服务。
调用127.0.0.1:8082/test/get

运行结果如下


运行结果

从上图可得知,为500毫秒左右,就是说,熔断器的熔断生效了。ribbion的配置失效了。当ribbion的超时时间小于hystrix的时候,当超时时间到达hystrix配置的超时时间,则会直接进入fallback的方法。

再验证Hystrix的熔断时间大于或者ribbon等于超时时间的情况下

先调整B服务的配置

ribbon:
  # 同一实例最大重试次数,不包括首次调用。默认值为0
  MaxAutoRetries: 1
  # 同一个微服务其他实例的最大重试次数,不包括第一次调用的实例。默认值为1
  MaxAutoRetriesNextServer: 1
  # 是否所有操作(GET、POST等)都允许重试。默认值为false
  OkToRetryOnAllOperations: false
  ReadTimeout: 1000  #响应超时(毫秒)      默认一秒
  ConnectTimeout: 1000 #连接超时(毫秒)

feign:
  hystrix:
    enabled: true

hystrix:
  command:
    default:
      execution:
        timeout:
          enabled: true
        isolation:
          thread:
            timeoutInMilliseconds: 100000

再次运行,结果如下


运行结果

结果为4秒。
因为没有连接没有超时,但是响应超时。总共重试4次,所以结果为4秒左右。

综上:
单独配置ribbon的时候,
1.整个接口的最大重试次数为:
1 + MaxAutoRetries + MaxAutoRetriesNextServer * (1 + MaxAutoRetries)
接口正常响应的最大时间:
最大重试次数 * (ReadTimeout + ConnectTimeout)

如果配置了Hystrix的话,若Hystrix的超时时间小于ribbon的 (连接超时时间 + 响应超时时间) * 重试次数。
则会直接fallback,进行熔断。

如果Hystrix的超时时间大于等于ribbon的 (连接超时时间 + 响应超时时间) * 重试次数,只要当ribbon重试完,就会马上fallback.

因此为了保证俩块配置不冲突。hystrix的超时时间 应该 >= ribbon的 (连接超时时间 + 响应超时时间) * 重试次数

相关文章

网友评论

      本文标题:springcloud 超时,重试配置相关

      本文链接:https://www.haomeiwen.com/subject/oxybtltx.html