關於上面現象的分析以下php
問題描述:mysql
接口偶發性出現接口耗時過長的狀況sql
根源:數據庫
「sockets的快速回收」機制被啓動後端
簡單代碼+數據分析:api
1. 經簡單分析,耗時主要出如今鏈接數據庫的方法:mysql_connect緩存
2. 耗時基本爲3s(3.001s,2.999s,3.000s)安全
進一步分析:服務器
因爲耗時出如今php的mysql_connect函數上,從代碼上基本上能夠確認非業務邏輯問題;網絡
可能狀況:
一、Mysql_connect具體實現問題
經查看具體代碼,未發現有異常。
二、網絡抖動
經抓包確認且不大可能爲穩定爲3秒,非此問題;
三、DNS解析
經分析直接綁定HOST與DNS解析對比,確認非此問題;
四、LVS抖動
根據出現時間,與LVS監控對比,確認非此問題
五、mysql服務器配置或者mysql配置存在問題
待分析
……
最終確認:
Mysql服務器配置問題,啓動了「sockets的快速回收」機制
根據運維和DBA對app機器即(Client端)到mysql服務(Server端)的tcp日誌抓包中出現了passive connection rejected because of time stamp,且抓到了syn數據包,這個即標識tcp請求一次握手成功
爲說明此問題,須要補充如下知識點:
(1) 公司的機器部署架構
大部分公司用LVS作負載均衡,一般是前面一臺LVS,後面多臺後端服務器,它便轉發給後端服務器
(2) TCP協議中的三次握手
(3) 「sockets的快速回收」機制
a) 目的:sockets快速回收
b) 行爲解釋:能夠緩存每一個鏈接最新的時間戳,後續請求中若是時間戳小於緩存的時間戳,即視爲無效,相應的數據包會被丟棄。
c) 涉及參數:tcp_timestamps和tcp_tw_recycle
i. tcp_timestamps默認爲1,tcp_tw_recycle默認爲0
ii. 當tcp_timestamps與tcp_tw_recycle同時爲1時,表示此機制開啓
結論分析:
在有LVS作負載均衡的狀況下,,對於後端服務器來講,請求的源地址就是LVS的地址((nat模式纔會修改源地址,咱們用的都是dr模式)),加上端口會複用,
因此從後端服務器的角度看,本來不一樣客戶端的請 求通過LVS的轉發,就可能會被認爲是同一個鏈接,因而後面的數據包就被丟棄了。
具體的表現一般是是客戶端明明發送的SYN,但服務端就是不響應ACK
後續思考:
一、
既然必須同時激活tcp_timestamps和tcp_tw_recycle纔會觸發這種現象,那隻要禁止 tcp_timestamps,同時激活tcp_tw_recycle,
就能夠既避免丟包問題,又下降TIME_WAIT鏈接數量。若是服務器並不 依賴於RFC1323,那麼這種方法應該也是可行的,不過最好多作測試,以防有其餘的反作用。
二、爲何是3s?
創建鏈接時SYN超時,若是server端接到了clien發的SYN後回了SYN-ACK後client掉線了,
server端沒有收到client回來的ACK,那麼,這個鏈接處於一箇中間狀態,即沒成功,也沒失敗。
因而,server端若是在必定時間內沒有收到的TCP會重發SYN-ACK。在Linux下,默認重試次數爲5次,
重試的間隔時間從1s開始每次都翻售,5次的重試時間間隔爲1s, 2s, 4s, 8s, 16s,總共31s,
第5次發出後還要等32s都知道第5次也超時了,因此,總共須要 1s + 2s + 4s+ 8s+ 16s + 32s = 2^6 -1 = 63s,
TCP纔會把斷開這個鏈接。但跟運維溝通以後咱們的重試機制時間間隔爲3s。
三、安全起見,一般要禁止tcp_tw_recycle,至於TIME_WAIT鏈接過多的問題,能夠經過激活tcp_tw_reuse來緩解
以上分析若有紕漏,麻煩指正,謝謝!