不論宣稱如何完美的解決方案,都會引入另一個更複雜的問題。

一、背景

我負責的緩存系統有一個版本號模塊,專門用來對數據生成唯一的版本號seq來保證數據的唯一性,從而做到數據數據實時更新以及避免舊數據覆蓋新數據的問題。

這個模塊是其他人交接給我的,之前服務一直都正常,也就沒去細看。

最近訪問量越來越大了,服務出現一些失敗,所以需要先梳理整個模塊的情況,然後在從整體上來優化這個模塊。

二、高延時

版本號模塊一梳理不要緊,發現一大堆問題,如將來處理數據存在瓶頸、模塊不可擴容、存在同步邏輯等等。 其中一個問題就是拉取版本號時,平均延時比較高。 看上圖,可以發現,測試環境平均耗時只有1毫秒,而正式環境是20多毫秒。這個不應該這麼高的。那版本號服務的延時為什麼這麼高呢? 目前我只能說不知道。 上面那個監控也是那個服務交接過來後,在我給那個服務增加功能時增加的。

而對於版本號模塊交接過來後發現沒監控,但是加監控這種優先順序最低的事情是不會單獨去做的,除非出了問題,比如現在,不得不加了。

現在能做的是先tcpdump抓個包看看,結果發現一個奇怪的現象,是的,就是這篇文章的標題,某些ACK延遲了40ms才發出來(當然,監控的高延時不是這個導致的)。

三、延遲ACK

如上圖,可以看到某些時候,服務端回數據包了,但是客戶端卻遲遲沒有回復ACK,直到40毫秒之後才發出ACK。為什麼會這樣呢? 查了TCP相關的資料,瞭解到TCP的 Nagel演算法演算法在某些時候,會進入這樣一個延遲回復ACK的邏輯,然後等待40毫秒,觸發超時邏輯,最終回復了ACK。這對應了我的其中一個座右銘:不論宣稱如何完美的解決方案,都會引入另一個更複雜的問題

weixin.qq.com/r/6DmBmVf (二維碼自動識別)

四、為什麼延遲

對於後臺服務,一般都是長連接,而且是一發一收的模式。場景就像下面的樣子。
  1. CLIENT -> SERVER:發送請求數據
  2. SERVER -> CLIENT:回應收到數據了
  3. SERVER -> CLIENT:返回處理後的數據
  4. CLIENT -> SERVER:回應收到數據了

是不是發現伺服器連續想客戶端發了兩次數據,一次是會請求數據的ACK,一次是請求數據的結果。這兩次回包如果能夠合併為一次,網路上的包是不是一下就少了四分之一。說幹就幹,TCP的Nagel加了這樣一個功能,先探測通信模型是不是一發一收的,符合條件了收到請求數據包時就先不回ACK,等一會,然後帶著處理後的數據一起回ACK,俗稱延遲ACK。那自然就會面臨一個問題:如果沒有下個請求了,這個ACK就遲遲的發不會去了嗎?

所以這個延遲功能就需要加個兜底時間,超過了兜底時間就補上遲遲沒發的ACK。

那怎麼手動關閉這個功能呢?root許可權下把/proc/sys/net/ipv4/tcp_no_delay_ack文件的值修改成1即可。 這樣的問題就是每個TCP數據包都會有一個ACK包,增加了網路的包量。

本文首發於公眾號:天空的代碼世界,微信號:tiankonguse-code。

推薦閱讀:經濟危機(一)《長尾理論》解釋了抖音為啥火了數據髒了怎麼辦

讀恐怖小說《1984》

中年危機筆記與思考靜態庫遇到靜態庫? 歡 迎 分 享 到 朋 友 圈 哦 ?

weixin.qq.com/r/6DmBmVf (二維碼自動識別)


推薦閱讀:
相關文章