close connection error java.sql.SQLRecoverableException: IO Error: Broken pipe


 java.sql.SQLRecoverableException: IO Error: Broken pipe

1 錯誤信息

ERROR [com.alibaba.druid.util.JdbcUtils] - close connection error
java.sql.SQLRecoverableException: IO Error: Broken pipe

2 分析

遇到這個問題,一般是程序訪問服務(比如數據庫)時遇到的。這之間存在着好幾個網絡 通信節點:

程序 –> 連接池 –> 網卡 –> 防火牆 –> 路由器 –> 防火牆 —> 服務端網卡 —> 服務端靜態路由 –> 服務端防火牆 –> 服務監聽 –> 服務

除了程序與連接池(一般集成在一起),其他任何一個節點中斷連接,都有可能引發這個問 題,尤其是防火牆。而一般將某個連接中斷原因,是因為這個連接空閑了太長的時間(保持 連接卻不做任何事情)。網絡防火牆、tcp網絡、服務器本地防火牆、監聽這幾個節點上都 有空閑連接控制。

下面分別通過配置連接池、服務器上的tcp網絡、數據庫層面、來解決空閑連接被異常中 斷的問題。

2.1 連接池

現在國內大都使用druid 作為程序的連接池。那么該連接池針對空閑連接提供了檢測和 校驗機制。比如在申請使用該連接時,先測試該連接是否可用,定時檢查空閑連接是否 可用等,空閑連接定時執行無意義的SQL以保證會話被驗證為alive,推薦配置如下:

spring.datasource.druid.test-while-idle=true
spring.datasource.druid.validation-query=SELECT 1 FROM DUAL
spring.datasource.druid.validation-query-timeout=1000
sping.datasource.druid.min-Evictable-Idle-Time-Millis=300000
sping.datasource.druid.time-Between-Eviction-Runs-Millis=3000
spring.datasource.druid.keep-alive=true
spring.datasource.druid.remove-abandoned=true
spring.datasource.druid.remove-abandoned-timeout=3600
spring.datasource.druid.log-abandoned=true

一般使用以上配置后,就不會再出現連接中斷的問題。

2.2 TCP網絡

  • keepalive 類Unix系統上,TCP 連接的 keepalive 可以在應用層實現,也可以在 TCP 中提供。 這個問題存在爭議,因此 TCP 連接的保活探測並不是 TCP 規范中的一部分。但為了方便 ,幾乎所有類 Unix 系統均在 TCP 中提供了相應的功能。

    常見類UNIX系統中的tcp keepalive:

    操作系統 保活定時器
    AIX # no -a | grep keep
      tcp_keepcnt = 8
      tcp_keepidle = 14400
      tcp_keepintvl = 150
    Linux # sysctl -A | grep keep
      net.ipv4.tcp_keepalive_intvl = 75
      net.ipv4.tcp_keepalive_probes = 9
      net.ipv4.tcp_keepalive_time = 7200
    FreeBSD #sysctl -A | grep net.inet.tcp
      net.inet.tcp.keepidle=…
      net.inet.tcp.keepintvl=…

    不同系統上的各參數的時間單位不盡相同。在 AIX 上, tcp_keeidle/tcp_keepinit/tcp_keepintvl 的時間單位是 0.5 秒;而在 Linux 上, net.ipv4.tcp_keepalive_intvl 和 net.ipv4.tcp_keepalive_time 的時間單位則為秒。並 且,上述參數僅對運行在其上的服務器應用連接有效。

    note
    在 Solaris 上可通過“ndd /dev/tcp \?”命令顯示上述類似參數信息,而在 HP

    Unix 上則可通過 nettune 或 ndd 命令進行查詢。

    由於所有類 Unix 系統上均支持這種功能,因此,在接下來的部分中我們將基於 AIX 系統 具體講述上述參數的意義和作用機制。

    控制參數 參數說明
    tcp_keepcnt 關閉一個非活躍連接之前進行探測的最大次數,默認為 8 次
    tcp_keepidle 對一個連接進行有效性探測之前運行的最大空閑時長,默認值為 14400(即 2 個小時)
    tcp_keepintvl 兩個探測的時間間隔,默認值為 150 即 75 秒

    我們要通過設置這些參數,使其控制時間間隔要小於防火牆設置的最大空閑時間,如果不了 解防火牆的設置,可以將該tcp_keepintvl的值設置為3分鍾以內,一般網絡防火牆對於 空閑會話的限制不會短於這個時間。

  • tcp retries 這里有另外一個現象,當連接被異常中斷,但是程序這端的服務器沒有收到相關終止信息 時,由原來存在的會話繼續發送報文時,不會得到反饋,超過一定時間后,TCP會重新發 送該報文,直到超過最大允許重發次數。所以,有些時間,程序收到broken pipe 信息 時,是在一段時間以后(常見的是15分鍾)。而在測試、開發人員的眼中,就是業務從開 始執行到報錯, 中間等待了很久,比如15分鍾。這里涉及到Linux內核對tcp 重發報文 次數的控制: net.ipv4.tcp_retries2 ,可以通過文件/proc/sys/net/ipv4/tcp_retries2 進行臨時調整。

    其規則是:配置重傳次數小於9的話,就是指數增長時間,如果大於9的話,就是最大超時時間.

    TCP_RTO_MIN=(HZ/5)=0.2s

    TCP_RTO_MAX=(120HZ)=120s

    linear_backoff_thresh = ilog2(1205)=ilog2(0x258)=9

    timeout:未超過linear_backoff_thresh=9的部分按TCP_RTO_MIN 2的指數倍增長,超過 的部分按TCP_RTO_MAX線性增長

    比如:

    sysctl_tcp_retries2=9,則timeout=1023TCP_RTO_MIN=204.6s sysctl_tcp_retries2=11時,timeout=1023TCP_RTO_MIN+2TCP_RTO_MAX=448.6s

針對這個問題,我們可以將重傳次數設置得小一些。比如設置為3.

2.3 數據庫監聽

數據庫也會把一些長時間沒有任何操作的會話給kill掉,並不會給出任何的反饋。當程序 使用長連接,再次請求這些會話時,就會遇到報錯。從數據庫角度來講,可以把空閑時間 設置得更長一些,但是這樣是存在風險的,日積月累后,數據庫中可能存在大量的空閑連 接,由於數據庫一般會限制最大連接數的。如果大量的空閑連接存在,可能導致新的連接 無法建立。

  • ORACLE oracle中對空閑會話的檢測是在$ORACLE_HOME/network/admin/sqlnet.ora中配置

的,參數是sqlnet.expire_time ,單位是秒。比如:

sqlnet.expire_time=180
  • MySQL 設置wait_timeout 指定空閑時間,單位是秒,最長不建議超過1天。

Author: halberd.lee

Created: 2019-09-26 Thu 21:20

Validate


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM