在數據庫postgresql中,一個客戶端到服務器連接實際上是一個tcp socket連接,tcp連接是虛連接,一方非正常退出(如斷電),另一方會繼續維持這個連接。
舉個例子,一個客戶端電腦正常連上服務器后,強行拔掉電源造成人為斷電,重新啟動電腦,再此連上服務器。用SQL語句select * from pg_stat_activily 查看服務器的所有連接,會發現本客戶端的連接除了本次外,斷電前的連接還在。因為服務器根本不知道客戶端的斷電行為,還以為那連接正在空閑狀態。
然而這個死連接不會永遠存在,2個小時后,服務器上的這個連接會自動切掉,因為postgresql支持TCP_KEEPLIVE機制。有三個 系統變量tcp_keepalives_idle,tcp_keepalives_interval ,tcp_keepalives_count 來設 置postgresql如何處理死連接。
對於每個連接,postgresql會對這個連接空閑tcp_keepalives_idle秒后,主動發送tcp_keeplive包給客戶 端,以偵探客戶端是否還活着 ,當發送tcp_keepalives_count個偵探包,每個偵探包在tcp_keepalives_interval 秒內沒有回應,postgresql就認為這個連接是死的。於是切斷這個死連接。
在postgresql, 這三個參數都設為0將使用操作系統的默認值,在linux下,tcp_keepalives_idle一般是2個小時,也就是2個小時后,服務器才可以自動關掉死連接。在實際應運中,可以自行調整以上參數。
然而,單單依靠服務器以此方法來切掉死連接,是永遠不夠。假設有一個連接,在運行以下交互式命令中突然斷電
begin transaction;
lock table xxx in exclusive mode;
-- 突然斷電,這種可能很小,但肯定存在
。。。
commit
由於這個連接還保留着,且這個transaction還沒結束(本來上1秒之內的事務,現在變成至少要2個小時),所以這個表的鎖一直存在着,導致系統的並發性嚴重降低。
所以必需有手工殺掉連接的語句來切掉此連接,以釋放鎖。不幸的是,直到8.3,postgresql還沒有此語句,源代碼是有pg_terminate_query函數,因為有bug, 被屏蔽掉,必須到8.4才有。
所以只能用操作系統的命令殺掉此連接,或者重啟服務器。 在linux下,殺掉此連接的命令是:
kill -s SIGTERM 進程號。
這個內容有點老,但是思想是一一致的,詳細可參見:http://blog.163.com/digoal@126/blog/static/163877040201331041830502/