Gateway网关使用不规范,同事加班泪两行~

简介: Gateway网关使用不规范,同事加班泪两行~

问题


Spring cloud gateway是替代zuul的网关产品,基于Spring 5、Spring boot 2.0以上、Reactor, 提供任意的路由匹配和断言、过滤功能。


笔者公司之前有系统也使用了Spring cloud gateway做为后台应用访问的网关,采用的版本信息为:


组件 版本 其他
spring boot 2.1.7.RELEASE
spring cloud Greenwich.SR2
spring cloud gateway 2.1.2.RELEASE


其中的一个路由的代码如下:


@Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
        RouteLocatorBuilder.Builder routes = builder.routes();
        RouteLocatorBuilder.Builder serviceProvider = routes
          .route("accept",
            r -> r
            .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8_VALUE)
            .and()
            .method(HttpMethod.POST)
            .and()
            .readBody(String.class, readBody -> true)
            .and()
            .path("/gateway-accept/**")
            .filters(f -> {
              f.rewritePath("/gateway-accept/(?<path>.*)", "/${path}");
                  return f;
              })
            .uri("lb://ACCEPT-MICROSERVICE"));                
        return serviceProvider.build();
    }


后台采用的是版本也是spring boot 2.1.2.RELEASE, 内置Tomcat的一个服务。

一开始系统运行良好,最近业务慢慢繁忙,前端调用说偶尔返回这样的问题:


{"timestamp":"2021-01-06T01:50:00.468+0000","path":"/gateway-accept/policy","status":500,"error":"Internal Server Error","message":"Connection prematurely closed BEFORE response"}


字面意思是“响应前过早关闭连接”, 查看后台服务的日志,根本没有调用的信息,再次调用也没有问题,服务和网关都没有任何问题,到底怎么回事?


原因


由于这是Spring cloud gateway的问题,肯定有人碰上过,先去gateway的github上的issues去碰碰运气。


果然,在issues中查找“Connection prematurely closed BEFORE response”,列出了十几条,相关的有七八条,一个一个翻阅,终于一个issue提到了相同的的问题:


https://github.com/spring-cloud/spring-cloud-gateway/issues/1148


image.png


image.png


总结如下


gateway调用后台服务,会使用httpclient连接池里面的连接


gateway使用的httpclient连接池的连接有个参数:max-idle-time,大意指的是多长时间连接不使用就关闭。如果设置为null, 连接不会关闭。


后台服务也有相应的连接对应连接池的连接,参数keepAliveTimeout,大意指后台服务的连接空闲多长时间就会自动关闭,缺省的值就是connection-timeout参数的值。如果为-1就不会有时间限制,缺省值为60s ,但是一般的再server.xml里面设置为20s.


重要:如果网关的连接池的连接max-idle-time不设置(null),后台服务的connection-timeout为20s


  • 假设网络连接池有个连接(gateway-connect-1)对应后台服务的连接(server-connect-1)
  • 前端请求过来,gateway的分配给这个请求的连接正好是(gateway-connect-1), 向后端发起请求调用
  • 同时,服务端连接(server-connect-1)已经等待空闲20秒,自动关闭;
  • 可想而知,服务端没有和(gateway-connect-1)对应的连接,于是发生了异常。


需要在网关层设置spring.cloud.gateway.httpclient.pool.max-idle-time


需要服务端设置server.connection-timeout, 这个值要适当的大于网关层的max-idle-time, 意思就是,网关层对后端连接的空闲时间要小于后端服务的连接空闲时间,这样就不会取到无效的网关层的连接。


解决


根据上面的描述,我在yml里面加入:


spring:
  cloud:
    gateway:
      httpclient:
        pool:
          max-idle-time: 5000
          max-connections: 30


在idea里面发现max-idle-time黄色标底,找不到这个配置,点击没有问题的max-connections, 定位到


image.png


原来,我用的这个gateway版本2.1.2的连接池根本没有提供max-idle-time这个参数,那个版本可以提供?


我新建了一个gateway服务,用的版本如下:


组件 版本 其他
spring boot 2.3.4.RELEASE
spring cloud Hoxton.SR1
spring cloud gateway 2.2.1.RELEASE


在网关服务层设置:


spring:
  cloud:
    gateway:
      httpclient:
        pool:
          max-idle-time: 10000


i点击max-idle-time, 可以看到已经提供这个参数了:


image.png


后端服务设置(后端用的内嵌tomcat):


server:
  tomcat:
    connection-timeout: 20000


服务调用接口:


@GetMapping(value = "/test")
public String get() throws InterruptedException {
    Thread.sleep(10);
    return "laza";
}


第一种设置


网关不设置max-idle-time


后端服务我设置connection-time: 100


使用jmeter测试,配置如下:


image.png


点击开始,后台出现错误:


image.png


第二种设置


网关设置max-idle-time:10000


后端服务我设置connection-time: 20000


jmeter设置和上面一样,测试一切正常。


和版本也有点关系,我生产使用的版本目前不支持max-idle-time这个参数的设置,所以要升级一下gateway使用的版本了。


后续


在issues最后,发现这个:


image.png


点进去以后,发现是蚂蚁金服的同学Lovnx, 详细的阐述了这个问题,有兴趣可以去看一下。他在文章中提到:


reactor.netty.pool.leasingStrategy=lifo获取连接策略由默认的FIFO变更为LIFO,因为LIFO能够确保获取的连接最大概率是最近刚被用过的,也就是热点连接始终是热点连接,而始终用不到的连接就可以被回收掉,LRU的思想(文中原话)


Reactor-Netty 版本问题 我查了一下,spring cloud gateway 2.2.1.release提供的Reactor-Netty版本是0.9.2.RELEASE


<dependency>
      <groupId>io.projectreactor.netty</groupId>
      <artifactId>reactor-netty</artifactId>
      <version>0.9.2.RELEASE</version>
      <scope>compile</scope>
</dependency>


END

相关文章
|
3月前
|
负载均衡 Java 应用服务中间件
Gateway服务网关
Gateway服务网关
97 1
Gateway服务网关
|
7月前
|
Java 开发者 Sentinel
网关修改响应码,拯救业务不规范设计
项目中的后端接口普遍使用200响应码,无论是否出错,导致OpenFeign和第三方应用处理困难。问题在于后端开发者对HTTP基础知识理解不足,未统一处理异常时的响应码。客户端依赖响应体的`code`字段而非HTTP状态码判断请求结果。为解决这个问题,网关可扮演关键角色:
90 0
|
3月前
|
负载均衡 Java API
项目中用的网关Gateway及SpringCloud
Spring Cloud Gateway 是一个功能强大、灵活易用的API网关解决方案。通过配置路由、过滤器、熔断器和限流等功能,可以有效地管理和保护微服务。本文详细介绍了Spring Cloud Gateway的基本概念、配置方法和实际应用,希望能帮助开发者更好地理解和使用这一工具。通过合理使用Spring Cloud Gateway,可以显著提升微服务架构的健壮性和可维护性。
90 0
|
5月前
|
负载均衡 Java 网络架构
实现微服务网关:Zuul与Spring Cloud Gateway的比较分析
实现微服务网关:Zuul与Spring Cloud Gateway的比较分析
255 5
|
6月前
|
Java Sentinel Spring
网关修改响应码,拯救业务不规范设计
本文探讨了在一个未遵循HTTP标准规范的项目中遇到的问题及解决方案。
|
6月前
|
Java API 微服务
服务网关Gateway
该博客文章详细介绍了Spring Cloud Gateway的使用方法和概念。文章首先阐述了API网关在微服务架构中的重要性,解释了客户端直接与微服务通信可能带来的问题。接着,文章通过具体的示例代码,展示了如何在Spring Cloud Gateway中添加依赖、编写路由规则,并对路由规则中的基本概念如Route、Predicate和Filter进行了详细解释。最后,文章还提供了路由规则的测试方法。
服务网关Gateway
|
7月前
|
JSON 前端开发 Java
SpringCloud怎么搭建GateWay网关&统一登录模块
本文来分享一下,最近我在自己的项目中实现的认证服务,目前比较简单,就是可以提供一个公共的服务,专门来处理登录请求,然后我还在API网关处实现了登录拦截的效果,因为在一个博客系统中,有一些地址是可以不登录的,比方说首页;也有一些是必须登录的,比如发布文章、评论等。所以,在网关处可以支持自定义一些不需要登录的地址,一些需要登录的地址,也可以在网关处进行校验,如果未登录,可以返回JSON格式的出参,前端可以进行相关处理,比如跳转到登录页面等。
191 4
|
6月前
|
安全 API
【Azure API 管理】APIM Self-Host Gateway 自建本地环境中的网关数量超过10个且它们的出口IP为同一个时出现的429错误
【Azure API 管理】APIM Self-Host Gateway 自建本地环境中的网关数量超过10个且它们的出口IP为同一个时出现的429错误
|
6月前
|
存储 容器
【Azure 事件中心】为应用程序网关(Application Gateway with WAF) 配置诊断日志,发送到事件中心
【Azure 事件中心】为应用程序网关(Application Gateway with WAF) 配置诊断日志,发送到事件中心
|
6月前
|
负载均衡 Java 应用服务中间件
Gateway服务网关
本节针对微服务中另一重要组件:网关 进行了实战性演练,网关作为分布式架构中的重要中间件,不仅承担着路由分发(重点关注Path规则配置),同时可根据自身负载均衡策略,对多个注册服务实例进行均衡调用。本节我们借助GateWay实现的网关只是技术实现的方案之一,后续大家可能会接触像:Zuul、Kong等,其实现细节或有差异,但整体目标是一致的。