重慶分公司,新征程啟航
為企業提供網站建設、域名注冊、服務器等服務
為企業提供網站建設、域名注冊、服務器等服務
修改mysql配置文件 max_connections = 1000 重啟mysql。
公司主營業務:網站制作、成都做網站、移動網站開發等業務。幫助企業客戶真正實現互聯網宣傳,提高企業的競爭能力。成都創新互聯公司是一支青春激揚、勤奮敬業、活力青春激揚、勤奮敬業、活力澎湃、和諧高效的團隊。公司秉承以“開放、自由、嚴謹、自律”為核心的企業文化,感謝他們對我們的高要求,感謝他們從不同領域給我們帶來的挑戰,讓我們激情的團隊有機會用頭腦與智慧不斷的給客戶帶來驚喜。成都創新互聯公司推出鐘樓免費做網站回饋大家。
可通過show variables like 'max_connections'; 查看當前設置的連接數。
方法一:進入MYSQL安裝目錄 打開MYSQL配置文件 my.ini 或 my.cnf查找 max_connections=100 修改為 max_connections=1000 服務里重起MYSQL即可
方法二:MySQL的最大連接數默認是100客戶端登錄:mysql -uusername -ppassword
設置新的最大連接數為200:mysql set GLOBAL max_connections=200
顯示當前運行的Query:mysql show processlist
顯示當前狀態:mysql show status
退出客戶端:mysql exit
查看當前最大連接數:mysqladmin -uusername -ppassword variables
現象
Sysbench對MySQL進行壓測, 并發數過大(5k)時, Sysbench建立連接的步驟會超時.
猜想
猜想: 直覺上這很簡單, Sysbench每建立一個連接, 都要消耗一個線程, 資源消耗過大導致超時.
驗證: 修改Sysbench源碼, 調大超時時間, 仍然會發生超時.
檢查環境
猜想失敗, 回到常規的環境檢查:
MySQL error log 未見異常.
syslog 未見異常.
tcpdump 觀察網絡包未見異常, 連接能完成正常的三次握手; 只觀察到在出問題的連接中, 有一部分的TCP握手的第一個SYN包發生了重傳, 另一部分沒有發生重傳.
自己寫一個簡單的并發發生器, 替換sysbench, 可重現場景. 排除sysbench的影響
猜想2
懷疑 MySQL 在應用層因為某種原因, 沒有發送握手包, 比如卡在某一個流程上:
檢查MySQL堆棧未見異常, 仿佛MySQL在應用層沒有看到新連接進入.
通過strace檢查MySQL, 發現?accept()?調用確實沒有感知到新連接.
懷疑是OS的原因, Google之, 得到參考文檔:?A TCP “stuck” connection mystery【】
分析
參考文檔中的現象跟目前的狀況很類似, 簡述如下:
正常的TCP連接流程:
Client 向 Server 發起連接請求, 發送SYN.
Server 預留連接資源, 向 Client 回復SYN-ACK.
Client 向 Server 回復ACK.
Server 收到 ACK, 連接建立.
在業務層上, Client和Server間進行通訊.
當發生類似SYN-flood的現象時, TCP連接的流程會使用SYN-cookie, 變為:
Client 向 Server 發起連接請求, 發送SYN.
Server 不預留連接資源, 向 Client 回復SYN-ACK, 包中附帶有簽名A.
Client 向 Server 回復ACK, 附帶 f(簽名A) (對簽名進行運算的結果).
Server 驗證簽名, 分配連接資源, 連接建立.
在業務層上, Client和Server間進行通訊.
當啟用SYN-cookie時, 第3步的ACK包因為?某種原因?丟失, 那么:
從Client的視角, 連接已經建立.
從Server的視角, 連接并不存在, 既沒有建立, 也沒有”即將建立” (若不啟用SYN-cookie, Server會知道某個連接”即將建立”)
發生這種情況時:
若業務層的第一個包應是從 Client 發往 Server, 則會進行重發或拋出連接錯誤
若業務層的第一個包應是從 Server 發往 Client的, Server不會發出第一個包. MySQL的故障就屬于這種情況.
TCP握手的第三步ACK包為什么丟失
參考文檔中, 對于TCP握手的第三步ACK包的丟失原因, 描述為:
Some of these packets get lost because some buffer somewhere overflows.
我們可以通過Systemtap進一步探究原因.?通過一個簡單的腳本:
probe kernel.function("cookie_v4_check").return
{
source_port = @cast($skb-head + $skb-transport_header, "struct tcphdr")-source
printf("source=%d, return=%d\n",readable_port(source_port), $return)
}
function readable_port(port) {
return (port ((19)-1)) 8 | (port 8)
}
觀察結果, 可以確認cookie_v4_check?(syn cookie機制進行包簽名檢查的函數)會返回 NULL(0). 即驗證是由于syn cookie驗證不通過, 導致TCP握手的第三步ACK包不被接受.
之后就是對其中不同條件進行觀察, 看看是哪個條件不通過. 最終原因是accept隊列滿(sk_acceptq_is_full):
static inline bool sk_acceptq_is_full(const struct sock ?*sk){ ? return sk-sk_ack_backlog sk- ? sk_max_ack_backlog;}
恢復故障與日志的正關聯
在故障處理的一開始, 我們就檢查了syslog, 結論是未見異常.
當整個故障分析完成, 得知了故障與syn cookie有關, 回頭看syslog, 里面是有相關的信息, 只是和故障發生的時間不匹配, 沒有正關聯, 因此被忽略.
檢查Linux源碼:
if (!queue-synflood_warned
sysctl_tcp_syncookies != 2
xchg(queue-synflood_warned, 1) == 0)
pr_info("%s: Possible SYN flooding on port %d. %s.
Check SNMP counters.\n",
proto, ntohs(tcp_hdr(skb)-dest), msg);
可以看到日志受到了抑制, 因此日志與故障的正關聯被破壞.
粗看源碼, 每個listen socket只會發送一次告警日志, 要獲得日志與故障的正關聯, 必須每次測試重啟MySQL.
解決方案
這種故障一旦形成, 難以檢測; 系統日志中只會出現一次, 在下次重啟MySQL之前就不會再出現了; Client如果沒有合適的超時機制, 萬劫不復.
解決方案:
1. 修改MySQL的協議, 讓Client先發握手包. 顯然不現實.
2. 關閉syn_cookie. 有安全的人又要跳出來了.
3. 或者調高syn_cookie的觸發條件 (syn backlog長度). 降低系統對syn flood的敏感度, 使之可以容忍業務的syn波動.
有多個系統參數混合影響syn backlog長度, 參看【】
下圖為精華總結
請點擊輸入圖片描述