美文网首页
【Spring Cloud 系列 六】Zuul 构建微服务网关

【Spring Cloud 系列 六】Zuul 构建微服务网关

作者: 司鑫 | 来源:发表于2018-09-03 00:38 被阅读34次

    一 为什么需要使用微服务网关


    当使用微服务架构时,我们会将单体应用拆分成很多小的服务,每个服务一般都会有不同的网络地址,而客户端可能需要调用多个服务接口才能完成一个业务需求,这样客户端就会直接与各个服务进行通信,造成以下可能出现的问题:

    • 客户端多次请求不同的微服务,增加了客户端的复杂性
    • 存在跨域请求,在一定场景下处理相对复杂
    • 认证复杂,每个服务都需要独立认证
    • 难以重构,随着项目的迭代,可能需要重新划分微服务,那么客户端如果直接和服务进行通信,那么将会很难进行重构

    以上问题都可以通过加入网关来解决,网关是介于客户端和微服务端之间的中间层,所有的外部请求都需要先经过微服务网关,然后由网关在进行进一步的处理。封装了应用程序的内部结构,客户端只需要与网关打交道。


    二 Zuul 简介


    Zuul 是 Netflix 开源的微服务网关,可以和 Eureka、Ribbon、Hystrix 等组件配合使用。Zuul 的核心是提供了一些列的过滤器,完成下列功能:

    • 身份认证与安全:识别每个资源的验证要求,并拒绝那些不符合要求的请求
    • 审查与监控:在边缘位置追踪有意义的数据和统计结果
    • 动态路由
    • 压力测试:为每一种负载类型分配相应容量,并启用超出限定值的请求
    • 静态响应处理:在边缘位置直接建立部分响应,从而避免其转发到内部集群

    Spring Cloud 对 Zuul 进行了整合与增强,Zuul 目前使用的默认HTTP 客户端是 Apache HTTP client,也可以设置使用 RestClient 或者 okhttp3.OKHttpClient,只需要设置对应的配置ribbon.restclient.enabled=trueribbon.okhttp.enabled=true

    三 编写 Zuul 微服务网关


    1 创建一个新项目(microservice-gateway-zuul),并添加相关依赖
     compile group: 'org.springframework.cloud', name: 'spring-cloud-starter-netflix-zuul', version:'1.4.0.RELEASE'
        compile group: 'org.springframework.cloud', name: 'spring-cloud-starter-netflix-eureka-client', version:'1.4.0.RELEASE'
    
    2 在启动类上添加注解@EnableZuulProxy,声明一个代理,该代理同时还整合了 Ribbon 和 Hystrix
    @SpringBootApplication
    @EnableZuulProxy
    public class ZuulApplication {
      public static void main(String[] args) {
        SpringApplication.run(ZuulApplication.class, args);
      }
    }
    
    
    3 编写配置文件application.yml
    server:
      port: 8040
    spring:
      application:
        name: microservice-gateway-zuul
    eureka:
      client:
        service-url:
          defaultZone: http://localhost:8761/eureka/
      instance:
        prefer-ip-address: true
    
    4 启动相关的服务
    • microservice-discovery-eureka
    • mircroservice-provider-user
    • microservice-consumer-movie-ribbon
    • microservice-gateway-zuul

    当访问 http://localhost:8040/microservice-consumer-movie/user/1 时,请求会被转发到 mocroservice-consumer-movie-ribbon服务中的 /user/1 接口。

    四 路由配置详解


    在上个demo中我们对不同的service的 application name 进行了代理,我们还可以使用 Zull 代理部分服务,或者对 URL 进行更加准确的控制

    自定义指定微服务的访问路径

    配置 zuul.routes.「指定微服务的 serviceId」= 指定路径,例如

    zuul:
      routes:
        microservice-provider-user: /user/**
    
    通配符 含义 举例 解释
    ? 匹配任意单个字符 /feign-consumer/? 匹配/feign-consumer/a,/feign-consumer/b,/feign-consumer/c等
    * 匹配任意数量的字符 /feign-consumer/* 匹配/feign-consumer/aaa,feign-consumer/bbb,/feign-consumer/ccc等,无法匹配/feign-consumer/a/b/c
    ** 匹配任意数量的字符 /feign-consumer/* 匹配/feign-consumer/aaa,feign-consumer/bbb,/feign-consumer/ccc等,也可以匹配/feign-consumer/a/b/c
    忽略指定微服务
    zuul:
      ignored-services: microservice-provider-user,microservice-consumer-movie // 多个服务使用 , 分割
    
    忽略所有服务,只路由指定的服务
    zuul:
      ignored-services: '*'   # 使用'*'可忽略所有微服务
      routes:
        microservice-provider-user: /user/**
    
    同时指定服务的 serviceId 和 对应路径
    zuul:
      routes:
        user-route:                   # 该配置方式中,user-route只是给路由一个名称,可以任意起名。
          service-id: microservice-provider-user
          path: /user/**              # service-id对应的路径
    
    同时指定 path 和 URL
    zuul:
      routes:
        user-route:                   # 该配置方式中,user-route只是给路由一个名称,可以任意起名。
          url: http://localhost:8000/ # 指定的url
          path: /user/**              # url对应的路径。
    

    这种配置方式的路由 HystrixRibbon 都不会工作

    同时指定 URL 和 path,并且 HystrixRibbon 可以正常工作
    zuul:
      routes:
        user-route:
          path: /user/**
          service-id: microservice-provider-user
    ribbon:
      eureka:
        enabled: false    # 禁用掉ribbon的eureka使用。详见:http://cloud.spring.io/spring-cloud-static/Camden.SR3/#_example_disable_eureka_use_in_ribbon
    microservice-provider-user:
      ribbon:
        listOfServers: localhost:8000,localhost:8001
    
    路由前缀
    zuul:
      prefix: /api
      strip-prefix: false
      routes:
        microservice-provider-user: /user/**
    

    当访问 Zuul 的 /api/mocroservice-provide-user/1 时会被转发到 microservice-provider-user/api/1

    忽略某些路径
    zuul:
      ignoredPatterns: /**/admin/**   # 忽略所有包括/admin/的路径
      routes:
        microservice-provider-user: /user/**
    
    五 Zuul 的安全与 Header
    敏感 Header 的设置

    不同服务之间通信时会共享 Header,可以对敏感的 Header 进行设置,避免外泄

    zuul:
      routes:
        user-route:
          path: /user/**
          service-id: microservice-provider-user
          sensitive-headers: Cookie, Set-Cookie ... 
    
    忽略 Header
    zuul:
      ignored-headers: Header 1, header 2
    

    默认情况下,zuul.ignored-headers 是空值,但如果项目中存在 Spring security的依赖,那么 zuul.ignored-headers 就会存在一些header,如果我们需要使用下游服务中的 header 时,需要将 zuul.ingoredSecurity-Headers设置为 false

    六 Zuul 的容错与回退


    在 Spring Cloud 中,Zuul 已经默认整合了 hystrix。想要为 Zuul 添加回退,需要实现 ZuulFallbackProvider 接口,在实现类中,指定为哪个服务提供回退,并提供一个 ClientResponse 作为回退响应,例如:

    @Component
    public class MyFallbackProvider implements FallbackProvider {
      @Override
      public String getRoute() {
        // 表明是为哪个微服务提供回退,*表示为所有微服务提供回退
        return "*";
      }
    
      @Override
      public ClientHttpResponse fallbackResponse(Throwable cause) {
        if (cause instanceof HystrixTimeoutException) {
          return response(HttpStatus.GATEWAY_TIMEOUT);
        } else {
          return this.fallbackResponse();
        }
      }
    
      @Override
      public ClientHttpResponse fallbackResponse() {
        return this.response(HttpStatus.INTERNAL_SERVER_ERROR);
      }
    
      private ClientHttpResponse response(final HttpStatus status) {
        return new ClientHttpResponse() {
          @Override
          public HttpStatus getStatusCode() throws IOException {
            return status;
          }
    
          @Override
          public int getRawStatusCode() throws IOException {
            return status.value();
          }
    
          @Override
          public String getStatusText() throws IOException {
            return status.getReasonPhrase();
          }
    
          @Override
          public void close() {
          }
    
          @Override
          public InputStream getBody() throws IOException {
            return new ByteArrayInputStream("服务不可用,请稍后再试。".getBytes());
          }
    
          @Override
          public HttpHeaders getHeaders() {
            // headers设定
            HttpHeaders headers = new HttpHeaders();
            MediaType mt = new MediaType("application", "json", Charset.forName("UTF-8"));
            headers.setContentType(mt);
            return headers;
          }
        };
      }
    }
    

    相关文章

      网友评论

          本文标题:【Spring Cloud 系列 六】Zuul 构建微服务网关

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