這個問題之前在項目中就困擾了我很多次鹦马,只不過重新部署就好了而且再也沒有出現(xiàn)過了,所以也就沒注意菱肖。但是今天這個問題一直出現(xiàn)旭从,重新部署運行一會兒就出現(xiàn),運行一會就出現(xiàn)退疫。不知道怎么弄鸽素,沒辦法就硬著頭皮上網(wǎng)搜,花了一天時間付鹿,也算是把這奇葩的BUG解決了舵匾,這里記錄一下解決的幾個過程谁不。
首先講一下場景,項目是一個物聯(lián)網(wǎng)項目刹帕,會有硬件向服務(wù)器上報信息偷溺,硬件數(shù)量多,上傳頻率高挫掏,上來的數(shù)據(jù)需要做處理尉共,在這種高并發(fā)的環(huán)境下,我先是盡可能不去數(shù)據(jù)庫取數(shù)據(jù)袄友,但是無可避免的還是會需要訪問到數(shù)據(jù)庫,退無可退了支竹,只能開始找原因了。
故障的意思很簡單直接柳洋,就是說數(shù)據(jù)庫的連接池空了叹坦,在超時時限內(nèi)沒有獲取到連接,則拋出異常绪囱,于是去數(shù)據(jù)庫查看連接
Mysql -> show full processlist;
通過這句話在MySQL中去獲取所有進程莹捡,看看自己這個項目的進程,確實有很多篮赢,而且在Command這一欄還都是sleep启泣,想來可能跟這個有關(guān)系,于是乎上網(wǎng)搜相關(guān)內(nèi)容寥茫,搜來的大致意思是連接沒有正確關(guān)閉。不過我代碼里面用到的SQL是關(guān)閉了的纱耻,雖然體感是這個問題,但是從這入手應(yīng)該是解決不了問題玖喘。
但是關(guān)于這個sleep的問題蘑志,又引申到了MySQL的wait_timeout和interactive_timeout的這兩個屬性,這兩個都是空閑連接的超時時間费尽,只不過前者是非交互式連接的(通過jdbc連接)羊始,后者是交互式連接的(通過MySQL客戶端連接)。于是嘗試設(shè)置一下wait_timeout的時間柏卤,這里默認設(shè)置的是8h
Mysql -> set global wait_timeout=30;
設(shè)置成30s之后,重新部署勾笆,跑起來之后確實是有效的桥滨,那些sleep的進程都消失了,感覺好像這樣就OK了齐媒,但是接下來又報了另外一個異常喻括,具體異常忘記記錄了,大致意思是連接丟失唬血,上網(wǎng)搜一下發(fā)現(xiàn)時wait_timeout時間設(shè)置太短造成的拷恨。所以感覺修改wait_timeout的時間不是正確的解,于是又重新設(shè)置成了8H挑随,再從別的地方入手兜挨。
這條異常記錄上有提到size是100眯分,于是乎想到提高最大連接量試試(其實這是個很笨的主意,因為100能超弊决,1000估計都一樣超飘诗,時間問題而已)。這就又涉及到了Tomcat-jdbc連接池的配置昆稿,但是之前我試著去配置連接池溉潭,想讓最大連接量能大一些少欺,只不過沒有用馋贤,先貼一下原先的配置,由于是spring-boot項目仿滔,所以配置是寫在properties里面
#連接池最大連接數(shù)
spring.datasource.tomcat.max-active=200
#空閑池中最大連接數(shù)
spring.datasource.tomcat.max-idle=50
#空閑池中最小連接數(shù)
spring.datasource.tomcat.min-idle=10
spring.datasource.tomcat.initial-size=10
本意是想讓連接池的連接數(shù)變成200的犹芹,但是不起作用,stackoverflow上看是說spring-boot的1.4.1版本有一個更改实昨,本來是spring.datasource.max-active=200的盐固,現(xiàn)在得要根據(jù)具體情況來調(diào)整,比如用Tomact就是spring.datasource.tomcat.max-active=200志电。只不過我是1.4.3版本蛔趴,我以為是向上兼容,沒想到居然是向下兼容鱼蝉,改為不帶Tomcat的就可以了箫荡,加上又看了一下連接池的配置,最終連接池的配置版本為
#連接池最大連接數(shù)
spring.datasource.max-active=200
#空閑池中最大連接數(shù)
spring.datasource.max-idle=50
#空閑池中最小連接數(shù)
spring.datasource.min-idle=10
spring.datasource.initial-size=10
#連接在池中空閑最小時間后被清除
spring.datasource.min-evictable-idle-time-millis=60000
#隔多久時間清回收廢棄連接
spring.datasource.time-between-eviction-runs-millis=30000
#每次調(diào)用檢測池里連接的可用性洁奈,假如連接池中的連接被數(shù)據(jù)庫關(guān)閉了绞灼,應(yīng)用通過連接池getConnection時會重新創(chuàng)建
spring.datasource.testOnBorrow=true
spring.datasource.validation-query=SELECT 1
#移除被遺棄的連接
spring.datasource.remove-abandoned=true
#設(shè)置超時時間
spring.datasource.tomcat.remove-abandoned-timeout=60
不得不說低矮,在高并發(fā)的應(yīng)用環(huán)境下,連接池的配置是真的重要喉钢,關(guān)于連接池的配置我感覺可以另開一篇來介紹了。最下面兩個就是確實解決掉這個BUG所需要的配置肠虽,注釋也稍微寫了一下税课,是移除被遺棄的連接,超過60秒就被判斷為遺棄的連接韩玩。這里的遺棄的連接就是在代碼過程中寫的比如沒有及時關(guān)閉的連接之類的糟糕的寫法找颓。其實針對這個問題,體感上來說也確實是這么回事击狮,連接用完之后彪蓬,超過一個設(shè)定的時間就自動刪掉。這點有點像Java線程池框架中的Executors.newCachedThreadPool()膘茎,設(shè)定的是線程存活60秒就自動刪掉酷誓,之前試過在60秒之內(nèi)瘋狂增加線程數(shù),并將線程數(shù)設(shè)定的比較小刮萌,一段時間后就報錯了娘扩,跟今天連接池的這種情況確實是很像壮锻。
大概就是這么個情況,僅僅提供一個結(jié)題思路灰殴,當(dāng)中還有不少繞路掰邢,也怪自己對連接池的配置還并不了解,如果一開始就修改對連接池的配置的話掰伸,也不至于被這個BUG糾纏一整天了。
長路漫漫合搅。歧蕉。