問題:最近網站人數一多、MySQL的Connection 會異常變多
解釋:
我是使用一台ASUS TS300 當做伺服器、記憶體4G
作業系統是 Ubuntu 11.04 32bits
上面架設 Apache2.2.17 + php5.3.5 + mysql5.1.54
Apache 使用prefork MPM
[Apache 相關設定]
KeepAlive On
MaxKeepAliveRequests 100
KeepTimeOut 30
[prefork MPM 設定]
ServerLimit 20000
StartServers 10
MinSpareServers 20
ManSpareServer 64
MaxClients 800
MaxRequestsPerChild 20000
[MySQL相關設定]
key_buffer = 64M
read_buffer = 1M
join_buffer = 1M
read_rnd_buffer_size = 2M
myisam_sort_buffer_size = 32M
max_allowed_packet = 32M
thread_stack = 192K
thread_cache_size = 32
myisam-recover = BACKUP
max_connections = 100
wait_timeout = 5
back_log = 100
table_cache = 512
thread_concurrency = 10
query_cache_limit = 2M
query_cache_size = 32M
MySQL在還沒當掉之前的狀態:
Connention Usage => Maximal : 9
Average : 3
Number of SQL Queries => Maximal : 100
Average : 20
此時Google Analystic 同時在線人數測到大約400-800 (之間)
檢查連線數(netstat -na | grep ESTABLISHED | wc -l) 約在400-600之間
此時記憶體大約吃到1.5G-2G
問題發生時的狀態:
伺服器當掉前 Google Analystic 同時在線人數測到大約 1300-1800 (之間)
檢查連線數(netstat -na | grep ESTABLISHED | wc -l) 約在850-1100之間
此時記憶體大約吃到2.6-2.8G
但是重點來了,當人數飆高時,突然之間MySQL的Connection會飆到最大值(看設定多少就飆到多少),原本平均可能才在6、但是就突然飆到100,接著Web就無法瀏覽、必須要重開MySQL才可以。
我有嘗試將Apahce的MaxClient調小,但是瞬間只要太多人瀏覽、就還是有可能出問題。
我的Web型態、主要都只有用到select,唯一一個就是當user讀取某篇文章時,文章閱讀次數會+1,而我是使用update table set count = count + 1 where id = 'xxx',除此之外並沒有任何insert or delete。
請問有人有知道發生這個狀況可能是哪邊導致的原因嗎?
或者可以指引我一些方向,讓我去處理這個問題
之前網站營運都很正常、但是最近瀏覽人數越來越多,有時候晚上熱門時間太多人瀏覽,就開始不穩,很常掛掉
請高手解答>"< 非常感謝
設定建議調整如下:
[Apache 相關設定]
MaxKeepAliveRequests=100 太少,加大到 10000,或乾脆設為 0 (無限),以免一個 request 服務 100 個檔案後就自殺。
KeepTimeOut=30 太長,縮短到 15 秒。一頁裡的檔案,很少會傳超過 15 秒的。
[prefork MPM 設定]
ServerLimit=20000 與 MaxClients=800,這兩者應該相等,否則你的 ServerLimit 佔用 19200 個記憶體空間都是浪費掉的,因為連線數到 800 就上不去了。
[MySQL相關設定]
如果你站台的在線數已經到達 1000,那麼 max_connections = 100 設得太少了,至少也要 500 以上。
wait_timeout = 5 設太小。這樣會造成使用者若超過 5 秒沒動作,再點下一個頁面會重新連 mysql,造成額外開銷。所以估計使用者大約多久會點下一頁,可以設定三分鐘到五分鐘 (180~300)
thread_concurrency = 10,這個值應該是 CPU 核心數 (包含多核心) * 2。所以設成 10 看來是怪怪的。
不過你說的人數瞬間飆高,必須觀察 apache log 是否是同一個 IP 在對同一個頁面密集 request,或者不同 IP 在對特定頁面密集 request。這種 DoS 攻擊,不管你怎麼加大設定也沒用,必須在 apache 加掛像是 mod_limitipconn 或 mod_evasive 等模組來阻擋。
關於ServerLimit跟MaxClient如果要一樣、是不是針對我的記憶體大小去決定比較好?假設1500人時大概佔用3G、那ServerLimit也設為1500就好?
關於MySQL的設定、平常的連線數都在個位數、大不了十位數、我的狀況是當掉之後才飆到100...@@ 所以我在想這邊設大並不是真正的重點
wait_timeout 我當初是想說、當掉的時候是不是有可能某一個環節卡住
所以希望他在五秒過後就斷掉連線、不過這邊我也有設置過幾分鐘到十幾秒
thread_concurrency 我是按照他的預設的值、沒有動過、不過我會照你的方式設定為CPU核心數目*2試試看
關於最後一點、我有檢查過apache log、我有裝mod_evasive、但是還沒研究過你說的mod_limitipconn,我這邊會努力去找一下
關於DoS攻擊、我也有想過、不過我想過如果真的有心人士攻擊、他應該會隨時都有可能攻擊我的網站才對、但是我掛點都只出現在某個特定的行為之後(我是透過粉絲團發文、讓user知道我網站的消息),所以當我粉絲團沒發文時,應該也會遭受到攻擊而當掉,但是卻沒有>"< 所以這邊我有先初步排除 DoS攻擊(還有我可能想說我有裝evasive應該沒事情)
我後來把網站的唯一Update的部分拿掉了(先做測試),就等於我的web純粹只有select,而最複雜的select也只有三個table做left join,我的資料庫大概2000筆資料而已(最多的那個table),拿掉update之後有稍微撐比較久,在想說
是不是有可能瞬間MySQL處理同一筆資料的Update時可能會出問題
(我的粉絲團20萬人、發一個文可能有幾百人同時點近來看,針對同一個文章、又會去做update table set count = count + 1 where id = 'xxx'時,在想說會不會是這個環節出了錯)
今天晚上有好一些,平常應該當個7-8次、到目前為止只當一次
不好意思另外想請問,back_log = 100 這個怎麼設定比較好?
另外超級謝謝你的回覆>"<
我會在努力研究一下你說的每個重點、真的謝謝你