腾讯王卡运营坑之一:web容器优雅停机缓慢
什么叫做優雅停機:
通俗點理解(以tomcat為例),優雅停機就是當tomcat收到停機命令時,tomcat會關閉所有入口(表明我已經要停機了,你們別再來請求我了),同時對已經接受的請求繼續完成相應的處理邏輯。當所有的用戶定義的線程都處理完成,進程內只剩下daemon線程時,機徹底關機,殺死進程。
優雅停機的正確姿勢:
ps -ef|grep java 找到你需要殺死的pid
?
假如我們要殺死的進程pid為254569,則執行 kill??254569即可。切記千萬不能如此操作 kill -9? 254569,如此操作后進程馬上殺死,同時會造成已經接收的請求不會繼續處理,從而造成一些不必要的邏輯錯誤。
問題回顧
在系統邏輯實現時,為了提高系統吞吐量,程序猿們往往會使用一些多線程技術,來處理一些延時高的、強依賴資源的一些請求(消耗資源比較高的通常是DBio,網絡io,文件讀寫io)。但是在使用時經常忽略了線程的關閉問題,下面就是騰訊王卡在運營過程中發現的問題。
在本地項目停止過程中發現,tomcat在停止時很耗時,甚至停止過程中直接拋出異常,這個現象引起了大家的注意。
我們是這樣定位的:
第一:停止tomcat
第二:使用jstack命令查看停機后,還有那些線程在運行
第三:分析打印出來的堆棧信息
在分析jstack打印出來的堆棧信息時,找出和項目相關代碼,查看可疑點。
問題分析:
該代碼是向線程池提交執行一個邏輯,該邏輯是一個死循環
改進后的代碼如:
改進后的方法,沒使用線程池提交,直接new一下thread執行即可。那問題來了,那線程池和直接new一個thread執行相同的方法,為啥線程池就不可以,new 一個thread就可以呢?
帶著問題,我們分別查看線程的shutdown方法和線程的interrupt。相關代碼截圖如下
我們先分析一下線程池的shutdown方法。
checkShutdownAccess檢查操作權限
advanceRunState關閉線程池
interruptIdleWorkers中斷空閑線程
onShutdown取消一些延遲任務
大家請注意interruptIdleWorkers的作用中斷空閑線程,而我們的方法是一個死循環,自然不能中斷
線程池里面有個方法叫shutdownNow,里面有個方法interruptWorkers,該方法是強制關閉所有線程,不論是空閑還是繁忙。到此我們了解了線程池為什么清理死循環的線程了。
而直接new一個thread之所以可以中斷一個死循環的線程,是因為interrupt0這個方法的存在,該方法作用是給線程打個標記(Just to set the interrupt flag),告訴操作系統,該線程可以終止,操作系統會自動中斷被標記中斷的線程。
問題解方案
最后建議大家,如果確實有業務需要寫一個死循環,不中斷的處理一些業務,我們建議使用如下兩種寫法
寫法一:
該方法在bean被銷毀時,start標志會置為false,從而退出死循環
寫法二:
使用interrupted()方法,根據線程的中斷狀態來退出循環
總而言之,言而總之:線程池不能用于處理死循環邏輯。
?
如分析有誤,歡迎大家拍磚
?作者也玩公眾號,歡迎關注《JAVA之庖丁解牛》
?
?
總結
以上是生活随笔為你收集整理的腾讯王卡运营坑之一:web容器优雅停机缓慢的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 爬虫获取微博首页热搜
- 下一篇: SAP 自动记账 零星记录