當MySQL資料庫遇到Syn Flooding

攜程DBA發表於2019-06-17

Syn攻擊是最常見又最容易被利用的一種攻擊手法,利用TCP協議的缺陷,傳送大量偽造TCP連線請求,常用假冒的IP發來海量的SYN包,被攻擊的伺服器迴應SYN+ACK,因為對方是假冒的IP,永遠收不到包並且不會迴應,導致被攻擊伺服器保持大量SYN_RECV狀態的半連線,並且會重試預設5次迴應握手包,塞滿TCP等待連線佇列,資源耗盡,讓正常的業務請求連線不進來。

Syn攻擊常見於應用伺服器,而資料庫伺服器在內網中,應該很難碰到類似的攻擊,但有時候應用程式如果和資料庫建連姿勢不正確,在資料庫端,也會被認為是Syn攻擊,並拒絕連線建立。

【問題描述】

資料庫突發的拒絕連結,應用報錯,出問題的時間點上,資料庫伺服器的作業系統日誌裡,即/var/log/messages,可看到如下報錯資訊:

kernel: possible SYN flooding on port 3306. Sending cookies.

【問題分析】

出問題的點上,從資料庫的監控指標來看,Threads Connected 這個指標有增長。這個也是很明顯,因為對資料庫來說,Syn Flooding就是應用程式突發的對資料庫發起建連,作業系統處理不過來,所以報Syn Flooding, 從資料庫的效能指標來看,連線數肯定是會有一個突發的增長。應對方案就是需要分析這些突發的增長是怎麼來的,削峰填谷,讓連線更平穩。

【解決方案】

在資料庫服務端,做如下調整:這個調整的意思是說:增加TCP半連線的緩衝,預設值是2048,我們調整到8192,讓系統的抗突發壓力增大一些。Tcp_syn_retires和Tcp_synack_retires預設是5,也就是伺服器端要傳送五次包,才會終止重試,我們把這個引數調整為2. 只重試一次,讓出錯的包儘量提早出錯,以減少快取的連線數。

echo 8192 > /proc/sys/net/ipv4/tcp_max_syn_backlog
echo 2 > /proc/sys/net/ipv4/tcp_syn_retries
echo 2 > /proc/sys/net/ipv4/tcp_synack_retries

這個引數調整,即時生效,無需重啟。當然伺服器重啟後,這些引數也會回退到預設值。經此調整,資料庫端的抗壓能力得到加強,但並沒有完全解決問題。

我們在客戶端也做相應調整:

為減少資料庫的連線數壓力,通常我們建議連線池做如下配置:

testWhileIdle="false"。空閒時不檢測連線串健康
minIdle="0"。連線池裡面空閒連線的最小個數
maxAge="30000"。一個連結超過多少毫秒就可以回收掉。
initialSize="1"。連線池裡面初始連線的最小個數
timeBetweenEvictionRunsMillis="5000"。回收執行緒的執行間隔(毫秒)

對於現在的場景,我們建議調高minIdle這個引數,從0調整到5. 讓連線池平時有5個空閒連線存在,這樣,發起對資料庫請求的時候,會先使用這5個空閒連線。達到削峰填谷的作用。當然,副作用就是資料庫平時的連線數會增長。具體調整到多少合適,需要結合實際的資料庫連線負載情況。對於.NET程式,也有相應的連線池引數可以調整:可以適當修改minPoolSize這個引數,也調整到5.

經此調整,基本上大部分的資料庫Syn Flooding問題都能解決。

當然,這些都是調優的手段,只能是微微的改善系統。提高抗壓能力。最終的分析,還是要看連線壓力從何而來。以及為何需要突發建立大量連線到資料庫。對於此種突發場景,用資料庫是否合適。替代方案是前面用Redis加一層緩衝。避免突發的對資料庫發起建連請求。這個就涉及到應用的改造了。

相關文章