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断路器。
三、Nginx
简介:Nignx采用C语言开发,具有反向代理和负载均衡功能,也可以过滤请求,达到网关效果,可以整合Lua脚本语言,是一个高性能的HTTP、SMIP服务器,适合服务器端负载均衡。
四、OpenResty
五、Kong