網(wǎng)上有很多關(guān)于pos機(jī)交易超時(shí),Go 驗(yàn)證 TCP SYN 超時(shí)重傳機(jī)制的知識(shí),也有很多人為大家解答關(guān)于pos機(jī)交易超時(shí)的問題,今天pos機(jī)之家(www.rcqwhg.com)為大家整理了關(guān)于這方面的知識(shí),讓我們一起來看下吧!
本文目錄一覽:
pos機(jī)交易超時(shí)
背景最近寫了一個(gè)壓測代碼,測試一個(gè) http 接口,代碼大概是這個(gè)樣子,代碼跑在 Linux 機(jī)器上,內(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)) }}預(yù)期 error
提供 http 服務(wù)的 server,在這樣的壓測條件下會(huì)來不及處理這么多的請(qǐng)求,因此會(huì)存在 5s 超時(shí)的情況。5s 超時(shí)的時(shí)候,cli.Do(req) 會(huì)返回下面的錯(cuò)誤信息。原因是 http.Client 經(jīng)歷 5s 沒有收到結(jié)果,context 到達(dá)了 Deadline。
context deadline exceeded (Client.Timeout exceeded while awaiting headers), cost:5.00031874s其他 error
在壓測過程中,還出現(xiàn)了其他的 error,并且數(shù)量要多于預(yù)期的 context deadline exceeded 錯(cuò)誤。這是錯(cuò)誤信息,錯(cuò)誤信息里隱去了 ip、port。
dial TCP ($ip):($port): connect: connection timed out, cost:3.017266219s
出現(xiàn)這個(gè)錯(cuò)誤的調(diào)用耗時(shí)只有 3s,但是在代碼中初始化 cli 的時(shí)候設(shè)置了 5s 的超時(shí),這是為什么呢?
分析上面的 dial tcp 錯(cuò)誤顯示是發(fā)起 tcp 調(diào)用時(shí)出的錯(cuò),那就需要從 tcp 的方面進(jìn)行分析。
祖?zhèn)魅挝帐宙?zhèn)樓。
client 向 server 發(fā)起第一次握手的時(shí)候,會(huì)發(fā)送 SYN 信號(hào)。如果 client 等待了一個(gè)超時(shí)時(shí)間之后沒有收到 server 的 ACK,client 則會(huì)重試。如果重試之后還是等待超時(shí)了,就再重試。
在 Linux 中,client 重傳 SYN 的次數(shù)由內(nèi)核參數(shù) net.ipv4.tcp_syn_retries 控制,默認(rèn)為 6。
通過以下指令在壓測機(jī)器上查看 SYN 重傳次數(shù),可以看到壓測機(jī)器上發(fā) tcp 請(qǐng)求時(shí)只會(huì)超時(shí)重傳一次 SYN。
$: sysctl -a | grep tcp_syn_retriesnet.ipv4.tcp_syn_retries = 1
重傳間隔是怎么規(guī)定的呢?
SYN 重傳間隔存在過一個(gè) 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 修復(fù)前,超時(shí)時(shí)間是由TCP_RTO_MIN這個(gè)參數(shù)計(jì)算的,該參數(shù)在內(nèi)核代碼/include/net/tcp.h中定義。
#define TCP_RTO_MIN ((unsigned(HZ/5))
bug 修復(fù)之后,超時(shí)時(shí)間由TCP_TIMEOUT_INIT計(jì)算,代碼地址:
https://elixir.bootlin.com/linux/v3.10.107/source/include/net/tcp.h#L136
#define TCP_TIMEOUT_INIT((unsigned(1*HZ)
這個(gè)值在RFC 6298中,定義為1秒。在RFC 1122中為3秒。這是最開始的超時(shí)等待時(shí)間,如果在這段時(shí)間內(nèi)沒有收到 ACK,超時(shí)等待時(shí)間按 2 的指數(shù)倍增長。如果重試次數(shù)為 6 次,那么 RFC 6298 的超時(shí)重傳間隔就是 1, 2, 4, 8, 16, 32;RFC 1122 中就是 3, 6, 9, 18, 36, 72。
通過壓測機(jī)器的內(nèi)核版本號(hào),查證源碼得到該機(jī)器的初始超時(shí)重傳時(shí)間為 1s。
那么這就解釋的通了,壓測機(jī)器 SYN 重傳次數(shù)為 1,所以 tcp 握手的時(shí)候第一次發(fā) SYN,等待了 1s 沒有收到 ACK,又重傳一次,等待 2s 也沒有收到 ACK,這樣總共耗時(shí)了 3s,就報(bào)了 dial tcp: connection timeout。
復(fù)現(xiàn)接下來復(fù)現(xiàn)一下這種情況。
找一臺(tái)服務(wù)器,將 net.ipv4.tcp_syn_retries 設(shè)置為 1。通過編輯 /etc/sysctl.conf 文件實(shí)現(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
開一個(gè)新終端:
$: date '+ %F %T'; telnet 127.0.0.1 5000; date '+ %F %T';
可以看到 tcpdump 中,只收到了兩次 SYN(16:50:20 和 16:50:21),并且兩次間隔為 1s。
而在新終端中,看到整個(gè)調(diào)用的耗時(shí)為 3s(16:50:20 - 16:50:23)。
總結(jié)http 或 tcp 調(diào)用時(shí)的 dial tcp (ip):(port): connect: connection timed out 錯(cuò)誤是 SYN 的超時(shí)重傳機(jī)制引起的。如果遇到這種錯(cuò)誤,一方面需要考慮 server 可以處理請(qǐng)求的 QPS,另一方面也要檢查 client 端重傳相關(guān)參數(shù)的設(shè)置。
參考文獻(xiàn)[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ù)和超時(shí)時(shí)間_陶士涵的菜地的技術(shù)博客_51CTO博客
https://blog.51cto.com/u_15274085/2919125
[4] 《關(guān)于TCP SYN包的超時(shí)與重傳》——那些你應(yīng)該知道的知識(shí)(四)_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
以上就是關(guān)于pos機(jī)交易超時(shí),Go 驗(yàn)證 TCP SYN 超時(shí)重傳機(jī)制的知識(shí),后面我們會(huì)繼續(xù)為大家整理關(guān)于pos機(jī)交易超時(shí)的知識(shí),希望能夠幫助到大家!