2023年7月20日 星期四

PostgreSQL 錯誤訊息:Connection to client lost

在監控觀察 PostgreSQL 資料庫的 Logs 時,有時候會觀察到錯誤訊息 Connection to client lost ,這時候會有兩個問題,第一個是這錯誤訊息跟誰有關,第二個是這錯誤訊息代表什麼意思。


在一般沒有特定設定時,Logs 裡面只會顯示紀錄時間還有錯誤訊息,除非有明確的 SQL 語法能夠對應,不容易判斷實際上造成此異常的源頭,需要搭配 log_line_prefix 的設定來看。

可以設定如下,加入 PID 與 UserName 來輔助判斷,依實際需求可以再加上 Application Name 和來源 IP 等等。

log_line_prefix = '%t %p %u'


接下來討論這個錯誤訊息代表什麼意思,這訊息告訴我們,資料庫想要嘗試將 SQL 執行結果回傳給 Client ,但卻發現找不到 Client 。

看到此訊息一般最有可能的原因是 Client 端沒有做 Tcp Keep Alive 的設定,執行長 SQL 在等待資料庫執行完成前,會有一段時間資料庫與AP沒有做任何封包的溝通,在這段期間在中間網路層可能會判斷認為這連線死掉了,就把連線砍掉了,導致 AP 認為資料庫一直沒有回應,而資料庫要回應的時候找不到人。

在資料庫端主要是以下三個參數來控制

tcp_keepalives_interval

tcp_keepalives_idle

tcp_keepalives_count


預設沒有調整的時候會依照 OS 的設定值如下:

[root@EDB-Primary ~]# cat /proc/sys/net/ipv4/tcp_keepalive_intvl

75

[root@EDB-Primary ~]# cat /proc/sys/net/ipv4/tcp_keepalive_probes

9

[root@EDB-Primary ~]# cat /proc/sys/net/ipv4/tcp_keepalive_time

7200

以預設的設定來說,若 7200 秒內沒有任何封包溝通,資料庫會主動向 AP 進行 Tcp 的 Keepalive 確認,若確認失敗,則會依據設定 tcp_keepalive_probes 檢查 9 次,每次檢查間隔 75 秒,若 9 次檢查都沒有回應,則判斷 Clinet 連線中斷。

一般來說,通常遇到這類錯誤訊息基本上都不會等到那麼久,通常可能十幾分鐘就發現了,所以基本上與資料庫端的 Tcp Keepalive 設定無關,可能會是網路層 或 AP 的主機不確定是否有什麼設定。

理想的解法會是 AP 端自己做 Tcp Keepalive 的設定確認,可以的一個偷吃步方法是在資料庫端設定把 tcp_keepalives_idle 的時間設定很短,例如一分鐘檢查一次,這樣資料庫就會主動向 AP 端做 TCP Keep Alive 確認,就可以確保連線活著。