Zuul配置Hystrix和Ribbon

概述:

由于Spring Cloud Zuul包含了对Hystrix和Ribbon的依赖,所以Zuul拥有线程隔离和断路器的自我保护功能,以及对客户端的负载均衡能力。但是,需要注意在使用path和url的映射关系来配置路由规则时,对于路由转发的请求不会采用HystrixCommand来包装,所以这类路由请求没有线程隔离和断路器的保护以及负载均衡的能力。所以使用Zuul的时候尽量使用path和serviceId的方式配置

路由各种超时时间配置:

hystrix.command.default.execution.isolation.thread.timeoutMilliseconds

该参数用来设置API网关中路由转发请求的HystrixCommand超时时间,单位为毫秒。当路由转发请求的命令执行时间超过该配置值后,Hystrix会将该执行命令标记为TIMEOUT并抛出异常。

ribbon.ConnectTimeout

该参数用来设置路由转发请求的时候,创建请求连接的超时时间。当ribbon.ConnectTimeout的配置值小于hystrix.command.default.execution.isolation.thread.timeoutMilliseconds配置值的时候,若出现路由请求连接超时,会自动进行重试路由请求。如果ribbon.ConnectTimeout的配置值大于hystrix.command.default.execution.isolation.thread.timeoutMilliseconds配置值的时候,不会进行请求重试,直接抛出异常(一般都是要小于timeoutMilliseconds

ribbon.ReadTimeout:

该参数用来设置路由转发请求的超时时间。它的处理与ribbon.ConnectTimeout相似,当ribbon.ReadTimeout的配置值小于hystrix.command.default.execution.isolation.thread.timeoutMilliseconds配置值的时候,若出现路由请求连接超时,会自动进行重试路由请求。如果ribbon.ReadTimeout的配置值大于hystrix.command.default.execution.isolation.thread.timeoutMilliseconds配置值的时候,不会进行请求重试,直接抛出异常。(一般都是要小于timeoutMilliseconds)

Zuul默认连接超时未2s、read超时时间为5s,hystrix 的默认超时时间是 1 秒

实现重试机制方式:

第一步,在zuul的工程中引入spring-retry依赖。

<dependency>
    <groupId>org.springframework.retry</groupId>
    <artifactId>spring-retry</artifactId>
</dependency>
第二步,修改zuul工程的配置文件,添加如下内容。
ribbon:
    #对当前实例的重试次数
    MaxAutoRetries: 3
    #切换实例的重试次数
    MaxAutoRetriesNextServer: 0
zuul:
  retryable: true

第三步,为了模拟出Zuul重试的功能,需要对后端应用服务进行改造,改造后的内容如下:

@RestController
public class HelloEndpoint {

    @RequestMapping(value = "/hello", method = RequestMethod.GET)
    public String hello() {
        System.out.println("request is coming...");
        try {
          Thread.sleep(100000);
       } catch (InterruptedException e) {
          System.out.println("线程被打断... " + e.getMessage());
       }
        return "hello spring ..";
    }
}

通过使用Thread.sleep(100000)达到Zuul转发超时情况,从而触发Zuul的重试功能

熔断处理;

熔断处理-概述:

1、在一些不稳定因素导致路由后面的微服务宕机或者无响应时,zuul 就会累计大量的请求,久而久之基本上所有的请求都会超时,但是请求链接数却不断的在增加,不断的占用资源池不能结束知道超时消耗殆尽导致zuul微服务死机,整体挂机消亡;
2、而 zuul 在这种情况下,提供一种很好的回退机制,针对大量请求时提供了友好的熔断机制,确保在路由微服务修复前,尽量将过多的请求快速响应返回,减轻zuul的压力;
3、在本章节,我们对上面发生的这种普遍现象做了一种简单的回退处理,有效降低微服务的压力,还可以友好的提示给前端用户,或者调用方;
 

熔断处理-逻辑如下:

在zuul工程的配置文件中添加如下:

hystrix:
    command:
        default:
            execution:
                isolation:
                    thread:
                        timeoutInMilliseconds: 20000
                        
ribbon:  
  MaxAutoRetries: 3
  MaxAutoRetriesNextServer: 0
  ReadTimeout: 5000  
  ConnectTimeout: 2000 

在rest请求重试3次且都没有连接成功,就会触发熔断机制(熔断器开关打开),执行Zuul回退机制处理逻辑,当熔断器开关处于打开状态, 经过一段时间后, 熔断器会自动进入半开状态, 这时熔断器只允许一个请求通过. 当该请求调用成功时, 熔断器恢复到关闭状态. 若该请求失败, 熔断器继续保持打开状态, 接下来的请求被禁止通过.

熔断处理-代码实现:

在原有的zuul工程的基础上,添加zuul回退处理类;

package com.springms.cloud.fallback;


import org.springframework.cloud.netflix.zuul.filters.route.ZuulFallbackProvider;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.stereotype.Component;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;

/**
 * 自定义Zuul回退机制处理器。
 *
 * Provides fallback when a failure occurs on a route 英文意思就是说提供一个回退机制当路由后面的服务发生故障时。
 *
 * @author hmilyylimh
 *
 */
@Component
public class CustomZuulFallbackHandler implements ZuulFallbackProvider {

    /**
     * 返回值表示需要针对此微服务做回退处理(该名称一定要是注册进入 eureka 微服务中的那个 serviceId 名称);
     *
     * @return
     */
    @Override
    public String getRoute() {
        return "springms-provider-user";//该名称一定要是注册进入 eureka 微服务中的那个 serviceId 名称
    }

    @Override
    public ClientHttpResponse fallbackResponse() {
        return new ClientHttpResponse() {
            @Override
            public HttpStatus getStatusCode() throws IOException {
                return HttpStatus.BAD_REQUEST;
            }

            @Override
            public int getRawStatusCode() throws IOException {
                return HttpStatus.BAD_REQUEST.value();
            }

            @Override
            public String getStatusText() throws IOException {
                return HttpStatus.BAD_REQUEST.getReasonPhrase();
            }

            @Override
            public void close() {
            }

            /**
             * 当 springms-provider-user 微服务出现宕机后,客户端再请求时候就会返回 fallback 等字样的字符串提示;
             *
             * 但对于复杂一点的微服务,我们这里就得好好琢磨该怎么友好提示给用户了;
             *
             * @return
             * @throws IOException
             */
            @Override
            public InputStream getBody() throws IOException {
                return new ByteArrayInputStream((getRoute() + " fallback").getBytes());
            }

            @Override
            public HttpHeaders getHeaders() {
                HttpHeaders headers = new HttpHeaders();
                headers.setContentType(MediaType.APPLICATION_JSON);
                return headers;
            }
        };
    }
}
测试:

/****************************************************************************************
 一、Zuul 路由后面的微服务挂了后,Zuul 提供了一种回退机制来应对熔断处理:

 1、编写 application.yml 文件,添加应用程序的注解 EnableZuulProxy 配置;
 2、启动 springms-discovery-eureka 模块服务,启动1个端口;
 3、启动 springms-provider-user 模块服务,启动1个端口(application.yml 文件中的 appname 属性不去掉的话,测试一是无法测试通过的);
 4、启动 springms-gateway-zuul-fallback 模块服务,启动1个端口;

 5、新起网页页签,输入 http://localhost:7900/simple/3 正常情况下是能看到 ID != 0 一堆用户信息被打印出来;
 6、新起网页页签,然后输入 http://localhost:8200/springms-provider-user/simple/3,正常情况下是能看到 ID != 0 一堆用户信息被打印出来;

 7、这个时候,停止 springms-provider-user 模块服务;
 8、刷新 http://localhost:8200/springms-provider-user/simple/3 网页,正常情况下会提示 “fallback” 字样的字符串;

 ...... 等待大约两分钟左右 ......(微服务宕机默认好像是120秒再连不上eureka服务的话,就会被eureka服务剔除掉)

 总结:首先 Zuul 作为路由转发微服务,其也提供了一种熔断机制,避免大量请求阻塞在路由分发处;
      其次当注册进入 eureka 服务治理发现框架后,一定时间后还没有连上eureka时,这个时候eureka就会将这个宕机的微服务移除服务治理框架;

 

猜你喜欢

转载自blog.csdn.net/oqqaKun1/article/details/85718993