在負載較重的MySQL服務(wù)器上,有時你偶爾會看到一些連接超時的錯誤,諸如: Can’t connect to MySQL server on ‘mydb’(110)。如果當(dāng)時你有多個連接請求,你會發(fā)現(xiàn)其它連接卻沒問題。這類問題開始時很不顯眼,且長時間來看幾乎可以忽略不計(注:次數(shù)不多),類似于百萬分之一的發(fā)生率,但是在服務(wù)器負載不斷加重時,可能出現(xiàn)的頻率將有所上升。
如果你對連接進行計時你會發(fā)現(xiàn),連接一般都接近3-9秒。這個時長有時也很詭異,多年前我就曾遇到過一次,當(dāng)時數(shù)據(jù)庫請求連接被重置,SYN包一直被丟棄。3秒就有一個SYN包被拋棄,9秒有兩被拋棄。如果你也碰到了類似情況,則有可能是你的網(wǎng)絡(luò)存在問題或你的數(shù)據(jù)庫服務(wù)器請求偵聽隊列溢出,你可以通過運行netstat -s命令進行檢查,可能會返回類似于:偵聽隊列的Socket發(fā)生了38409次溢出,38409個SYN包被丟棄,這就意味著偵聽Socket的內(nèi)核緩存溢出了,SYN包將不得不被丟棄 -- MySQL并不是在需要時就盡快接受連接。
如果發(fā)生了這種情況,有2個調(diào)優(yōu)的地方你可以考慮。
1. Linux內(nèi)核:net.ipv4.tcp_max_syn_backlog,這參數(shù)是用來設(shè)置所有Socket內(nèi)核緩存大小的。我的系統(tǒng)缺省值為2048,其它版本可能不盡相同,如果你的連接并發(fā)較大則你可能需要將此值提高到8192左右。具體匹配情況我會在下面介紹。
2.
MySQL參數(shù):back_log,缺省值為50。你可能需將此值設(shè)置為1000或更高。同時,你可能提高net.core.somaxconn內(nèi)核參數(shù)值,這個參數(shù)是用來設(shè)置偵聽隊列的最大深度。我本人內(nèi)核中此參數(shù)設(shè)置的是128,這在很多情況下會偏低。
現(xiàn)在我們來深入研究下這個問題。首先看看MySQL是如何接受連接的。有個主線程將接受所有請求偵聽Socket的連接。當(dāng)有個新連接來到時,主線程將為新連接創(chuàng)建一個新的Socket,同時創(chuàng)建一個新的子線程或從緩存中取一個子線程來處理這個連接。站在MySQL網(wǎng)絡(luò)通訊基多線程這點來看,多核是有利的,但對于主線程來說,多核并沒什么用。通常主線程接受連接會很快,但是,如果主線程因為互斥等待或為啟動新線程而等待,則偵聽隊列可能會溢出。我們來看看,如果一個數(shù)據(jù)庫一般每秒能接受1000個連接,這個值很高,但你可能會碰到更高的。因為連接請求的隨機到達特性,有時你可能會看到3000個連接并發(fā)。這種情況下,缺省的back_log(50)僅能支撐17毫秒,主線程在某些地方處理稍有停滯超過17毫秒,則有些SYN包將被丟棄。
我建議將tcp_max_syn_backlog和back_log的值調(diào)整到足夠支撐2秒的連接請求(注:連接請求2秒未超時)。比方說,正常情況下每秒有100個連接,假設(shè)峰值為3倍正常情況,則為300連接/秒,這意味著前面提到的參數(shù)至少需設(shè)到600。(注:300連接/秒 * 2秒 = 600連接/秒)
將參數(shù)設(shè)到支持2秒以上請求的意義不大,因為客戶端在3秒內(nèi)未收到應(yīng)答后將發(fā)出新的連接請求。
另外,如果你每秒創(chuàng)建了1000個MySQL連接,你可能有點過了,畢竟創(chuàng)建和銷毀1000個連接需使用大量的資源。考慮下使用長連接或連接池吧,至少是那種大部分連接是由應(yīng)用創(chuàng)建的情況。
本文出自“IT牛奶”
bitsCN.com聲明:本網(wǎng)頁內(nèi)容旨在傳播知識,若有侵權(quán)等問題請及時與本網(wǎng)聯(lián)系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com