日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

Java线上问题排障:Linux内核bug引发JVM死锁导致线程假死

發(fā)布時間:2023/11/27 生活经验 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java线上问题排障:Linux内核bug引发JVM死锁导致线程假死 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

?Java本質(zhì)上還是離不開操作系統(tǒng),一來Java源碼是用C/C++實現(xiàn)的,二來java進程還是需要依附于操作系統(tǒng)和硬件資源,有時候一些問題是操作系統(tǒng)級別導(dǎo)致的,下面的整個事件是源自一則真實的線上案例。

?

過程:

JVM死鎖導(dǎo)致線程不可用,然后會瞬間起N個線程,當然起再多也是不可用的,因為需要的對象發(fā)生死鎖,然后耗盡文件句柄導(dǎo)致外部請求也就是TCP連接無法建立產(chǎn)生拒絕服務(wù),看起來就像線程假死了一樣,不過巧合的是jstack之后就會恢復(fù)。

?

問題升級:

futex.c的bug->JVM死鎖->起更多的線程->達到線程上限->新的請求無線程可以使用->拒絕服務(wù)

?

原因:

Linux內(nèi)核某個switch分支缺少memory barrier的正確處理,導(dǎo)致外部應(yīng)用如JVM的lock被錯誤鎖住;一般jstack連后就恢復(fù),當然你線上不能老是這樣是不是,必須徹底解決這個問題。

?

解決辦法:

方法一:上層解決替換中間件類庫 ,比如httpclient的(前提是你是由此觸發(fā)的)。

方法二:下沉解決方案前面已經(jīng)說了給Linux內(nèi)核打patch或者升級內(nèi)核到比較穩(wěn)定的新版本。

?

內(nèi)存屏障(英語:Memory barrier),也稱內(nèi)存柵欄,內(nèi)存柵障,屏障指令等,是一類同步屏障指令,是CPU或編譯器在對內(nèi)存隨機訪問的操作中的一個同步點,使得此點之前的所有讀寫操作都執(zhí)行后才可以開始執(zhí)行此點之后的操作。 大多數(shù)現(xiàn)代計算機為了提高性能而采取亂序執(zhí)行,這使得內(nèi)存屏障成為必須。

關(guān)于內(nèi)存屏障參考:User-space RCU: Memory-barrier menagerie?https://lwn.net/Articles/573436/

?

先看linux-2.6.33.1的代碼\linux-2.6.33.1\linux-2.6.33.1\kernel\futex.c

然后再看Linus的修復(fù)記錄:?

https://github.com/torvalds/linux/commit/76835b0ebf8a7fe85beb03c75121419a7dec52f0

很清楚的看到這個switch被加了default,以前是沒有這個所以導(dǎo)致死鎖的。

/** Take a reference to the resource addressed by a key.* Can be called while holding spinlocks.**/
static void get_futex_key_refs(union futex_key *key)
{if (!key->both.ptr)return;switch (key->both.offset & (FUT_OFF_INODE|FUT_OFF_MMSHARED)) {case FUT_OFF_INODE:ihold(key->shared.inode); /* implies MB (B) */break;case FUT_OFF_MMSHARED:futex_get_mm(key); /* implies MB (B) */break;default:smp_mb(); /* explicit MB (B) */}
}

v3.18版修復(fù)?:?

?

?

futex: Ensure get_futex_key_refs() always implies a barrierCommit b0c29f7 (futexes: Avoid taking the hb->lock if there's
nothing to wake up) changes the futex code to avoid taking a lock when
there are no waiters. This code has been subsequently fixed in commit
11d4616 (futex: revert back to the explicit waiter counting code).
Both the original commit and the fix-up rely on get_futex_key_refs() to
always imply a barrier.However, for private futexes, none of the cases in the switch statement
of get_futex_key_refs() would be hit and the function completes without
a memory barrier as required before checking the "waiters" in
futex_wake() -> hb_waiters_pending(). The consequence is a race with a
thread waiting on a futex on another CPU, allowing the waker thread to
read "waiters == 0" while the waiter thread to have read "futex_val ==
locked" (in kernel).Without this fix, the problem (user space deadlocks) can be seen with
Android bionic's mutex implementation on an arm64 multi-cluster system.Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
Reported-by: Matteo Franchin <Matteo.Franchin@arm.com>
Fixes: b0c29f7 (futexes: Avoid taking the hb->lock if there's nothing to wake up)
Acked-by: Davidlohr Bueso <dave@stgolabs.net>
Tested-by: Mike Galbraith <umgwanakikbuti@gmail.com>
Cc: <stable@vger.kernel.org>
Cc: Darren Hart <dvhart@linux.intel.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

futex:確保get_futex_key_refs()始終隱含屏障

提交b0c29f7(futexes:如果有的話,避免使用hb-> lock沒有什么可以喚醒的)

更改futex代碼以避免在什么時候鎖定沒有waiter。

此代碼隨后在提交中得到修復(fù)11d4616(futex:恢復(fù)顯式waiter計數(shù)代碼)。
原始提交和修復(fù)都依賴于get_futex_key_refs()總是意味著一個障礙。

但是,對于私有futexes,switch語句中沒有任何一種情況
將觸發(fā)get_futex_key_refs()并且函數(shù)完成
檢查“waiter”之前需要的內(nèi)存屏障futex_wake() - > hb_waiters_pending()。

結(jié)果是一場比賽,線程在另一個CPU上的futex上等待,允許waker線程讀取“waiters == 0”,而waiter線程讀取“futex_val ==鎖定“(在內(nèi)核中)。

如果沒有此修復(fù)程序,可以看到問題(用戶空間死鎖)在arm64多集群系統(tǒng)上實現(xiàn)Android bionic的互斥鎖。

?

下面是這個問題最初的發(fā)現(xiàn)和修復(fù)的討論,是ARM公司的人員發(fā)現(xiàn)的。

?https://lore.kernel.org/patchwork/patch/508701/

?參考知乎上關(guān)于這個問題的討論,類似的情況:

https://www.zhihu.com/search?type=content&q=jvm%E5%81%87%E6%AD%BB

?

https://ma.ttias.be/linux-futex_wait-bug/

?

想自己看看內(nèi)核源碼可以去:

https://mirrors.edge.kernel.org/pub/linux/kernel/

http://mirrors.163.com/kernel/linux/kernel/

?

?

總結(jié)

以上是生活随笔為你收集整理的Java线上问题排障:Linux内核bug引发JVM死锁导致线程假死的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。