2014-07-25 111 views
4

我有一個在EC2上的GlassFish上運行的Java EE應用程序,在Amazon RDS上有一個MySQL數據庫。 我正在嘗試配置JDBC連接池以最大限度地減少數據庫故障轉移時的停機時間。配置GlassFish JDBC連接池以處理Amazon RDS多可用區故障轉移

我的當前配置在多可用區故障轉移期間無法正常工作,因爲備用數據庫實例在幾分鐘內(根據AWS控制檯)可用,而我的GlassFish實例長時間卡住(約15分鐘)才能恢復工作。

連接池配置是這樣的:

asadmin create-jdbc-connection-pool --restype javax.sql.ConnectionPoolDataSource \ 
--datasourceclassname com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource \ 
--isconnectvalidatereq=true --validateatmostonceperiod=60 --validationmethod=auto-commit \ 
--property user=$DBUSER:password=$DBPASS:databaseName=$DBNAME:serverName=$DBHOST:port=$DBPORT \ 
MyPool 

如果我使用一個單AZ db.m1.small實例和重啓從控制檯數據庫,GlassFish的將無效斷開的連接,拋出一些異常,然後在數據庫可用時立即重新連接。在此設置中,我可以獲得不到1分鐘的停機時間。

如果我使用一個多AZ db.m1.small實例,並重啓從AWS控制檯故障,我看不出有什麼異常的。服務器完全停止,所有傳入的請求都會超時。 15分鐘後,我終於得到這個:

Communication failure detected when attempting to perform read query outside of a transaction. Attempting to retry query. Error was: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.3.2.v20111125-r10461): org.eclipse.persistence.exceptions.DatabaseException 
Internal Exception: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure 

The last packet successfully received from the server was 940,715 milliseconds ago. The last packet sent successfully to the server was 935,598 milliseconds ago. 

,就像每個HTTP線程阻塞得到一個無效的連接上沒有得到一個異常,所以沒有機會進行連接驗證時出現。

多可用區域案例中的停機時間總是在15-16分鐘之間,所以它看起來像某種類型的超時,但我無法更改它。

事情我已經嘗試沒有成功:

  • 連接泄漏超時/收回
  • 語句泄漏超時/使用不同的驗證方法
  • 使用MysqlDataSource回收
  • 聲明超時
  • 代替MysqlConnectionPoolDataSource

如何設置停滯查詢的超時時間,以便重新使用,驗證和替換池中的連接? 或者我如何讓GlassFish檢測到數據庫故障轉移?

+0

你能解決這個問題嗎? – hectorg87

+1

@ hectorg87不是。我發現如果我設置更多的HTTP線程,服務器將創建與數據庫的新連接,並在數據庫可用時立即恢復。但是,舊連接仍會阻塞15分鐘,如果數據庫連接池耗盡,此設置將中斷。 – Andrea

+0

該死!我有這樣的假設:它與池本身無關,並與Java的DNS緩存有關。它正在緩存舊數據庫的IP地址,並且在故障轉移完成後從不更改爲新數據庫。只要我禁用Java的DNS緩存,我就會通知你。也許我會回答你的問題:-) – hectorg87

回答

4

正如我以前所說,這是因爲打開並連接到數據庫的套接字沒有意識到連接已經丟失,所以他們保持連接,直到OS套接字超時被觸發,我通常可能讀取在大約30分鐘內。

要解決此問題,您需要在JDBC連接字符串或JDNI連接配置/屬性中重寫套接字超時,以便將參數定義爲更短時間的socketTimeout

請記住,任何長於定義值的連接都將被終止,即使它正在被使用(我還沒有能夠確認這一點,這是我讀的)。

我在評論中提到的另外兩個參數是connectTimeoutautoReconnect

這裏是我的JDBC連接字符串:

jdbc:(...)&connectTimeout=15000&socketTimeout=60000&autoReconnect=true 

我也做禁用Java的DNS緩存

java.security.Security.setProperty("networkaddress.cache.ttl" , "0"); 
java.security.Security.setProperty("networkaddress.cache.negative.ttl" , "0"); 

我這樣做是因爲Java不兌現將TTL的,當故障發生,DNS是相同的,但IP變化。

由於您正在使用Application Server,因此在使用-Dnet啓動glassfish而不是應用程序本身時,必須將用於禁用DNS緩存的參數傳遞給JVM。