SpringCloud 整合Zuul/Gateway分布式网关路由

简介:API网关是系统的唯一入口,客户端和消费端都是通过统一的网关接入微服务,在网关层处理所有的非业务功能,具有如下特征:

  路由:动态路由规则;

  性能:服务高可用、负载均衡和具有容错机制;

  安全:Token校验、权限校验、脱敏等;

  限流:流量控制;

  监控:记录请求和响应信息、请求耗时统计、性能监控、链路追踪等;

  缓存:缓存数据;

  灰度发布:线上灰度发布。

一、Zuul

  简介:网关是一个网络整体系统中的前置门户入口,请求首先通过网关,进行路径的路由,定位到具体的服务节点上。Zuul是Netflix开源的微服务网关,采用Java语言开发,可以过滤请求,微服务会在注册中心中进行服务的注册和发现,请求通过zuul来进行路由,实现反向代理和本地负载均衡功能。作用体现在统一入口、鉴权校验、动态路由和减少客户端与服务端的耦合。Zuul默认结合了Ribbon负载均衡和Hystrix熔断功能,适合微服务中实现网关。

  1. pom.xml Maven依赖

<!-- zuul网关 -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>

<!-- zuul网关重试机制 -->
<dependency>
    <groupId>org.springframework.retry</groupId>
    <artifactId>spring-retry</artifactId>
</dependency>

<!-- zuul限流保护 -->
<dependency>
    <groupId>com.marcosbarbero.cloud</groupId>
    <artifactId>spring-cloud-zuul-ratelimit</artifactId>
    <version>1.3.4.RELEASE</version>
</dependency>

  2. application.yml 文件配置

zuul: 
    # 允许敏感头信息
    sensitive-headers: Cookie,Set-Cookie 
    host:
     # 每个服务的http客户端连接池最大连接 max
-total-connections: 1000
     # 每个Route可用的最大连接数 max-per-route-connections: 1000
     # 连接超时时间 connect-timeout-millis: 2000
     # 连接超时时间 socket-timeout-millis: 10000 # 限流 semaphore: max-semaphores: 1000

  3. Zuul注解

    A. @EnableZuulProxy:开启zuul网关;

  4. Zuul过滤器

    A. Zuul提供一个ZuulFilter父类过滤器,在父类中提供了四个抽象方法filterType()、filterOrder()、shouldFilter()、run();

    B. filterType:方法返回的字符串代表当前过滤器的类型,有四个值如下

      pre —— 前置过滤器,在请求被路由前执行,通常用于处理身份认证,日志记录等;

      route —— 路由后过滤器,在路由执行后,服务调用前被调用;

      post —— 后置过滤器,在route或error执行后被调用,一般用于收集服务信息,统计服务性能指标等,也可以对response结果做特殊处理;

      error —— 异常过滤器,任意一个filter发生异常的时候执行或远程服务调用没有反馈的时候执行(超时),通常用于处理异常;

    C. filterOrder:方法返回int数据,用于为同filterType的多个过滤器定制执行顺序,返回值越小,执行顺序越优先;

    D. shouldFilter:方法返回boolean数据,代表当前filter是否生效;

    E. run:具体的过滤执行逻辑,如pre类型的过滤器,可以通过对请求的验证来决定是否将请求路由到服务上;

    F. 过滤器的生命周期

  5. Zuul网关容错

    A. zuul依赖包含了Hystrix依赖,提供了FallbackProvider接口来处理容错逻辑,注意是只针对超时(timeout)异常处理,当请求被Zuul路由后,只要服务有返回(包括异常),都不会触发Zuul的fallback容错逻辑;

    B. 实现FallbackProvider接口:fallbackResponse方法是fallback逻辑,可以根据异常类型决定处理方式。

  6. Zuul服务负载均衡(Ribbon)

  7. 路由

    A. 调用路径:http://网关ip:网关端口/调用服务ID/调用服务具体请求路径,服务ID即注册名。

 

  可参考:微服务Zuul网关参数调优

https://blog.csdn.net/lzxlfly/article/details/88090197

 

二、Gateway

  简介:SpringCloud Gateway是基于WebFlux实现的,底层使用了Netty通信框架,不仅提供了路由方式,还提供了如限流的高级功能,该网关旨在替代Zuul。

  1. 基础

    A. 三大特征:过滤器(Filter)、路由(Route)和断言(Predicate);

      Predicate:含path、after、before、host、header等;

    B. 路由三种方式:基于文件常规配置、基于代码配置(RouteLocator)、结合注册中心和基于文件配置(如Nacos);

      结合注册中心:配置uri,注意lb协议表示启用负载均衡,后面跟着微服务名称;

    C. 高级配置:分布式限流、配置文件配置跨域。

  2. pom.xml Maven依赖

<!-- 不能同时依赖spring-boot-starter-web -->
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId>
   <version>3.0.0</version> </dependency>

   3. application.yml 文件配置

spring:
  cloud:
    gateway:
      discovery:
        locator:
      # 启用服务发现自动路由 enabled:
true
      # 将服务id的路由转成全小写,默认是全大写 lower-case-service-id: true

  4. 过滤器

    A. 过滤器分为前置过滤(pre)和后置过滤(post),执行时order越小越先执行,过滤器又分全局过滤器和局部过滤器;

    B. 自定义全局过滤器(GlobalFilter),如下是Token鉴权过滤器;

package com.ruhuanxingyun.dcy.gateway.gateway.filter;

import com.alibaba.fastjson.JSONObject;
import com.ruhuanxingyun.dcy.common.jwt.config.TokenProvider;
import com.ruhuanxingyun.dcy.common.tool.model.ResultBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.io.File;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;

/**
 * @description: Token校验
 * @author: ruphie
 * @date: Create in 2021/1/27 20:59
 * @company: ruhuanxingyun
 */
@Component
public class JwtFilter implements GlobalFilter, Ordered {

    /**
     * 白名单URI
     */
    private List<String> allowUris = new ArrayList<String>() {{
        add("/dcy-common-redis/api/1.0/lock/redisLock");
    }};

    private static final AntPathMatcher ANT_PATH_MATCHER = new AntPathMatcher(File.separator);

    @Autowired
    private TokenProvider tokenProvider;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        String path = request.getURI().getPath();
        // 不鉴权URL
        if (allowUris.stream().anyMatch(allowUri -> ANT_PATH_MATCHER.match(allowUri, path))) {
            return chain.filter(exchange);
        }

        // Token有效
        String token = tokenProvider.getToken(request);
        if (tokenProvider.verifyToken(token)) {
            return chain.filter(exchange);
        }

        ServerHttpResponse response = exchange.getResponse();
        response.setStatusCode(HttpStatus.UNAUTHORIZED);
        response.getHeaders().add("Content-Type", "application/json; charset=utf-8");
        String json = JSONObject.toJSONString(ResultBuilder.build("token校验失败"));
        // 解决页面字符集乱码
        DataBuffer buffer = response.bufferFactory().wrap(json.getBytes(StandardCharsets.UTF_8));

        return response.writeWith(Flux.just(buffer));
    }

    /**
     * 值越小优先级越高
     *
     * @return 执行顺序
     */
    @Override
    public int getOrder() {
        return 0;
    }

}

    C. 定义局部过滤器(GatewayFilter)。

  5. 集成Nacos

    A. 引入Nacos Maven依赖;

<!-- Nacos注册中心 -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    <version>2.2.3.RELEASE</version>
</dependency>
<!-- 解决SpringCloud 2020.0.0版本bootstrap.yml文件不生效问题 -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-bootstrap</artifactId>
    <version>3.0.0</version>
</dependency>

    B. bootstrap.yml 文件配置;

spring:
  profiles:
    active: dev
  cloud:
    nacos:
      username: nacos
      password: nacos
      discovery:
        # 默认开启
        register-enabled: true
        server-addr: 127.0.0.1:8848
        namespace: ${spring.profiles.active}

    C. 结合Nacos实现动态路由介绍

  若想了解更多Nacos方面知识,可前往SpringCloud Nacos注册和配置中心

  6. 集成Swagger

    A. 引入Swagger Maven依赖;

<!-- Swagger2 API文档 -->
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger2</artifactId>
    <version>3.0.0</version>
</dependency>
<!-- Swagger Bootstrap用户界面 -->
<dependency>
    <groupId>com.github.xiaoymin</groupId>
    <artifactId>swagger-bootstrap-ui</artifactId>
    <version>1.9.6</version>
</dependency>

    B. 自定义SwaggerProvider配置类,实现SwaggerResourcesProvider接口;

package com.ruhuanxingyun.dcy.gateway.gateway.config;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.stereotype.Component;
import springfox.documentation.swagger.web.SwaggerResource;
import springfox.documentation.swagger.web.SwaggerResourcesProvider;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * @description: Swagger入口 配置
 * @author: ruphie
 * @date: Create in 2021/1/25 21:02
 * @company: ruhuanxingyun
 */
@Component
public class SwaggerProvider implements SwaggerResourcesProvider {

    private static final String API_DOCS = "/v2/api-docs";

    @Value("${spring.application.name}")
    private String selfServiceName;

    @Autowired
    private RouteLocator routeLocator;

    @Override
    public List<SwaggerResource> get() {
        List<String> serviceNames = new ArrayList<>();
        // 获取所有可用服务
        routeLocator.getRoutes()
                .filter(route -> {
                    String serviceName = route.getUri().getHost();

                    return ObjectUtil.isNotNull(serviceName) && !StrUtil.equals(serviceName, selfServiceName);
                }).subscribe(route -> serviceNames.add(route.getUri().getHost()));

        // 服务剔除多实例
        Set<String> urls = new HashSet<>();
        List<SwaggerResource> resources = new ArrayList<>();
        serviceNames.forEach(serviceName -> {
            String url = String.format("/%s%s", serviceName, API_DOCS);
            if (!urls.contains(url)) {
                urls.add(url);

                SwaggerResource swaggerResource = new SwaggerResource();
                swaggerResource.setName(serviceName);
                swaggerResource.setUrl(url);
                swaggerResource.setSwaggerVersion("2.0");
                resources.add(swaggerResource);
            }
        });

        return resources;
    }

}

    C. 根据ApiResourceController类,重写Swagger获取数据接口类;

package com.ruhuanxingyun.dcy.gateway.gateway.controller;

import com.ruhuanxingyun.dcy.gateway.gateway.config.SwaggerProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Profile;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import springfox.documentation.swagger.web.*;

import java.util.List;

/**
 * @description: Swagger接口API 控制层
 * @author: ruphie
 * @date: Create in 2021/2/5 9:43
 * @company: ruhuanxingyun
 */
@RestController
@RequestMapping("/swagger-resources")
@Profile({"dev", "test"})
public class SwaggerController {

    @Autowired
    private SwaggerProvider swaggerProvider;

    @GetMapping
    public ResponseEntity<List<SwaggerResource>> swaggerResources() {
        return new ResponseEntity<>(swaggerProvider.get(), HttpStatus.OK);
    }

    @GetMapping("/configuration/ui")
    public ResponseEntity<UiConfiguration> uiConfiguration() {
        return new ResponseEntity<>(UiConfigurationBuilder.builder().build(), HttpStatus.OK);
    }

    @GetMapping("/configuration/security")
    public ResponseEntity<SecurityConfiguration> securityConfiguration() {
        return new ResponseEntity<>(SecurityConfigurationBuilder.builder().build(), HttpStatus.OK);
    }

}

  若想了解更多Swagger方面知识,可前往SpringBoot 整合Swagger API文档

  7. 集成Sentinel

    A. 引入Sentinel Maven依赖;

<!-- Sentinel限流熔断器 -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
    <version>2.2.3.RELEASE</version>
</dependency>
<!-- Sentinel整合nacos -->
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-datasource-nacos</artifactId>
    <version>1.8.0</version>
</dependency>

    B. bootstrap.yml 文件配置;

spring:
  profiles:
    active: dev
  cloud:
    nacos:
      username: nacos
      password: nacos
      discovery:
        # 默认开启
        register-enabled: true
        server-addr: 127.0.0.1:8848
        namespace: ${spring.profiles.active}
    sentinel:
      enabled: true
      transport:
        port: 8719
        dashboard: ${host}:8080
        heartbeat-interval-ms: 3000
      # 服务启动直接建立心跳连接
      eager: true
      datasource:
        # 自定义的流控规则数据源名称
        flow:
          nacos:
            server-addr: ${spring.cloud.nacos.discovery.server-addr}
            namespace: ${spring.profiles.active}
            username: ${spring.cloud.nacos.username}
            password: ${spring.cloud.nacos.password}
            data-id: ${spring.application.name}-flow-rules
            group-id: SENTINEL_GROUP
            data-type: json
            rule-type: flow
        # 自定义的降级规则数据源名称
        degrade:
          nacos:
            server-addr: ${spring.cloud.nacos.discovery.server-addr}
            namespace: ${spring.profiles.active}
            username: ${spring.cloud.nacos.username}
            password: ${spring.cloud.nacos.password}
            data-id: ${spring.application.name}-degrade-rules
            group-id: SENTINEL_GROUP
            data-type: json
            rule-type: degrade

  若想了解更多Sentinel方面知识,可前往SpringCloud Sentinel断路器

 

可参考:Spring Cloud Gateway官方文档

    SpringCloud Gateway 详解

 

三、Nginx

  简介:Nignx采用C语言开发,具有反向代理和负载均衡功能,也可以过滤请求,达到网关效果,可以整合Lua脚本语言,是一个高性能的HTTP、SMIP服务器,适合服务器端负载均衡。

 

四、OpenResty

 

五、Kong

 

posted @ 2020-09-12 14:07  如幻行云  阅读(849)  评论(0编辑  收藏  举报