SpringBoot Admin2.0 集成Arthas的實現(xiàn)步驟
項目最初使用 Arthas 主要有兩個目的:
- 通過 arthas 解決實現(xiàn)測試環(huán)境、性能測試環(huán)境以及生產(chǎn)環(huán)境性能問題分析工具的問題。
- 通過使用 jad、mc、redefine 功能組合實現(xiàn)生產(chǎn)環(huán)境部分節(jié)點代碼熱更新的能力。
技術(shù)選型相關(guān)
因為公司還未能建立起較為統(tǒng)一的生產(chǎn)微服務(wù)配置以及狀態(tài)管理的能力,各自系統(tǒng)的研發(fā)運維較為獨立?,F(xiàn)在項目使用了 Spring Cloud 以及 Eureka 的框架結(jié)構(gòu),和 SBA 的基礎(chǔ)支撐能力較為匹配,同時,SBA 已經(jīng)可以提供服務(wù)感知,日志級別配置管理,以及基于 actuator 的 JVM、Spring 容器的眾多管理插件,可以滿足基礎(chǔ)使用的需求。
在調(diào)研期間,Arthas 整體版本為 3.4.5,提供了基于 Webconsole 的 Tunner Server 模式,通過前面鏈接文章已經(jīng)實踐,與SBA已經(jīng)可以實現(xiàn)集成。因為項目本身沒有歷史包袱,在實際集成的過程中采用了 SBA 2.0 版本以提供更多的管理功能和圖形界面能力。其他優(yōu)點:
- web console 界面嵌入 SBA 整體密碼登錄和網(wǎng)頁權(quán)限管理,實現(xiàn)登陸 SBA 后才可以使用相關(guān) arthas web console 的功能。
- 基于SBA 客戶端依賴的 jolokia-core 開放目標服務(wù)進程的 jmx 管理,通過實現(xiàn) jmx 接口復(fù)用 SBA 的相關(guān)操作界面,減少前端界面開發(fā)能力的要求。
整體結(jié)構(gòu)

幾個關(guān)鍵點,使用 JVM 內(nèi)置 Arthas Spring Boot 插件,參考工商銀行的模式建立完善的客戶端下載以及修改腳本實現(xiàn)遠程控制。內(nèi)置方案工作開發(fā)量小,只需要集成相關(guān)的開源組件即可實現(xiàn)相關(guān)的遠程使用的模式并兼顧安全。工銀的方案大而全適合整體架構(gòu)規(guī)劃后配置專有研發(fā)團隊之城。內(nèi)置方案同時包含通過 JMX 的啟停操作(基于 3.4.5 的 Spring Boot 插件無法獲得相關(guān)句柄,暫時無法實現(xiàn)),默認不啟動。通過遠程 JMX 開通后,JVM 新增相關(guān)線程 8 個,新增虛擬機內(nèi)存 30MB 左右,和本文參考的 SBA1.0 方案相同,需要考慮在線開啟前 JVM 內(nèi)存是否可以支持。
實現(xiàn)效果
SBA 2.0 最大的方便就是提供了配置化鏈接外部網(wǎng)頁的能力,同時如果網(wǎng)頁實現(xiàn)在當前 JVM 進程,可以實現(xiàn) Spring-Security 的本地權(quán)限管理,在生產(chǎn)環(huán)境下只有在登錄 SBA 后才能使用相關(guān)集成的 arthas 功能。
- 登錄界面

- 外嵌連接位置

- JMX 的使用


- 跳轉(zhuǎn) arthas web console

改造方案
1. 整體工程結(jié)構(gòu)

整體工程修改自 SBA 開源項目的 example 工程,具體使用 custom-ui 的工程鏈接為:[spring-boot-admin-sample-custom-ui]_,_紅色框的部分是 arthas web console 的全部靜態(tài)文件,通過 Maven Resource 的指定配置打入指定目錄,實現(xiàn) SBA 啟動時的自定義加載。maven resource 配置--下:
<resource>
<directory>static</directory>
<targetPath>${project.build.directory}/classes/META-INF/spring-boot-admin-server-ui/extensions/arthas
</targetPath>
<filtering>false</filtering>
</resource>
2. 外部鏈接配置
SBA 2.0 開始已經(jīng)使用 vue 全家桶了,擴展集成均比較方便。其中,官方文檔給出了外嵌連接的配置方式:[Linking / Embedding External Pages]。
參考 sba example 工程的 application.yml 配置即可:
# tag::customization-external-views[]
spring:
boot:
admin:
ui:
external-views:
- label: "Arthas Console"
url: http://21.129.49.153:8080/
order: 1900
# end::customization-external-views[]
3. 對應(yīng) Spring MVC controller 實現(xiàn)
參考引用原實現(xiàn)的 SBA 集成部分,該部分主要修改實現(xiàn)如下功能:
- 實現(xiàn) tunnel server 已經(jīng)加載實例列表的刷新并展示到前段 AgentID 框供選擇點擊鏈接。
- 實現(xiàn)自定義 IP 地址的刷新(解決生產(chǎn)環(huán)境雙生產(chǎn) IP 和運維段 IP 不一致的問題)。
4. Arthas Spring Boot 插件修改和配置
參考引用原實現(xiàn)的 SBA 集成中插件修改以及客戶端配置 application.yml。
對原版 Spring boot 插件修改主要在于原有插件是通過 Spring的@ConditionalOnMissingBean 實現(xiàn)自動加載。
修改主要是通過修改這部分實現(xiàn)通過配置文件默認不啟動,然后使用時通過遠程啟動相關(guān) agent 線程。
5. 基于 Spring Actuator 的 JMX 實現(xiàn)
SBA client 在 maven 引入中會默認引入 jolokia-core.jar,如果沒有因為 SBA client 依賴可以自行引入該包,可以實現(xiàn)通過 actuator 開放基于 http 的 jmx 操作能力和 SBA 控制臺的相關(guān)功能無縫配合。
application.yml 中開放 management 相關(guān)配置,根據(jù)自身環(huán)境情況,也可以開在客戶端側(cè)開啟 Spring security 認證,SBA 也可以很好的支持通過服務(wù)發(fā)現(xiàn)實現(xiàn)密碼保護 actuator 端點的訪問。
#放開management
management:
endpoints:
web:
exposure:
# 這里用* 代表暴露所有端點只是為了觀察效果,實際中按照需進行端點暴露
include: "*"
exclude: env
endpoint:
health:
# 詳細信息顯示給所有用戶。
show-details: ALWAYS
health:
status:
http-mapping:
# 自定義健康檢查返回狀態(tài)碼對應(yīng)的 http 狀態(tài)碼
FATAL: 503
JMX 實現(xiàn)參考原文中 EnvironmentChangeListener 的實現(xiàn)思路,基于 Spring 的 JMX 注解實現(xiàn)即可。
@Component
@ManagedResource(objectName = "com.ArthasAgentManageMbean:name=ArthasMbean", description = "Arthas遠程管理Mbean")
public class ArthasMbeanImpl {
@Autowired
private Map<String, String> arthasConfigMap;
@Autowired
private ArthasProperties arthasProperties;
@Autowired
private ApplicationContext applicationContext;
/**
* 初始化
*
* @return
*/
private ArthasAgent arthasAgentInit() {
arthasConfigMap = StringUtils.removeDashKey(arthasConfigMap);
// 給配置全加上前綴
Map<String, String> mapWithPrefix = new HashMap<String, String>(arthasConfigMap.size());
for (Map.Entry<String, String> entry : arthasConfigMap.entrySet()) {
mapWithPrefix.put("arthas." + entry.getKey(), entry.getValue());
}
final ArthasAgent arthasAgent = new ArthasAgent(mapWithPrefix, arthasProperties.getHome(),
arthasProperties.isSlientInit(), null);
arthasAgent.init();
return arthasAgent;
}
@ManagedOperation(description = "獲取配置Arthas Tunnel Server地址")
public String getArthasTunnelServerUrl() {
return arthasProperties.getTunnelServer();
}
@ManagedOperation(description = "設(shè)置Arthas Tunnel Server地址,重新attach后生效")
@ManagedOperationParameter(name = "tunnelServer", description = "example:ws://127.0.0.1:7777/ws")
public Boolean setArthasTunnelServerUrl(String tunnelServer) {
if (tunnelServer == null || tunnelServer.trim().equals("") || tunnelServer.indexOf("ws://") < 0) {
return false;
}
arthasProperties.setTunnelServer(tunnelServer);
return true;
}
@ManagedOperation(description = "獲取AgentID")
public String getAgentId() {
return arthasProperties.getAgentId();
}
@ManagedOperation(description = "獲取應(yīng)用名稱")
public String getAppName() {
return arthasProperties.getAppName();
}
@ManagedOperation(description = "獲取ArthasConfigMap")
public HashMap<String, String> getArthasConfigMap() {
return (HashMap) arthasConfigMap;
}
@ManagedOperation(description = "返回是否已經(jīng)加載Arthas agent")
public Boolean isArthasAttched() {
DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) applicationContext.getAutowireCapableBeanFactory();
String bean = "arthasAgent";
if (defaultListableBeanFactory.containsBean(bean)) {
return true;
}
return false;
}
@ManagedOperation(description = "啟動Arthas agent")
public Boolean startArthasAgent() {
DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) applicationContext.getAutowireCapableBeanFactory();
String bean = "arthasAgent";
if (defaultListableBeanFactory.containsBean(bean)) {
((ArthasAgent) defaultListableBeanFactory.getBean(bean)).init();
return true;
}
defaultListableBeanFactory.registerSingleton(bean, arthasAgentInit());
return true;
}
@ManagedOperation(description = "關(guān)閉Arthas agent,暫未實現(xiàn)")
public Boolean stopArthasAgent() {
// TODO 無法獲取自定義tmp文件夾加載的classLoader,因此無法獲取到com.taobao.arthas.core.server.ArthasBootstrap類并調(diào)用destroy方法
DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) applicationContext.getAutowireCapableBeanFactory();
String bean = "arthasAgent";
if (defaultListableBeanFactory.containsBean(bean)) {
defaultListableBeanFactory.destroySingleton(bean);
return true;
} else {
return false;
}
}
}
實際使用
管理工程投產(chǎn)后,多次在生產(chǎn)環(huán)境用于問題排查和代碼熱修復(fù)。性能問題主要用于性能流控組件以及灰度發(fā)布相關(guān)配置參數(shù)的在線驗證和 debug。
代碼熱加載相關(guān)初期通過 jad+mc 的方式進行操作,后續(xù)發(fā)現(xiàn) jad 在部分代碼上因環(huán)境配置以及 jvm 問題產(chǎn)生反編譯代碼不一致的情況,后續(xù)通過 maven 打包部署應(yīng)用程序 source 壓縮包的方式解決,直接使用和應(yīng)用 jar 同版本構(gòu)建的 source 進行修改更加可靠。整體方案在管理較為嚴格的生產(chǎn)環(huán)境提供了有效的性能分析以及熱修復(fù)的能力。
遺留問題
現(xiàn)有官方提供的 com.taobao.arthas.agent.attach.ArthasAgent 中啟動 arthas agent 的客戶端使用的 arthasClassLoader 和 bootstrapClass 均為方法內(nèi)的臨時變量,外部無法獲取相關(guān)句柄實現(xiàn)通過 bootstrapClass 關(guān)閉 arthas agent 的功能;臨時解決方案為通過 JMX 啟動后,在 web console 連接使用后,使用 stop 命令實現(xiàn)目標進程中 arthas agent 的關(guān)閉。
現(xiàn)有字節(jié)碼加載工具可以很好的實現(xiàn)內(nèi)部類,私有類的在線熱部署替換,同時經(jīng)測試可以兼容 SkyWalk8.x 版本的 javaagent 插件,但是在測試環(huán)境因為配置有 jacoco 覆蓋度采集插件與 Arthas 字節(jié)碼產(chǎn)生了不兼容的情況,在部分環(huán)境使用時需要先關(guān)閉對應(yīng)的 agent 后才能正常使用 arthas 的相關(guān)功能。
歡迎登陸 start.aliyun.com 知行動手實驗室體驗 Arthas 57 個動手實驗:

以上就是SpringBoot Admin2.0 集成Arthas的實現(xiàn)步驟的詳細內(nèi)容,更多關(guān)于SpringBoot Admin2.0 集成Arthas的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
關(guān)于java String中intern的深入講解
這篇文章主要給大家介紹了關(guān)于java String中intern的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家學(xué)習(xí)或者使用java具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-04-04
Spring Boot基于Active MQ實現(xiàn)整合JMS
這篇文章主要介紹了Spring Boot基于Active MQ實現(xiàn)整合JMS,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-07-07
基于Hibernate中配置文件的學(xué)習(xí)(分享)
下面小編就為大家?guī)硪黄贖ibernate中配置文件的學(xué)習(xí)(分享)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-06-06
詳解SpringBoot中異步請求的實現(xiàn)與并行執(zhí)行
這篇文章主要為大家詳細介紹了在SpringBoot中如何是實現(xiàn)異步請求、并行執(zhí)行,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-02-02
淺談利用Spring的AbstractRoutingDataSource解決多數(shù)據(jù)源的問題
本篇文章主要介紹了淺談利用Spring的AbstractRoutingDataSource解決多數(shù)據(jù)源的問題,具有一定的參考價值,有需要的可以了解一下2017-08-08

