linux内核3.6版本及以下的bug引发的故障--cpu使用率100%
現象:?
? ? ? ? 旗艦店運價庫cpu使用率100%,load升高,導致后續的請求失敗。?
? ? ? ? 重啟服務器,cpu、load恢復正常。
觸發條件:?
? ? ? ?(1)linux內核3.6版本及以下。 (線上機器大部分是2.6.32)
? ? ? ?(2)mysql-connector-java5.1.31版本及以下。(各業務線需要自己check)
? ? ? ?(3)mysql-client沒有設置socketTimeout。 (各業務線需要自己check)
? ? ? ?(4)殺死mysql-server與mysql-client的連接處于mysql-server端的線程。 (dba經常會殺死慢查詢)
? ? ? ? 當(1)(2)(3)同時具備,只要觸發(4),客戶端連接線程就會死循環。殺死一個mysql-server端線程,客戶端就會死循環一個,占用一個cpu內核。
具體原因:
Linux kernels version 3.6 and earlier (including 2.6.32) have a bug [1] which makes requests for the amount of available bytes to read in a socket in CLOSE_WAIT state to return 1 even after the EOF has been read.This bug makes SocketInputStream.available return 1 for sockets in CLOSE_WAIT state and causes a seemly infinite loop in MysqlIO.clearInputStream where it attempts to read from the socket until the number of available bytes reaches 0, but there is nothing to read.
? ? ? ? ?出處: ?https://bugs.mysql.com/bug.php?id=73053
mysql官網5.1.32版本的變更記錄,有提到這個bug:
? ? ? ??A bug in the Linux kernel version 3.6 and earlier caused the?MysqlIO.clearInputStream()?method to enter an endless loop. This fix changes the way the looping condition is evaluated, in order to avoid the problem. (Bug #19022745, Bug #73053)
? ? ? ? 出處:https://dev.mysql.com/doc/relnotes/connector-j/5.1/en/news-5-1-32.html
mysql驅動高版本(已兼容linux低版本內核的bug),附截圖:
? ? ? ?
解決方案:?
? ? ? (1)升級mysql-connector-java版本到5.1.32及以上。 或者
? ? ? (2)升級linux內核版本到3.7及以上。 ? ? ? ? ? ? ? ? ? ? ? ? 或者
? ? ? (3)客戶端設置socket讀超時時間。(殺死server端線程,客戶端線程立馬釋放,沒有到達超時時間。為什么能生效,不是很清楚,有知道的可以回復郵件)?
? ? ? ?推薦使用(1)
查問題的過程:
? ? ? ?1. 重啟機器,cpu使用率恢復正常。 但是保留一臺機器做現場。
? ? ? ?2. 使用jstack命令與top命令分析現場機器,發現執行時間長和cpu使用率高的線程,死循環在MysqlIO.clearInputStream()。
? ? ? ?3. 在網上查閱資料,發現是linux內核3.6版本及以下的bug導致。 但是不知道怎么觸發。
? ? ? ?4. 詢問dba,當時dba在殺死mysql-server端的慢查詢,時間是吻合的。 猜測觸發條件之一是,殺死mysql-server與mysql-client的連接 處于mysql-server端的線程。
復現過程:
? ? ? ?1. 使用內核版本2.6.32的linux部署應用服務,應用服務使用的mysql-connector-java版本為5.1.21, mysql-client沒有設置socketTimeout。 (與線上環境一致)
? ? ? ?2. 更改應用服務里的sql語句,其實是增加了休眠,方便能在mysql-server端查看此線程。 sql語句由select... 變為 select sleep(10) ...
? ? ? ?3. 調用http接口,觸發測試的查詢語句。
? ? ? ?4. 登錄mysql-server,使用命令 show processlist; 查看測試的查詢語句,得到線程id。 kill + 線程id, 殺死正在執行的線程。
? ? ? ?5. 應用服務器,cpu其中1核使用率達到100%, 并且http接口,一直沒有響應返回(應用服務器線程死循環了)。
? ? ? ?6. 重復步驟(3)、(4),每殺死mysql-server端的一個線程,cpu的一個核使用率就會達到100%。
?
? ? ? ?注意:如果應用服務器 打過補丁tcp: fix FIONREAD/SIOCINQ, 無法復現。 ??
幾個實驗:
? ? ? ?1. 升級mysql-connector-java版本到5.1.34,其他條件不變。 殺死mysql-server端的線程,應用服務器cpu沒有變化,mysql-client端線程立馬釋放。
? ? ? ?2. 升級linux內核版本到3.18.48,其他條件不變。 殺死mysql-server端的線程,應用服務器cpu沒有變化,mysql-client端線程立馬釋放。
? ? ? ?3. 設置mysql-client端超時時間2分鐘,其他條件不變。 殺死mysql-server端的線程,應用服務器cpu沒有變化,mysql-client端線程立馬釋放。沒有等到2分鐘超時,mysql-client端線程立馬釋放。
?
當時分析問題的線程棧信息如下:?
java.lang.Thread.State: RUNNABLE? ? ? at?java.net.PlainSocketImpl.socketAvailable(Native Method)
? ? ? at?java.net.AbstractPlainSocketImpl.available(
? ? ? AbstractPlainSocketImpl.java:478)
? ? ? - locked <0x000000070ed04a40> (a?java.net.SocksSocketImpl)
? ? ? at?java.net.SocketInputStream.available(SocketInputStream.java:245)
? ? ? at com.mysql.jdbc.util.ReadAheadInputStream.fill(ReadAheadInputStream.java:72)
? ? ? at com.mysql.jdbc.util.ReadAheadInputStream.skip(ReadAheadInputStream.java:300)
? ? ? at com.mysql.jdbc.MysqlIO.clearInputStream(MysqlIO.java:948)
? ? ? at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2404)
? ? ? at com.mysql.jdbc.ConnectionImpl.pingInternal(Unknown Source)
? ? ? at com.mysql.jdbc.ConnectionImpl.execSQL(Unknown Source)
? ? ? - locked <0x000000070ed04c10> (a com.mysql.jdbc.JDBC4Connection) ?
? ? ?at com.mysql.jdbc.ConnectionImpl.execSQL(Unknown Source)
? ? ?at com.mysql.jdbc.StatementImpl.execute(Unknown Source)
? ? ?- locked <0x000000070ed04c10> (a com.mysql.jdbc.JDBC4Connection)
? ? ?at com.mysql.jdbc.StatementImpl.execute(Unknown Source)
?
轉載于:https://www.cnblogs.com/DengGao/p/linx_cernel_bug.html
總結
以上是生活随笔為你收集整理的linux内核3.6版本及以下的bug引发的故障--cpu使用率100%的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: DCDC纹波小实验
- 下一篇: 常用 Http 的请求方法