切記: Debug時要檢視所有假設

I.T. 9 遊戲日誌
5 min readSep 24, 2022

近排application做test,然後同事話個app C call app S嘅Restful API (POST)有時會失敗(疑似timeout)。最鬼嘅地方係有時咋喎,但冇問題嘅時候就半秒唔使就有回應。

調查心路歷程

確定重現方法

  1. 用postman喺自己電腦call app S,無法重現。
  2. 由postman拎出curl parameters。喺app C嘅container入面用curl,無法重現。
  3. 調查app C source code,發現實情係用form-urlencode而非postman測試用嘅json (因為app S兩樣都可以食)。curl改用form-urlencode格式去傳payload,無法重現。
  4. 將app C send HTTP request嘅library function抽出來整個最細嘅demo app,用佢來call。係的確可以重現。
    順帶一提,app C底層都係用libcurl去send request。
  5. 喺以上嘅最細demo app中,打印出curl嘅payload,發現其中將所有,都被urlencoded成%25。喺curl嘅payload都做同樣嘅改動之後,係可以重現。
    順帶一提,成個payload係100kB左右,有一萬個逗號。

確定係咪網絡問題?

較早時已經查過當問題出現之時,app S嘅log完全無收到任何嘢。所以首先諗係要搵到底喺邊度斷咗纜,係咪又係pmtu, mss-clamp定WAF/IPS誤中副車嗰啲friend。

個Data flow大概係噉: App C → 雲嘅SLB → Kubernetes (nginx/ingress) → NodePort → Pod App S (nginx)

  • nginx/ingress確定係有收到,而喺失敗嘅case就固定約60秒就會返回status 408
  • Pod App S所在嘅node做tcpdump,喺重現得到嘅時候係一個packet都冇
  • nginx/ingress pod有好多個分佈喺唔同嘅node,但似乎出問題與否並無特定pattern。

似乎唔係Network問題🤔

用其他方式重現?

focus返去用乜嘢payload先可以trigger問題

  1. %25有特別?改%26%41依然可以重現
  2. 換URL? 因為都未hit到App S,試下換一個完全係404 not found嘅path。果然都可以重現。
  3. parameters內容問題?將%25連同附近嘅字換做同等長度嘅a-z字母,依然都可以重現。
  4. Call cluster入面其他service呢?咦咦咦咦無問題喎。
    不過其他service (production)係有用WAF。即係經WAF再ingress就唔會重現。

接近真相

依稀記得WAF唔support HTTP/2,到呢一步先醒起用curl -v,果然直接call而且出問題時係用HTTP/2 (ingress有TLS termination),而經WAF時就用返HTTP/1.1。

亦之所以點解production上面冇見過呢個問題。

然後當用curl --http1.1強制迫佢用HTTP/1.1嘅時候,就唔再重現喇。

結論

Ubuntu 20.04上面嘅curl喺HTTP/2有時會爛。

curl 7.68.0 (x86_64-pc-linux-gnu) libcurl/7.68.0 OpenSSL/1.1.1f zlib/1.2.11 brotli/1.0.7 libidn2/2.2.0 libpsl/0.21.0 (+libidn2/2.2.0) libssh/0.9.3/openssl/zlib nghttp2/1.40.0 librtmp/2.3
Release-Date: 2020-01-08

而的確用最新版嘅curl就點chok都冇問題

curl 7.85.0 (x86_64-pc-linux-musl) libcurl/7.85.0 OpenSSL/1.1.1q zlib/1.2.12 libssh2/1.10.0 nghttp2/1.47.0
Release-Date: 2022-08-31
Protocols: dict file ftp ftps gopher gophers http https imap imaps mqtt pop3 pop3s rtsp scp sftp smb smbs smtp smtps telnet tftp
Features: alt-svc AsynchDNS HSTS HTTP2 HTTPS-proxy IPv6 Largefile libz NTLM NTLM_WB SSL threadsafe TLS-SRP UnixSockets

而由於App C入面嘅libcurl更加難替換,個base container Ubuntu 20.04 apt update完都係一樣爛,所以嘛就直接喺nginx/ingress停用HTTP/2算數。(反正production都係經WAF一直冇用)

至於呢個bug有冇report過呢?搵到最類似嘅係 https://github.com/curl/curl/issues/1410 呢個issue。無論如何最新嘅curl已經改用nghttp作為HTTP/2嘅backend,睇怕即使report都唔會backport得返落Ubuntu 20.04㗎啦。

心得

常用嘅工具如curl都係可以爛,係可以有bug。唔好以為佢哋有咁多人用就一定係bug free。

另,當其時見到result status 408,如果察覺到係4**而聯想到係client side error嘅話,應該可以更快定位到個問題所在。

圖文不符求其配

--

--

I.T. 9 遊戲日誌

「IT9,你的資訊真的很有用」 你好 我就係IT9 Trust me I am IT9 // fb@it9gamelog, youtube@it9gamelog