【問題備忘錄】記一次DNS解析異常現象處理

noname發表於2022-05-12

背景

  • 系統升級改造,當前已有閘道器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的預設版本。
    • 引入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();

相關文章