背景

  • 系统升级革新,以后已有网关A,为了平滑降级,先部署网关B,并且在网关A和B前加一层转发层(IAS)。
  • 定时工作调用网关B下的服务接口时,接口返回:

    {  "timestamp":"2022-05-09T10:02:35.889+08:00",  "path":"/xxx/yyy",  "status":404,  "error":"Not Found",  "message":null,  "requestId":"06f3daf5-67392626"}
  • 转发层(IAS)的申请日志没有查到申请记录,网关A的申请日志也没有记录。

问题定位

  1. 确认IAS和网关B是否失常:不走域名,通过IP申请,接口调用胜利。论断:失常。
  2. 确认DNS是否失常:登陆容器,在容器内执行curl,接口调用胜利。论断:失常。

综上:初步狐疑是调用服务的程序有问题。服务采纳spring-webfluxWebClient调用接口,须要排查WebClient是否有DNS缓存。

问题确认

通过谷歌关键字搜寻,胜利定位到一个github问题:Document How To Switch DNS Resolver · Issue #1431 · reactor/reactor-netty · GitHub,再通过问题里的链接,定位到官网Reactor Netty Reference Guide (projectreactor.io),通过官网文档的阐明,得悉webclient底层用到的reactor-netty有对DNS做了缓存,默认最长缓存工夫为Int的最大值,也就是21亿秒

如果是缓存起因,那重启之后服务调用应该就会失常了,尝试重启之后发现的确能够调用到服务了。

问题解决

批改DNS缓存时长

依据文档,能够设置DNS缓存工夫

webClient = WebClient.builder()        .clientConnector(new ReactorClientHttpConnector(                HttpClient.create().followRedirect(true)        ))        .build();    

改为以下即可

webClient = WebClient.builder()        .clientConnector(new ReactorClientHttpConnector(                HttpClient.create()                        .resolver(spec -> spec.queryTimeout(Duration.ofSeconds(dnsCacheMaxTimeToLive)))                        .followRedirect(true)        ))        .build();

然而以后我的项目springboot版本是2.1.3.RELEASE,对应默认引入的reactor-netty版本是0.8.5.RELEASE,该版本没有resolver办法。

降级版本

  • 显式引入reactor-netty,指定版本1.0.15,启动报错NoSuchMethodException,发现是显式引入的reactor-netty跟springboot默认引入的netty-codec-http版本抵触了。

    • 降级springboot版本到2.3.0.RELEASE.
    • 顺便降级spring版本到5.3.18,解决下spring零日破绽问题。因为springboot默认有引入spring,只需批改默认引入的版本即可:配置maven的properties:<spring-framework.version>5.3.18</spring-framework.version>”,解决下spring零日破绽问题。
    • 因为spring-boot-dependencies默认有配置了netty.version,同上配置maven的properties:“<netty.version>4.1.72.Final</netty.version>”,笼罩springboot的默认版本。
    • 因为spring-boot-dependencies默认有配置了netty.version,同上配置maven的properties:“<netty.version>4.1.72.Final</netty.version>”,笼罩springboot的默认版本。
    • 引入io.projectreactor:reactor-core,版本3.4.17
  • 执行完以上降级之后,系统启动胜利,然而调内部的一个接口时报错:DataBufferLimitException: Exceeded limit on max bytes to buffer : 262144。新版springboot默认限度数据包大小为256K,参照以下文章spring-cloud-gateway缓存区不够用的解决办法来解决,因为我这是WebClient申请内部接口报错,所以创立WebClient时调大限度:

    webClient = WebClient.builder()      .clientConnector(new ReactorClientHttpConnector(              HttpClient.create()                      .resolver(spec -> spec.queryTimeout(Duration.ofSeconds(dnsCacheMaxTimeToLive)))                      .followRedirect(true)      ))      .codecs(configurer -> configurer              .defaultCodecs()              .maxInMemorySize(maxInMemorySize))      .build();