成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

懵了!簡(jiǎn)單的HTTP調(diào)用,時(shí)延竟如此大?

網(wǎng)絡(luò) 通信技術(shù) 開(kāi)發(fā)工具
最近項(xiàng)目測(cè)試遇到個(gè)奇怪的現(xiàn)象,在測(cè)試環(huán)境通過(guò) Apache HTTP Client 調(diào)用后端的 HTTP 服務(wù),平均耗時(shí)居然接近 39.2ms。

 最近項(xiàng)目測(cè)試遇到個(gè)奇怪的現(xiàn)象,在測(cè)試環(huán)境通過(guò) Apache HTTP Client 調(diào)用后端的 HTTP 服務(wù),平均耗時(shí)居然接近 39.2ms。

[[278773]]

 

圖片來(lái)自 Pexels

可能乍一看覺(jué)得這不是很正常嗎,有什么好奇怪的?其實(shí)不然,我再來(lái)說(shuō)下一些基本信息。

該后端的 HTTP 服務(wù)并沒(méi)有什么業(yè)務(wù)邏輯,只是將一段字符串轉(zhuǎn)成大寫然后返回,字符串長(zhǎng)度也僅只有 100 字符,另外網(wǎng)絡(luò) Ping 延時(shí)只有 1.9ms左右。

因此,理論上該調(diào)用耗時(shí)應(yīng)該在 2-3ms 左右,但為什么平均耗時(shí) 39.2ms 呢?

 

調(diào)用時(shí)延

 

Ping 時(shí)延

由于工作原因,調(diào)用耗時(shí)的問(wèn)題,對(duì)我來(lái)說(shuō),已經(jīng)見(jiàn)怪不怪了,經(jīng)常會(huì)幫業(yè)務(wù)解決內(nèi)部 RPC 框架調(diào)用超時(shí)的相關(guān)問(wèn)題,但是 HTTP 調(diào)用耗時(shí)是第一次遇到。

不過(guò),排查問(wèn)題的套路是一樣的。主要方法論無(wú)外乎由外而內(nèi)、自上而下等排查方法。我們先來(lái)看看外圍的一些指標(biāo),看能否發(fā)現(xiàn)蛛絲馬跡。

外圍指標(biāo)

系統(tǒng)指標(biāo)

主要看外圍的一些系統(tǒng)指標(biāo)(注意:調(diào)用與被調(diào)用的機(jī)器都要看)。例如負(fù)載、CPU。只需一個(gè) Top 命令就能一覽無(wú)余。

因此,確認(rèn)了下 CPU 和負(fù)載都很空閑。由于當(dāng)時(shí)沒(méi)有截圖,這里就不放圖了。

進(jìn)程指標(biāo)

Java 程序進(jìn)程指標(biāo)主要看 GC、線程堆棧情況(注意:調(diào)用與被調(diào)用的機(jī)器都要看)。

Young GC 都非常少,而且耗時(shí)也在 10ms 以內(nèi),因此沒(méi)有長(zhǎng)時(shí)間的 STW。

因?yàn)槠骄{(diào)用時(shí)間 39.2ms,比較大,如果耗時(shí)是代碼導(dǎo)致,線程堆棧應(yīng)該能發(fā)現(xiàn)點(diǎn)啥。

看了之后一無(wú)所獲,服務(wù)的相關(guān)線程堆棧主要表現(xiàn)是線程池的線程在等任務(wù),這就意味著線程并不忙。

是不是感覺(jué)黔驢技窮了,接下來(lái)該怎么辦呢?

本地復(fù)現(xiàn)

如果本地(本地是 MAC 系統(tǒng))能復(fù)現(xiàn),對(duì)排查問(wèn)題也是極好的。

因此在本地使用 Apache HTTP Client 寫了個(gè)簡(jiǎn)單 Test 程序,直接調(diào)用后端的 HTTP 服務(wù),發(fā)現(xiàn)平均耗時(shí)在 55ms 左右。

咦,怎么跟測(cè)試環(huán)境 39.2ms 的結(jié)果有點(diǎn)區(qū)別。主要是本地與測(cè)試環(huán)境的后端的 HTTP 服務(wù)機(jī)器跨地區(qū)了,Ping 時(shí)延在 26ms 左右,所以延時(shí)增大了。

不過(guò)本地確實(shí)也是存在問(wèn)題的,因?yàn)?Ping 時(shí)延是 26ms,后端 HTTP 服務(wù)邏輯簡(jiǎn)單,幾乎不耗時(shí),因此本地調(diào)用平均耗時(shí)應(yīng)該在 26ms 左右,為什么是 55ms?

是不是越來(lái)越迷惑,一頭霧水,不知如何下手?期間懷疑過(guò) Apache HTTP Client 是不是有什么地方使用的不對(duì)。

因此使用 JDK 自帶的 HttpURLConnection 寫了簡(jiǎn)單的程序,做了測(cè)試,結(jié)果一樣。

診斷

定位

其實(shí)從外圍的系統(tǒng)指標(biāo)、進(jìn)程指標(biāo),以及本地復(fù)現(xiàn)來(lái)看,大致能夠斷定不是程序上的原因。那 TCP 協(xié)議層面呢?

有網(wǎng)絡(luò)編程經(jīng)驗(yàn)的同學(xué)一定知道 TCP 什么參數(shù)會(huì)引起這個(gè)現(xiàn)象。對(duì),你猜的沒(méi)錯(cuò),就是 TCP_NODELAY。

那調(diào)用方和被調(diào)用方哪邊的程序沒(méi)有設(shè)置呢?調(diào)用方使用的是 Apache Http Client ,tcpNoDelay 默認(rèn)設(shè)置的就是 True。

我們?cè)賮?lái)看看被調(diào)用方,也就是我們的后端 HTTP 服務(wù),這個(gè) HTTP 服務(wù)用的是 JDK 自帶的 HttpServer:

  1. HttpServer server = HttpServer.create(new InetSocketAddress(config.getPort()), BACKLOGS); 

居然沒(méi)看到直接設(shè)置 tcpNoDelay 接口,翻了下源碼。哦,原來(lái)在這里。

在 ServerConfig 的類中有這段靜態(tài)塊,用來(lái)獲取啟動(dòng)參數(shù),默認(rèn) ServerConfig.noDelay 為 false:

  1. static { 
  2.     AccessController.doPrivileged(new PrivilegedAction<Void>() { 
  3.         public Void run() { 
  4.             ServerConfig.idleInterval = Long.getLong("sun.net.httpserver.idleInterval", 30L) * 1000L; 
  5.             ServerConfig.clockTick = Integer.getInteger("sun.net.httpserver.clockTick", 10000); 
  6.             ServerConfig.maxIdleConnections = Integer.getInteger("sun.net.httpserver.maxIdleConnections", 200); 
  7.             ServerConfig.drainAmount = Long.getLong("sun.net.httpserver.drainAmount", 65536L); 
  8.             ServerConfig.maxReqHeaders = Integer.getInteger("sun.net.httpserver.maxReqHeaders", 200); 
  9.             ServerConfig.maxReqTime = Long.getLong("sun.net.httpserver.maxReqTime", -1L); 
  10.             ServerConfig.maxRspTime = Long.getLong("sun.net.httpserver.maxRspTime", -1L); 
  11.             ServerConfig.timerMillis = Long.getLong("sun.net.httpserver.timerMillis", 1000L); 
  12.             ServerConfig.debug = Boolean.getBoolean("sun.net.httpserver.debug"); 
  13.             ServerConfig.noDelay = Boolean.getBoolean("sun.net.httpserver.nodelay"); 
  14.             return null
  15.         } 
  16.     }); 

驗(yàn)證

在后端 HTTP 服務(wù),加上啟動(dòng)"-Dsun.net.httpserver.nodelay=true"參數(shù)再試試。

效果很明顯,平均耗時(shí)從 39.2ms 降到 2.8ms:

 

優(yōu)化后調(diào)用時(shí)延

問(wèn)題是解決了,但是到這里如果你就此止步,那就太便宜了這個(gè)案例了,簡(jiǎn)直暴殄天物。

因?yàn)檫€有一堆疑惑等著你呢:

  • 為什么加了 TCP_NODELAY ,時(shí)延就從 39.2ms 降低到 2.8ms?
  • 為什么本地測(cè)試的平均時(shí)延是 55ms,而不是 Ping 的時(shí)延 26ms?
  • TCP 協(xié)議究竟是怎么發(fā)送數(shù)據(jù)包的?

來(lái),我們接著趁熱打鐵。

解惑

①TCP_NODELAY 何許人也?

在 Socket 編程中,TCP_NODELAY 選項(xiàng)是用來(lái)控制是否開(kāi)啟 Nagle 算法。

在 Java 中,為 Ture 表示關(guān)閉 Nagle 算法,為 False 表示打開(kāi) Nagle 算法。你一定會(huì)問(wèn) Nagle 算法是什么?

②Nagle 算法是什么鬼?

Nagle 算法是一種通過(guò)減少通過(guò)網(wǎng)絡(luò)發(fā)送的數(shù)據(jù)包數(shù)量來(lái)提高 TCP/IP 網(wǎng)絡(luò)效率的方法。

它使用發(fā)明人 John Nagle 的名字來(lái)命名的,John Nagle 在 1984 年首次用這個(gè)算法來(lái)嘗試解決福特汽車公司的網(wǎng)絡(luò)擁塞問(wèn)題。

試想如果應(yīng)用程序每次產(chǎn)生 1 個(gè)字節(jié)的數(shù)據(jù),然后這 1 個(gè)字節(jié)數(shù)據(jù)又以網(wǎng)絡(luò)數(shù)據(jù)包的形式發(fā)送到遠(yuǎn)端服務(wù)器,那么就很容易導(dǎo)致網(wǎng)絡(luò)由于太多的數(shù)據(jù)包而過(guò)載。

在這種典型情況下,傳送一個(gè)只擁有 1 個(gè)字節(jié)有效數(shù)據(jù)的數(shù)據(jù)包,卻要花費(fèi) 40 個(gè)字節(jié)長(zhǎng)包頭(即 IP 頭部 20 字節(jié)+TCP 頭部 20 字節(jié))的額外開(kāi)銷,這種有效載荷(payload)的利用率是極其低下。

Nagle 算法的內(nèi)容比較簡(jiǎn)單,以下是偽代碼:

  1. if there is new data to send 
  2.   if the window size >= MSS and available data is >= MSS 
  3.     send complete MSS segment now 
  4.   else 
  5.     if there is unconfirmed data still in the pipe 
  6.       enqueue data in the buffer until an acknowledge is received 
  7.     else 
  8.       send data immediately 
  9.     end if 
  10.   end if 
  11. end if 

具體的做法就是:

  • 如果發(fā)送內(nèi)容大于等于 1 個(gè) MSS,立即發(fā)送。
  • 如果之前沒(méi)有包未被 ACK,立即發(fā)送。
  • 如果之前有包未被 ACK,緩存發(fā)送內(nèi)容。
  • 如果收到 ACK,立即發(fā)送緩存的內(nèi)容。(MSS 為 TCP 數(shù)據(jù)包每次能夠傳輸?shù)淖畲髷?shù)據(jù)分段)

③Delayed ACK 又是什么玩意?

大家都知道 TCP 協(xié)議為了保證傳輸?shù)目煽啃裕?guī)定在接受到數(shù)據(jù)包時(shí)需要向?qū)Ψ桨l(fā)送一個(gè)確認(rèn)。

只是單純的發(fā)送一個(gè)確認(rèn),代價(jià)會(huì)比較高(IP 頭部 20 字節(jié)+TCP 頭部 20 字節(jié))。

TCP Delayed ACK(延遲確認(rèn))就是為了努力改善網(wǎng)絡(luò)性能,來(lái)解決這個(gè)問(wèn)題的。

它將幾個(gè) ACK 響應(yīng)組合合在一起成為單個(gè)響應(yīng),或者將 ACK 響應(yīng)與響應(yīng)數(shù)據(jù)一起發(fā)送給對(duì)方,從而減少協(xié)議開(kāi)銷。

具體的做法是:

  • 當(dāng)有響應(yīng)數(shù)據(jù)要發(fā)送時(shí),ACK 會(huì)隨響應(yīng)數(shù)據(jù)立即發(fā)送給對(duì)方。
  • 如果沒(méi)有響應(yīng)數(shù)據(jù),ACK 將會(huì)延遲發(fā)送,以等待看是否有響應(yīng)數(shù)據(jù)可以一起發(fā)送。在 Linux 系統(tǒng)中,默認(rèn)這個(gè)延遲時(shí)間是 40ms。
  • 如果在等待發(fā)送 ACK 期間,對(duì)方的第二個(gè)數(shù)據(jù)包又到達(dá)了,這時(shí)要立即發(fā)送 ACK。

但是如果對(duì)方的三個(gè)數(shù)據(jù)包相繼到達(dá),第三個(gè)數(shù)據(jù)段到達(dá)時(shí)是否立即發(fā)送 ACK,則取決于以上兩條。

④Nagle 與 Delayed ACK 一起會(huì)發(fā)生什么化學(xué)反應(yīng)?

Nagle 與 Delayed ACK 都能提高網(wǎng)絡(luò)傳輸?shù)男剩谝黄饡?huì)好心辦壞事。

例如,以下這個(gè)場(chǎng)景,A 和 B 進(jìn)行數(shù)據(jù)傳輸 : A 運(yùn)行 Nagle 算法,B 運(yùn)行 Delayed ACK 算法。

如果 A 向 B 發(fā)一個(gè)數(shù)據(jù)包,B 由于 Delayed ACK 不會(huì)立即響應(yīng)。而 A 使用 Nagle 算法,A 就會(huì)一直等 B 的 ACK,ACK 不來(lái)一直不發(fā)送第二個(gè)數(shù)據(jù)包,如果這兩個(gè)數(shù)據(jù)包是應(yīng)對(duì)同一個(gè)請(qǐng)求,那這個(gè)請(qǐng)求就會(huì)被耽誤了 40ms。

⑤抓個(gè)包玩玩吧

我們來(lái)抓個(gè)包驗(yàn)證下吧,在后端 HTTP 服務(wù)上執(zhí)行以下腳本,就可以輕松完成抓包過(guò)程。

  1. sudo tcpdump -i eth0 tcp and host 10.48.159.165 -s 0 -w traffic.pcap 

如下圖,這是使用 Wireshark 分析包內(nèi)容的展示,紅框內(nèi)是一個(gè)完整的 POST 請(qǐng)求處理過(guò)程。

 

測(cè)試環(huán)境數(shù)據(jù)包分析

看 130 序號(hào)和 149 序號(hào)之間相差 40ms(0.1859 - 0.1448 = 0.0411s = 41ms),這個(gè)就是 Nagle 與 Delayed ACK 一起發(fā)送的化學(xué)反應(yīng)。

其中 10.48.159.165 運(yùn)行的是 Delayed ACK,10.22.29.180 運(yùn)行的是 Nagle 算法。

10.22.29.180 在等 ACK,而 10.48.159.165 觸發(fā)了 Delayed ACK,這樣傻傻等了 40ms。

這也就解釋了為什么測(cè)試環(huán)境耗時(shí)是 39.2ms,因?yàn)榇蟛糠侄急?Delayed ACK 的 40ms 給耽誤了。

但是本地復(fù)現(xiàn)時(shí),為什么本地測(cè)試的平均時(shí)延是 55ms,而不是 Ping 的時(shí)延 26ms?我們也來(lái)抓個(gè)包吧。

如下圖,紅框內(nèi)是一個(gè)完整的 POST 請(qǐng)求處理過(guò)程,看 8 序號(hào)和 9 序號(hào)之間相差 25ms 左右,再減去網(wǎng)絡(luò)延時(shí)約是 Ping 延時(shí)的一半 13ms。

 

本地環(huán)境數(shù)據(jù)包分析

因此 Delayed Ack 約 12ms 左右(由于本地是 MAC 系統(tǒng)與 Linux 有些差異)。

  1. Linux 使用的是 /proc/sys/net/ipv4/tcp_delack_min 這個(gè)系統(tǒng)配置來(lái)控制 Delayed ACK 的時(shí)間,Linux 默認(rèn)是 40ms; 
  2. 2. MAC 是通過(guò) net.inet.tcp.delayed_ack 系統(tǒng)配置來(lái)控制 Delayed ACK 的。 
  3.   delayed_ack=0 responds after every packet (OFF
  4.   delayed_ack=1 always employs delayed ack, 6 packets can get 1 ack  
  5.   delayed_ack=2 immediate ack after 2nd packet, 2 packets per ack  (Compatibility Mode) 
  6.   delayed_ack=3 should auto detect when to employ delayed ack, 4packets per ack.  (DEFAULT
  7. 設(shè)置為 0 表示禁止延遲 ACK,設(shè)置為 1 表示總是延遲 ACK,設(shè)置為 2 表示每?jī)蓚€(gè)數(shù)據(jù)包回復(fù)一個(gè) ACK,設(shè)置為 3 表示系統(tǒng)自動(dòng)探測(cè)回復(fù) ACK 的時(shí)機(jī)。 

⑥為什么 TCP_NODELAY 能夠解決問(wèn)題?

tcpNoDelay 關(guān)閉了 Nagle 算法,即使上個(gè)數(shù)據(jù)包的 ACK 沒(méi)有到達(dá),也會(huì)發(fā)送下個(gè)數(shù)據(jù)包,進(jìn)而打破 Delayed ACK 造成的影響。

一般在網(wǎng)絡(luò)編程中,強(qiáng)烈建議開(kāi)啟 tcpNoDelay,來(lái)提升響應(yīng)速度。

當(dāng)然也可以通過(guò) Delayed ACK 相關(guān)系統(tǒng)的配置來(lái)解決問(wèn)題,但由于需要修改機(jī)器配置,很不方便,因此,這種方式不太推薦。

總結(jié)

本文是從一個(gè)簡(jiǎn)單的 HTTP 調(diào)用,時(shí)延比較大而引發(fā)的一次問(wèn)題排查過(guò)程。首先由外而內(nèi)的分析了相關(guān)問(wèn)題,然后定位問(wèn)題并驗(yàn)證解決方案。

最后刨根問(wèn)底對(duì) TCP 傳輸中的 Nagle 與 Delayed ACK 做了全面的講解,更加透徹的剖析了該問(wèn)題案例。

責(zé)任編輯:武曉燕 來(lái)源: 滌生的博客
相關(guān)推薦

2019-07-16 16:00:31

HTTP時(shí)延服務(wù)

2019-07-15 10:22:40

HTTP分析CPU

2017-05-03 16:36:32

Android圖片動(dòng)畫

2018-04-11 10:07:09

大數(shù)據(jù)

2021-02-19 11:55:36

C語(yǔ)言MD5加密

2019-07-31 14:34:00

數(shù)據(jù)庫(kù)MySQLJava

2017-12-15 16:03:28

2015-07-06 10:52:19

BAT數(shù)據(jù)中心

2021-07-05 06:51:41

Nacos微服務(wù)源碼

2019-10-15 09:46:46

機(jī)器學(xué)習(xí)人工智能計(jì)算機(jī)

2017-12-25 09:30:00

互聯(lián)網(wǎng)視頻流量耗費(fèi)成本

2020-03-03 15:40:51

開(kāi)發(fā)技能代碼

2020-02-20 16:07:45

IT需求

2023-03-16 08:14:57

2019-09-02 22:17:01

英特爾

2023-11-15 14:34:05

MySQL悲觀鎖

2020-12-28 07:47:35

動(dòng)態(tài)代理AOP

2022-02-23 20:42:40

HTMLmarkdownturndown

2025-03-04 00:02:00

Python序列報(bào)錯(cuò)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 国产高清一区二区 | 欧美精品久久久久久 | 国产精品欧美一区二区三区不卡 | 在线资源视频 | 日本天堂一区二区 | 久久精品国产免费一区二区三区 | 久久久久久中文字幕 | 亚洲精品久久久蜜桃 | 国产午夜精品一区二区三区四区 | 一级做a| 成人精品福利 | 91视频网址| 99久久精品免费看国产四区 | 伊人网站视频 | 国产精品色 | 99久久亚洲| 成人在线小视频 | 亚洲一区二区三区视频 | 国产精品久久久久无码av | 天天综合成人网 | 日韩精品 电影一区 亚洲 | 91 久久 | 日日摸日日爽 | 国产在线资源 | 婷婷综合五月天 | 欧产日产国产精品v | 久久精品成人 | 在线视频中文字幕 | 九九热精品在线视频 | 精品九九 | 精品视频导航 | 久久久国产精品网站 | 中文字幕男人的天堂 | 妹子干综合 | 欧美一级片在线观看 | 亚洲一区二区三区四区五区午夜 | 波多野吉衣在线播放 | 国产亚洲精品美女久久久久久久久久 | 日韩一区二区福利视频 | 91免费视频观看 | 在线中文视频 |