Mysql超時配置項的深入理解
1 JDDB超時
JDBC 是 Java 應(yīng)用程序中用于訪問數(shù)據(jù)庫的一套標準 API
類型4驅(qū)動是通過socket來處理字節(jié)流的。如果socket超時設(shè)置不合適,類型4驅(qū)動也可能有同樣的錯誤(連接被阻塞)。
1.2 JDBC超時層次
應(yīng)用程序WAS與數(shù)據(jù)庫間的超時的層次
更上層的超時依賴于下層的超時,只有當(dāng)較低層的超時機制正常工作,上層的超時才會正常。
1.2.1 事務(wù)超時
事務(wù)超時是在框架(Spring、EJB容器)或應(yīng)用程序?qū)用嫔喜庞行У某瑫r。 在 Spring 中,事務(wù)超時可以 XML文件配置或在 Java 代碼中用 Transactional 注解來配置。
Spring 中數(shù)據(jù)庫連接被保存在線程本地變量(ThreadLocal)中,這被稱作事務(wù)同步(Transaction Synchronization)。當(dāng)數(shù)據(jù)庫連接被保存到 ThreadLocal 時,同時會記錄事務(wù)的開始時間和超時時間。所以通過數(shù)據(jù)庫連接的代理創(chuàng)建的 Statement 在執(zhí)行時就會校驗這個時間。
1.2.2 Statement 超時
Statement 超時是用來限制 Statement 的執(zhí)行時間的,它的具體值是通過 JDBC API 來設(shè)置的。JDBC 驅(qū)動程序基于這個值進行 Statement 執(zhí)行時的超時處理。Statement 超時是通過 JDBC API 中java.sql.Statement
類的 setQueryTimeout(int timeout)
方法配置的。不過現(xiàn)在更多是通過框架來進行設(shè)置。
以 iBatis 為例,可以通過 SqlMapConfig.xml
中的 settings
屬性defaultStatementTimeout
來設(shè)置全局的statement超時
缺省值。
也可以通過在具體的 sql 映射文件中的 select insert update
標簽的 timeout
屬性來覆蓋。
JDBC的statement timeout處理過程
每個數(shù)據(jù)庫和驅(qū)動程序的Statement超時的處理也是不同的。MySQL (5.0.8) 中的 Statement 超時處理如下:
調(diào)用 Connection 的 createStatement() 方法創(chuàng)建一個 Statement 對象
調(diào)用 Statement 的 executeQuery() 方法
Statement 通過內(nèi)部的 Connection 將查詢命令傳輸?shù)?MySqlServer 數(shù)據(jù)庫
Statement 創(chuàng)建一個新的超時執(zhí)行線程(timeout-execution)來處理超時
5.1以上版本改為每個連接分配一個線程
向timeout-execution 線程注冊當(dāng)前的 Statement
發(fā)生超時
timeout-execution 線程創(chuàng)建一個相同配置的 Connection
用新創(chuàng)建的 Connection 發(fā)送取消查詢的命令
1.2.3 JDBC的socket timeout
Socket超時可以通過 JDBC 驅(qū)動程序配置。通過設(shè)置 Socket 超時,可以防止出現(xiàn)網(wǎng)絡(luò)錯誤時一直等待的情況并縮短故障時間。 Socket 超時的值必須要高于 Statement 的超時時間,否則Socket超時將會先生效。
Socket 連接時的超時:通過 Socket 對象的
connect(SocketAddress endpoint, int timeout)
方法來配置Socket 讀寫時的超時:通過 Socket 對象的
setSoTimeout(int timeout)
方法來配置
MySQL驅(qū)動的socket timeout配置方式
- 連接超時配置 :connectTimeout(默認值:0,單位:ms)
- Socket超時配置: socketTimeout(默認值:0,單位:ms)
示例: jdbc:mysql://xxx.xx.xxx.xxx:3306/database?connectTimeout=60000&socketTimeout=60000
也可以通過屬性進行配置,而無需直接使用 DBCP 的 API 。
1.2.4 操作系統(tǒng)Socket超時
操作系統(tǒng)同樣能夠?qū)ocket timeout進行配置。 通常,應(yīng)用會在調(diào)用Socket.read()時由于網(wǎng)絡(luò)問題被阻塞住,而很少在調(diào)用Socket.write()時進入waiting狀態(tài)。如果系統(tǒng)內(nèi)核緩沖區(qū)由于某種網(wǎng)絡(luò)錯誤而滿了的話,Socket.write()也會進入waiting狀態(tài)。這種情況下,操作系統(tǒng)會嘗試重新發(fā)包,當(dāng)達到重試的時間限制時,將產(chǎn)生系統(tǒng)錯誤。
2 Mysql服務(wù)器超時配置
mysql> show variables like '%timeout%'; +-----------------------------+----------+ | Variable_name | Value | +-----------------------------+----------+ | connect_timeout | 10 | | delayed_insert_timeout | 300 | | innodb_flush_log_at_timeout | 1 | | innodb_lock_wait_timeout | 50 | | innodb_rollback_on_timeout | OFF | | interactive_timeout | 28800 | | lock_wait_timeout | 31536000 | | net_read_timeout | 30 | | net_write_timeout | 60 | | rpl_stop_slave_timeout | 31536000 | | slave_net_timeout | 3600 | | wait_timeout | 28800 | +-----------------------------+----------+
2.1 connect_timeout
connect_timeout指的是連接過程中握手的超時時間,在5.0.52以后默認為10秒,之前版本默認是5秒。官方文檔是這樣說的:
connect_timeout: The number of seconds that the mysqld server waits for a connect packet before responding with Bad handshake. The default value is 10 seconds as of MySQL 5.0.52 and 5 seconds before that
connect timeout就是tcp連接超時 其中又分兩種,一種是超過了自己設(shè)置的連接超時時間 一種是tcp層面連接sync包報文達到了重試次數(shù)報的超時, 兩種超時錯誤提示信息是不一樣的。
2.2 interactive_timeout & wait_timeout
wait_timeout和interactive_timeout都是指不活躍的連接超時時間,連接線程啟動的時候wait_timeout會根據(jù)是交互模式還是非交互模式被設(shè)置為這兩個值中的一個。 如果我們運行mysql -uroot -p
命令登陸到mysql,wait_timeout
就會被設(shè)置為interactive_timeout的值
2.3 net_read_timeout & net_write_timeout
net_read_timeout和net_write_timeout這個參數(shù)只對TCP/IP鏈接有效,分別是數(shù)據(jù)庫等待接收客戶端發(fā)送網(wǎng)絡(luò)包和發(fā)送網(wǎng)絡(luò)包給客戶端的超時時間
The number of seconds to wait for more data from a connection before aborting the read. When the server is reading from the client, net_read_timeout is the timeout value controlling when to abort. When the server is writing to the client, net_write_timeout is the timeout value controlling when to abort
這兩個參數(shù)控制由于網(wǎng)絡(luò)原因造成的異常超時。比如server在從client端讀取大量的數(shù)據(jù),讀著讀著突然發(fā)現(xiàn)讀不到了,也沒有遇到結(jié)束標識符,這種情況下,server在等待net_read_timeout秒還沒讀到后續(xù)數(shù)據(jù),就斷開連接;或者當(dāng)server select出了大量數(shù)據(jù)發(fā)向客戶端,發(fā)著發(fā)著,突然發(fā)現(xiàn)發(fā)不動了,客戶端不接收了,而數(shù)據(jù)還沒有發(fā)送完,這時server在等待net_write_timeout秒后就斷開連接。
是mysql應(yīng)用層的協(xié)議,而tcp的寫超時只有在丟包次數(shù)過多才會。
3 Mysql客戶端
示例
jdbc:mysql://192.168.1.8:3306/mytest?serverTimezone=GMT%2B8&autoReconnect=true&allowMultiQueries=true&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&connectTimeout=60000&socketTimeout=60000
connectTimeout
建立鏈接需要的時間。該參數(shù)只在建立鏈接階段生效。默認是0,不超時。建議配置connectTimeout=60000,單位毫秒。
socketTimeout
發(fā)送請求給數(shù)據(jù)庫(建立鏈接后),數(shù)據(jù)庫處理的最大時間;默認是0,不超時。建議配置socketTimeout=60000,單位毫秒。
超過這個客戶端報超時超時異常Caused by: java.net.SocketTimeoutException: Read timed out
。
autoReconnect
是否自動重連。默認false。mysql服務(wù)端參數(shù)wait_timeout,其默認值為 28800秒(8小時),其意義為如果一個連接閑置超過這個選項所設(shè)置的秒數(shù),MySQL會主動斷開這個連接。如果無法保證應(yīng)用程序在設(shè)定的秒數(shù)內(nèi)至少有一次操作,添加autoReconnect=true這個參數(shù),即能解決這個問題。
maxReconnects
autoReconnect設(shè)置為true時,重試連接的次數(shù),默認3。
initialTimeout
autoReconnect設(shè)置為true時,兩次重連之間的時間間隔,默認2,單位:秒
4 Mysql連接池配置
4.1 Druid連接池配置
DruidDataSource參考配置 github.com/alibaba/dru…
4.1.1 連接池的初始值、最大值、最小值
initialSize: 5 minIdle: 6 maxActive: 10
項目啟動時,會自動初始化initialSize
個連接出來(沒有流量訪問數(shù)據(jù)庫也會創(chuàng)建),這幾個鏈接會一直存在。可以通過數(shù)據(jù)庫命令SHOW PROCESSLIST
查看初始化的鏈接。
4.1.2 獲取連接的等待時間
maxWait: 6000
獲取連接池中的連接時的最大等待時間,單位是毫秒。
如果這個時間內(nèi)未獲得可用鏈接則報錯:nested exception is com.alibaba.druid.pool.GetConnectionTimeoutException: wait millis 6000, active 10, maxActive 10, creating 0
。這個報錯表明獲取鏈接超時了,而且數(shù)據(jù)庫的10個鏈接都被占用,也不能創(chuàng)建新的鏈接了。
4.1.3 回收連接池中的鏈接
timeBetweenEvictionRunsMillis: 2000 minEvictableIdleTimeMillis: 10000
每隔timeBetweenEvictionRunsMillis: 2000ms
對連接池的連接做一次檢查, 如果有連接空閑時間超過minEvictableIdleTimeMillis: 10000ms
就回收該鏈接。
4.1.4 校驗鏈接池中的鏈接是否有效
validationQuery: SELECT 1 testWhileIdle: true testOnBorrow: false testOnReturn: false validationQueryTimeout:10
校驗的方式:使用待校驗的連接在在數(shù)據(jù)庫上執(zhí)行一下校驗的sql,這里使用SELECT 1
,一定要保證改sql是該數(shù)據(jù)能執(zhí)行的,不同的數(shù)據(jù)庫的校驗sql可能不一樣。
校驗的時機: 通常是在連接空閑時校驗(testWhileIdle: true),
也可以在獲取連接時校驗(testOnBorrow: true,這個配置會降低性能),
也可以在歸還連接到連接池時校驗(testOnReturn: true,這個配置會降低性能)。
validationQueryTimeout是檢測連接是否有效的超時時間,單位:秒。
如果validationQuery為null,testOnBorrow、testOnReturn、testWhileIdle都不會起作用。
4.1 HikariCP配置
4.2.1 連接池的最大值、最小值
maximumPoolSize: 池中最大連接數(shù),包括閑置和使用中的連接。默認為 10
。如果 maxPoolSize 小于1,則會被重置。當(dāng) minIdle <=0 被重置為DEFAULT_POOL_SIZE 則為 10;如果 minIdle > 0 則重置為 minIdle 的值。
minimumIdle: 控制連接池空閑連接的最小數(shù)量,當(dāng)連接池空閑連接少于 minimumIdle,而且總共連接數(shù)不大于 maximumPoolSize 時,HikariCP 會盡力補充新的連接。為了性能考慮,不建議設(shè)置此值,而是讓 HikariCP 把連接池當(dāng)做固定大小的處理,默認 minimumIdle 與 maximumPoolSize 一
樣。當(dāng) minIdle < 0 或者 minIdle > maxPoolSize,則被重置為 maxPoolSize,該值默認為 10。
4.2.2 獲取連接的等待時間
connectionTimeout: 等待來自池的連接的最大毫秒數(shù),默認為 30000 ms = 30 s
,允許最小時間是 250 毫秒,如果小于 250 毫秒,則被重置回 30 秒。
4.2.3 超時時間
idleTimeout: 連接允許在池中閑置的最長時間。
如果 idleTimeout + 1 秒 > maxLifetime 且 maxLifetime > 0,則會被重置為 0(代表永遠不會退出);只有當(dāng) minimumIdle 小于 maximumPoolSize 時,這個參數(shù)才生效
,當(dāng)空閑連接數(shù)超過 minimumIdle,而且空閑時間超過 idleTimeout,則會被移除。
這是hikaricp用來判斷是否應(yīng)該從連接池移除空閑連接的一個重要的配置。負責(zé)剔除的也還是HouseKeeper這個定時任務(wù),值為0時,HouseKeeper不會移除空閑連接,直到到達maxLifetime后,才會移除,默認值也就是0。
maxLifetime:
池中連接最長生命周期。默認為 1800000, 30 分鐘
。 Mysql 為了防止空閑連接浪費,占用資源,在超過wait_timeout 時間后,會主動關(guān)閉該連接,清理資源。 但是hikaricp如何知道池子里維護的一把連接,有沒有被mysql回收呢?所以就有了maxLifetime
這個配置,官方也強烈建議必須按需設(shè)置此值!自然這個值也應(yīng)該小于mysql的wait_timeout
。 那hikaricp在空閑連接
超過maxLifetime
,就會從連接池中剔除,防止業(yè)務(wù)進程取到了已關(guān)閉的連接,導(dǎo)致業(yè)務(wù)受損。
keepaliveTime & connectionTestQuery
keepaliveTime類比tcp的keepAlive機制。為了防止獲取到被mysql關(guān)閉的無效連接,導(dǎo)致業(yè)務(wù)出錯的一種兜底掃描方案。
具體過程就是每隔keepaliveTime時間間隔,去和數(shù)據(jù)庫發(fā)送心跳,來探測連接是否有效。如果發(fā)現(xiàn)是無效的,就會及時從連接池中剔除,來保證業(yè)務(wù)進程獲取到的都是有效連接。
如果配置了connectionTestQuery
,如 select 1
, 心跳檢查過程就會調(diào)用connectionTestQuery。
所以如果你配置了connectionTestQuery
但是沒有配置keepaliveTime
,是沒有用的,因為默認是關(guān)閉的。
而connectionTestQuery
配置項,官方建議如果驅(qū)動支持JDBC4,不要設(shè)置此屬性!
因為相比于通過select查詢方式探活,mysql 自帶的ping命令 性能更高(直接在sql server返回結(jié)果,就不會做語法解析,執(zhí)行優(yōu)化,再通過存儲引擎操作)。 而基本上java mysql驅(qū)動包5以上的版本都支持JDBC4。
總結(jié)
到此這篇關(guān)于Mysql超時配置項的文章就介紹到這了,更多相關(guān)Mysql超時配置項內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
使用innodb_force_recovery解決MySQL崩潰無法重啟問題
這篇文章主要介紹了使用innodb_force_recovery解決MySQL崩潰無法重啟問題,這只一個成功案例,并不是萬能的解決方法,需要酌情考慮,需要的朋友可以參考下2015-05-05