切記: Debug時要檢視所有假設
近排application做test,然後同事話個app C call app S嘅Restful API (POST)有時會失敗(疑似timeout)。最鬼嘅地方係有時咋喎,但冇問題嘅時候就半秒唔使就有回應。
調查心路歷程
確定重現方法
- 用postman喺自己電腦call app S,無法重現。
- 由postman拎出curl parameters。喺app C嘅container入面用curl,無法重現。
- 調查app C source code,發現實情係用form-urlencode而非postman測試用嘅json (因為app S兩樣都可以食)。curl改用form-urlencode格式去傳payload,無法重現。
- 將app C send HTTP request嘅library function抽出來整個最細嘅demo app,用佢來call。係的確可以重現。
順帶一提,app C底層都係用libcurl去send request。 - 喺以上嘅最細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問題
%25
有特別?改%26
,%41
依然可以重現- 換URL? 因為都未hit到App S,試下換一個完全係404 not found嘅path。果然都可以重現。
- parameters內容問題?將%25連同附近嘅字換做同等長度嘅a-z字母,依然都可以重現。
- 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嘅話,應該可以更快定位到個問題所在。