網(wǎng)上有很多關于pos機交易超時,Go 驗證 TCP SYN 超時重傳機制的知識,也有很多人為大家解答關于pos機交易超時的問題,今天pos機之家(m.afbey.com)為大家整理了關于這方面的知識,讓我們一起來看下吧!
本文目錄一覽:
1、pos機交易超時
pos機交易超時
背景最近寫了一個壓測代碼,測試一個 http 接口,代碼大概是這個樣子,代碼跑在 Linux 機器上,內(nèi)核版本:3.10.107。
package mainimport ( "context" "fmt" "io/ioutil" "net/http" "time")func main() { for { time.Sleep(time.Millisecond * 10) cli := http.Client{ Timeout: 5 * time.Second, } req, err := http.NewRequestWithContext(context.Background(), "GET", "http://xxx.com", nil) if err != nil { fmt.Println(err) continue } now := time.Now() rsp, err := cli.Do(req) if err != nil { fmt.Printf("%v, cost:%v\", err, time.Since(now)) continue } body, err := ioutil.ReadAll(rsp.Body) defer rsp.Body.Close() if err != nil { fmt.Println(err) continue } fmt.Printf("len of body:%v", len(body)) }}預期 error
提供 http 服務的 server,在這樣的壓測條件下會來不及處理這么多的請求,因此會存在 5s 超時的情況。5s 超時的時候,cli.Do(req) 會返回下面的錯誤信息。原因是 http.Client 經(jīng)歷 5s 沒有收到結(jié)果,context 到達了 Deadline。
context deadline exceeded (Client.Timeout exceeded while awaiting headers), cost:5.00031874s其他 error
在壓測過程中,還出現(xiàn)了其他的 error,并且數(shù)量要多于預期的 context deadline exceeded 錯誤。這是錯誤信息,錯誤信息里隱去了 ip、port。
dial TCP ($ip):($port): connect: connection timed out, cost:3.017266219s
出現(xiàn)這個錯誤的調(diào)用耗時只有 3s,但是在代碼中初始化 cli 的時候設置了 5s 的超時,這是為什么呢?
分析上面的 dial tcp 錯誤顯示是發(fā)起 tcp 調(diào)用時出的錯,那就需要從 tcp 的方面進行分析。
祖?zhèn)魅挝帐宙?zhèn)樓。
client 向 server 發(fā)起第一次握手的時候,會發(fā)送 SYN 信號。如果 client 等待了一個超時時間之后沒有收到 server 的 ACK,client 則會重試。如果重試之后還是等待超時了,就再重試。
在 Linux 中,client 重傳 SYN 的次數(shù)由內(nèi)核參數(shù) net.ipv4.tcp_syn_retries 控制,默認為 6。
通過以下指令在壓測機器上查看 SYN 重傳次數(shù),可以看到壓測機器上發(fā) tcp 請求時只會超時重傳一次 SYN。
$: sysctl -a | grep tcp_syn_retriesnet.ipv4.tcp_syn_retries = 1
重傳間隔是怎么規(guī)定的呢?
SYN 重傳間隔存在過一個 bug: kernel/git/torvalds/linux.git - Linux kernel source tree
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=4d22f7d372f5769c6c0149e427ed6353e2dcfe61
在 bug 修復前,超時時間是由TCP_RTO_MIN這個參數(shù)計算的,該參數(shù)在內(nèi)核代碼/include/net/tcp.h中定義。
#define TCP_RTO_MIN ((unsigned(HZ/5))
bug 修復之后,超時時間由TCP_TIMEOUT_INIT計算,代碼地址:
https://elixir.bootlin.com/linux/v3.10.107/source/include/net/tcp.h#L136
#define TCP_TIMEOUT_INIT((unsigned(1*HZ)
這個值在RFC 6298中,定義為1秒。在RFC 1122中為3秒。這是最開始的超時等待時間,如果在這段時間內(nèi)沒有收到 ACK,超時等待時間按 2 的指數(shù)倍增長。如果重試次數(shù)為 6 次,那么 RFC 6298 的超時重傳間隔就是 1, 2, 4, 8, 16, 32;RFC 1122 中就是 3, 6, 9, 18, 36, 72。
通過壓測機器的內(nèi)核版本號,查證源碼得到該機器的初始超時重傳時間為 1s。
那么這就解釋的通了,壓測機器 SYN 重傳次數(shù)為 1,所以 tcp 握手的時候第一次發(fā) SYN,等待了 1s 沒有收到 ACK,又重傳一次,等待 2s 也沒有收到 ACK,這樣總共耗時了 3s,就報了 dial tcp: connection timeout。
復現(xiàn)接下來復現(xiàn)一下這種情況。
找一臺服務器,將 net.ipv4.tcp_syn_retries 設置為 1。通過編輯 /etc/sysctl.conf 文件實現(xiàn):
vim /etc/sysctl.confnet.ipv4.tcp_syn_retries = 1
在終端中:
$: iptables -A INPUT --protocol tcp --dport 5000 --syn -j DROP$: tcpdump -i lo -Ss0 -n src 127.0.0.1 and dst 127.0.0.1 and port 5000
開一個新終端:
$: date '+ %F %T'; telnet 127.0.0.1 5000; date '+ %F %T';
可以看到 tcpdump 中,只收到了兩次 SYN(16:50:20 和 16:50:21),并且兩次間隔為 1s。
而在新終端中,看到整個調(diào)用的耗時為 3s(16:50:20 - 16:50:23)。
總結(jié)http 或 tcp 調(diào)用時的 dial tcp (ip):(port): connect: connection timed out 錯誤是 SYN 的超時重傳機制引起的。如果遇到這種錯誤,一方面需要考慮 server 可以處理請求的 QPS,另一方面也要檢查 client 端重傳相關參數(shù)的設置。
參考文獻[1] 理解 timeout,這一篇就夠了 - poslua | ms2008 Blog
https://ms2008.github.io/2017/04/14/tcp-timeout/
[2] net.ipv4.tcp_syn_retries參數(shù)的含義_來自萬古的憂傷的博客-CSDN博客
https://blog.csdn.net/weixin_45413603/article/details/113891804
[3] [TCP] tcp連接SYN超時重傳次數(shù)和超時時間_陶士涵的菜地的技術(shù)博客_51CTO博客
https://blog.51cto.com/u_15274085/2919125
[4] 《關于TCP SYN包的超時與重傳》——那些你應該知道的知識(四)_BBIE的博客-CSDN博客_syn重傳
https://blog.csdn.net/sinat_17736151/article/details/82804404
[5] SYN retransmits: Add new parameter to retransmits_timed_out()
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=4d22f7d372f5769c6c0149e427ed6353e2dcfe61
[6] tcp.h - include/net/tcp.h - Linux source code (v3.10.107) - Bootlin
https://elixir.bootlin.com/linux/v3.10.107/source/include/net/tcp.h#L136
以上就是關于pos機交易超時,Go 驗證 TCP SYN 超時重傳機制的知識,后面我們會繼續(xù)為大家整理關于pos機交易超時的知識,希望能夠幫助到大家!