基于spring cloud gateway+sentinel构建微服务网关
前言
本文代码于GitHub - felixlyd/gateway-sentinel-sample: spring cloud gateway+sentinel+数据安全处理
spring cloud alibaba对应boot、cloud版本
- spring cloud gateway实现API发布、路由转发
- 引入sentinel实现限流和熔断;引入sentinel-dashboard实现限流监控
- 考虑接口安全设计:密文、防重放、签名和验签
- 全局异常处理
- 日志配置
- 自动部署
- actuator健康检查
- 打印日志?打哪些?请求和响应内容打不打?
- 占用哪些端口?sentinel-dashboard和sentinel-client
- sentinel-dashboard部署在哪台机器?
坑指南
无法添加自定义API分组
现象:
经过反复验证测试,spring cloud gateway+sentinel搭建微服务网关时,硬编码配置限流规则时,无法配置自定义API分组Set<ApiDefinition>
加载到GatewayApiDefinitionManager
中。如果有相关硬编码,则启动时无法被sentinel dashboard识别,但限流规则仍然生效。而zuul+sentinel搭建微服务网关,硬编码配置限流规则可以配置自定义API分组。
原因:
尚不明确,可能是sentinel的bug。
测试过程:
- 硬编码限流规则,添加自定义API分组,启动sentinel dashboard,分别启动zuul和gateway,发现gateway不被识别,zuul被识别;2. 硬编码限流规则,去掉自定义API分组,启动sentinel dashboard,分别启动zuul和gateway,两者均被识别。3. 继续测试其他限流规则硬编码的影响,例如普通限流规则、热点限流规则、熔断降级规则、系统规则,均不会造成sentinel dashboard不识别网关应用的现象。
解决办法:
**虽然sentinel+gateway无法通过代码硬编码配置自定义API分组,但gateway本身可以在路由配置中,将API分组为不同的路由,因此可以替代sentinel的自定义API分组。**后续如果进行规则持久化到DB的优化,有可能解决这一问题。
sentinel指定目录失效
修改spring.cloud.sentinel.log.dir,不起作用,还是会到默认的~/logs/csp路径来。 经过测试,2.6.11不生效,2.6.3版本生效
2021.0.4.0* | Spring Cloud 2021.0.4 | 2.6.11 |
---|---|---|
2021.0.1.0 | Spring Cloud 2021.0.1 | 2.6.3 |
请求流重复获取
参考
自定义过滤器 Spring Cloud Gateway—自定义过滤器 - 掘金
Spring Cloud Gateway 4 自定义Filter - 路迢迢 - 博客园
请求流重复获取的一些实现,但可能有问题?
Gateway网关自定义拦截器的不可重复读取数据_databufferutils.join_飘零未归人的博客-CSDN博客 SpringCloud Gateway自定义filter获取body中的数据为空_mameng1998的博客-CSDN博客
SpringCloud Gateway读取Request Body方式 - 掘金
Spring Cloud Gateway(读取、修改 Request Body) - 掘金
讲了几种请求流重复获取方案的缺陷:Spring Cloud Gateway 之获取请求体(Request Body)的几种方式 - 码农的进击 - 博客园
请求流获取和修改的官网API: Spring Cloud Gateway 结合官网API的实现: ModifyRequestBodyGatewayFilterFactory获取并修改请求体_GavinYCF的博客-CSDN博客
Spring cloud gateway中的request是基于Web Flux,和普通的请求方式不同,不能直接按照普通的ServletRequest
去处理请求数据,而是一个reactive.ServletRequest
。
代码
如果使用官网API的ModifyRequestBodyGatewayFilterFactory
去修改请求数据,那么整个路由配置无法放在配置文件application.yml
中,因为官网API需要一个RewriteFunction
,在配置文件中只能写类名,类名是String
,无法转换为RewriteFunction
。官网API也声明了该过滤器只能通过Java代码实现。
代码实现
package com.bocd.mkt.gatewaysentinelsample.config;
import com.bocd.mkt.gatewaysentinelsample.filter.SecurityRequestFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
@Configuration
public class GatewayRoutesConfig {
@Autowired
private SecurityRequestFilter securityRequestFilter;
@Bean
public RouteLocator routeLocator(RouteLocatorBuilder builder){
return builder.routes().route("test", r -> r
.path("/api-a/**")
.filters(f -> f
.modifyRequestBody(String.class,String.class, MediaType.APPLICATION_JSON_VALUE, securityRequestFilter))
.uri("lb://RULE-LITEFLOW")
).build();
}
}
配置信息
解决方式1
继承ModifyRequestBodyGatewayFilterFactory
,重写其配置,将其配置信息改为字符串类型,然后在实现方法中根据RewriteFunction
类名去反射调用spring容器中的RewriteFunction
。
方式1可能有潜在问题,不然为啥gateway官方不这样做?
解决方式2
按照ModifyRequestBodyGatewayFilterFactory
的实现方式,简化其配置,在原方法中,为了能兼容大多数情况,该类需要传入一个输入类名、输出类名、请求的content-type和一个重写方法RewriteFunction
,实际上,我们不需要这么多参数和步骤。
解决方式3
按照官网API建议,将路由配置写在代码中。
全局异常处理
参考
全局异常处理 Spring Cloud Gateway-自定义异常处理 - duanxz - 博客园
【SpringCloud】Spring Cloud Gateway 网关全局异常处理_springcloudgateway全局异常处理_islin_7的博客-CSDN博客
优雅的自定义Spring Cloud Gateway全局异常处理
sentinel的 api-gateway-flow-control | Sentinel
Gateway结合Sentinel1.8限流熔断管理以及自定义异常
SpringCloud: gateway整合sentinel 自定义异常处理类_amadeus_liu2的博客-CSDN博客
端点应用监控
参考
Spring Boot 2.x系列【20】应用监控篇之Actuator入门案例及端点配置详解_management.endpoints_云烟成雨TD的博客-CSDN博客
性能测试
加密解密
打印日志
Spring Cloud Gateway, logging request/response
SpringCloudGateway - Log incoming request url and corresponding route URI