您好,登錄后才能下訂單哦!
本篇文章給大家分享的是有關Arthas如何實現CPU 排查與代碼熱更新,小編覺得挺實用的,因此分享給大家學習,希望大家閱讀完這篇文章后可以有所收獲,話不多說,跟著小編一起來看看吧。
線上代碼經常會出現 CPU 占用過高的情況,按以往經驗我會使用 top 指令,進一步借助于 jstack 去查看具體信息從而進行問題排查,但基本上都逃不過需要重新發包的局面,及時是一個增量包,應用也需要短暫停啟。后來運維大兄弟讓我試一下 Arthas,說是可以進行代碼的熱更新操作,正好來試一下。
JDK1.8
SPringBoot 2.2.2
Arthas
Linux
測試代碼:
@RequestMapping(value = "/bigThread")@ResponseBodypublic String bigThread(int id) { ArthasService.test();while (true) { Thread t2 = new Thread(); t2.start(); id ++;if(100000 == id) {return String.valueOf(id); } } }
thread -b, 找出當前阻塞其他線程的線程,執行完之后并未發現,說明該線程并非一直阻塞、一直執行的。
在上一步基礎上,我們進一步查看,thread 15(因為上面的 ID=15)。
他的大致意思就是:線程在等待一個條件從而繼續執行,可以看到方法是在執行 LinkedBlockingQueue.take 方法時候,查看這個方法的 API 提示如下:
public E take() throws InterruptedException { E x;int c = -1;final AtomicInteger count = this.count;final ReentrantLock takeLock = this.takeLock; takeLock.lockInterruptibly();try {while (count.get() == 0) { notEmpty.await(); } x = dequeue(); c = count.getAndDecrement();if (c > 1) notEmpty.signal(); } finally { takeLock.unlock(); }if (c == capacity) signalNotFull();return x; }
其中:AtomicInteger 是保證高并發情況下的原子性,ReentrantLock 標識可重入鎖,都是 JUC 包下需要了解的這里不贅述,需要的百度了解下。
這段代碼關鍵點就在于:notEmpty.await(),從隊列中消費數據,當隊列為空是,線程阻塞,所以我們大致知道現在出現的問題是線程阻塞,但是還是不知道具體哪行代碼的問題。
如果能夠明確知道這次更改了哪些代碼,可以直接執行步驟 6,不知道的話可以通過步驟 5 來定位問題。
watch org.springframework.web.servlet.DispatcherServlet getHandler returnObj
這個腳本可以檢測一切通過 DispatcherServlet 匹配 Handler 的方法,也就是進入 Controller 的請求,如下:
找到了對應的代碼之后,我們來進一步觀察異常信息,這里可能會有一個問題:就是我明明能通過日志去查看錯誤信息,為什么還需要這么繁瑣的去操作。我的業務場景是:日志還是非常大的,剛撈到就被刷過去了,這時候定位日志不是很好操作,當然想撈下來日志肯定也是可以的,也很直觀,我一般也都是去查看日志進行問題定位,這里也是提供一個思路。
watch 類全路徑 方法名 "{params[0],throwExp}" -e -x 2
如上,錯誤很直觀的提示了出來,下面就可以修復解決了,這里我們也可以通過 trace 指令,查看執行時長:
trace 類全路徑 方法名 "{params[0],throwExp}" -e -x 2
返回信息如下,也可以看到錯誤信息,和每個方法執行的時長。
[arthas@10999]$ trace com.arthas.controller.OrderController bigThread Press Q or Ctrl+C to abort. Affect(class count: 1 , method count: 1) cost in 53 ms, listenerId: 10 `---ts=2020-08-19 14:45:57;thread_name=http-nio-0.0.0.0-8080-exec-10;id=16;is_daemon=true;priority=5;TCCL=org.springframework.boot.web.embedded.tomcat.TomcatEmbeddedWebappClassLoader@1f1c7bf6 `---[1452.684406ms] com.arthas.controller.OrderController:bigThread() [throws Exception] +---[0.168814ms] com.arthas.service.ArthasService:test() #20`---throw:java.lang.OutOfMemoryError #-2 [unable to create new native thread]
在上面知道問題之后,我們就來定位問題就好了。
命令:jad 類全路徑 方法名
[arthas@13190]$ jad com.arthas.controller.OrderController ClassLoader: +-org.springframework.boot.loader.LaunchedURLClassLoader@17f052a3 +-sun.misc.Launcher$AppClassLoader@3d4eac69 +-sun.misc.Launcher$ExtClassLoader@45f45fa1 Location: file:/opt/software/arthas/Arthas.jar!/BOOT-INF/classes!/ /* * Decompiled with CFR. * * Could not load the following classes: * com.arthas.service.ArthasService * org.springframework.stereotype.Controller * org.springframework.web.bind.annotation.RequestMapping * org.springframework.web.bind.annotation.ResponseBody */package com.arthas.controller;import com.arthas.service.ArthasService;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.ResponseBody;@Controllerpublic class OrderController {@RequestMapping(value={"/bigThread"})@ResponseBodypublic String bigThread(int id) { ArthasService.test();do { Thread t2 = new Thread(); t2.start(); } while (100000 != ++id);return String.valueOf(id); } } Affect(row-cnt:1) cost in 1513 ms.
此時代碼就被反編譯了,為了能夠更改,所以我們需要輸出為 java 文件。
指令:jad com.arthas.controller.OrderController > /tmp/OrderController.java
即:jad 類全路徑 方法名 > 存儲路徑/存儲名稱
然后到 tmp 路徑下 vi 修改 java 文件即可,修改完成之后,查看對應的 classloader 為編譯做準備。
sc -d *OrderController | grep classLoaderHash mc -c 17f052a3 /tmp/OrderController.java -d /tmp
但是這里編譯出錯了,官方提示:
[arthas@13190]$ trace com.arthas.controller.OrderController bigThread Press Q or Ctrl+C to abort. Affect(class count: 1 , method count: 1) cost in 77 ms, listenerId: 2 `---ts=2020-08-19 15:51:46;thread_name=http-nio-0.0.0.0-8080-exec-1;id=d;is_daemon=true;priority=5;TCCL=org.springframework.boot.web.embedded.tomcat.TomcatEmbeddedWebappClassLoader@1f1c7bf6 `---[6734.666529ms] com.arthas.controller.OrderController:bigThread() [throws Exception] +---[0.786517ms] com.arthas.service.ArthasService:test() #20`---throw:java.lang.OutOfMemoryError #-2 [unable to create new native thread]
@RequestMapping(value = "/bigThread")@ResponseBodypublic String bigThread(int id) { ArthasService.test();while (true) { Thread t2 = new Thread(); t2.start(); id ++;if(100000 == id) {return String.valueOf(id); } } }
@RequestMapping(value = "/bigThread")@ResponseBodypublic String bigThread(int id) { ArthasService.test(); Thread t2 = new Thread(); t2.start();return "success"; }
[arthas@13190]$ redefine /tmp/OrderController.classredefine success, size: 1, classes:com.arthas.controller.OrderController
`---ts=2020-08-19 15:52:02;thread_name=http-nio-0.0.0.0-8080-exec-3;id=f;is_daemon=true;priority=5;TCCL=org.springframework.boot.web.embedded.tomcat.TomcatEmbeddedWebappClassLoader@1f1c7bf6 `---[5.609405ms] com.arthas.controller.OrderController:bigThread() `---[0.204675ms] com.arthas.service.ArthasService:test() #20`---ts=2020-08-19 15:52:04;thread_name=http-nio-0.0.0.0-8080-exec-4;id=10;is_daemon=true;priority=5;TCCL=org.springframework.boot.web.embedded.tomcat.TomcatEmbeddedWebappClassLoader@1f1c7bf6 `---[3.900149ms] com.arthas.controller.OrderController:bigThread() `---[0.14636ms] com.arthas.service.ArthasService:test() #20`---ts=2020-08-19 15:52:04;thread_name=http-nio-0.0.0.0-8080-exec-5;id=11;is_daemon=true;priority=5;TCCL=org.springframework.boot.web.embedded.tomcat.TomcatEmbeddedWebappClassLoader@1f1c7bf6 `---[1.90945ms] com.arthas.controller.OrderController:bigThread() `---[0.147353ms] com.arthas.service.ArthasService:test() #20
可以發現時間從 6734.666529ms 變成 3ms 左右,說明熱更新的代碼生效了。
以上就是Arthas如何實現CPU 排查與代碼熱更新,小編相信有部分知識點可能是我們日常工作會見到或用到的。希望你能通過這篇文章學到更多知識。更多詳情敬請關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。