前言
springboot專案部署起來後,如何實時監控專案的執行狀況呢?本文記錄使用springboot-admin對服務進行監控。
springboot-admin介紹:https://codecentric.github.io/spring-boot-admin/current/#_what_is_spring_boot_admin
工程結構
服務端
server服務端
客戶端
client客戶端
服務端、客戶端都是獨立的web專案,服務端是監控程式,客戶端是被監控的程式,本文只測試了一個客戶端接入
程式碼編寫
服務端
server服務端引入相關依賴
2.2.0後admin的管理頁面支援中文,因此我們引入此版本(parent不再是引入我們的父工程pom了,直接引入springboot的2.2.0)
<!-- 引入admin相關依賴 2.2.0頁面支援中文顯示,需要springboot 2.2.0 --> <dependency> <groupId>de.codecentric</groupId> <artifactId>spring-boot-admin-starter-server</artifactId> <version>2.2.0</version> </dependency>
為了安全性,引入security
<!--springboot security 安全相關--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency>
解決控制檯報錯,移除tomcat,改用jetty
<!-- 報錯:java.lang.IllegalStateException: Calling [asyncError()] is not valid for a request with Async state [MUST_DISPATCH] 解決:移除tomcat,換成jetty --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jetty</artifactId> </dependency>
監控系統,直接配置賬號、密碼,不用搞那麼麻煩接入資料庫
#配置一個賬號和密碼 spring.security.user.name=admin spring.security.user.password=123456
做好security配置
/** * Security安全配置 */ @Configuration public class SecuritySecureConfig extends WebSecurityConfigurerAdapter { //專案應用路徑 private final String adminContextPath; public SecuritySecureConfig(AdminServerProperties adminServerProperties) { this.adminContextPath = adminServerProperties.getContextPath(); } @Override protected void configure(HttpSecurity http) throws Exception { SavedRequestAwareAuthenticationSuccessHandler successHandler = new SavedRequestAwareAuthenticationSuccessHandler(); successHandler.setTargetUrlParameter("redirectTo"); successHandler.setDefaultTargetUrl(adminContextPath + "/"); http.authorizeRequests() //無需登入即可訪問 .antMatchers(adminContextPath + "/assets/**").permitAll() .antMatchers(adminContextPath + "/login").permitAll() .anyRequest().authenticated() .and() //登入和登出路徑 .formLogin().loginPage(adminContextPath + "/login").successHandler(successHandler).and() .logout().logoutUrl(adminContextPath + "/logout").and() //開啟http basic支援,admin-client註冊時需要使用 .httpBasic().and() .csrf() //開啟基於cookie的csrf保護 .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()) //忽略這些路徑的csrf保護以便admin-client註冊 .ignoringAntMatchers( adminContextPath + "/instances", adminContextPath + "/actuator/**" ); } }
客戶端是要暴露actuator的web埠的,為了安全,客戶端只允許服務端請求actuator的web介面,為了方便客戶端區分請求來源,我們在請求頭注入自定義引數
/** * 注入額外的請求頭,方便客戶端區分請求來源 */ @Component public class HttpHeadersProviderConfig implements HttpHeadersProvider { @Value("${server.port}") private String port; @Override public HttpHeaders getHeaders(Instance instance) { HttpHeaders httpHeaders = new HttpHeaders(); //設定約定好的請求頭引數 httpHeaders.add("spring-boot-admin-service", port); return httpHeaders; } }
我們不可能整天上系統看監控資料,做好自定義通知,當例項狀態發生改變,及時通知(發郵件、企業微信、釘釘都可以,自己實現)
/** * 自定義通知 * 繼承 AbstractStatusChangeNotifier 類,實現了 doNotify 方法, * 當應用狀態改變的時候會回撥 doNotify 方法。 */ @Component public class CustomNotifierConfig extends AbstractStatusChangeNotifier { public CustomNotifierConfig(InstanceRepository repository) { super(repository); } @Override protected Mono<Void> doNotify(InstanceEvent event, Instance instance) { return Mono.fromRunnable(() -> { if (event instanceof InstanceStatusChangedEvent) { System.out.println("例項名稱:"+instance.getRegistration().getName()); System.out.println("例項服務地址:"+instance.getRegistration().getServiceUrl()); String status = ((InstanceStatusChangedEvent) event).getStatusInfo().getStatus(); switch (status) { case "DOWN": System.out.println("健康檢查沒通過!"); break; case "OFFLINE": System.out.println("服務離線!"); break; case "UP": System.out.println("服務上線!"); break; case "UNKNOWN": System.out.println("服務未知異常!"); break; default: System.out.println(status); break; } } }); } }
最後在啟動打上@EnableAdminServer註解,開啟服務監控
@EnableAdminServer//開啟AdminServer功能 @SpringBootApplication public class SpringBootAdminServerApplication { public static void main(String[] args) { SpringApplication.run(SpringBootAdminServerApplication.class, args); } /** * 啟動成功 */ @Bean public ApplicationRunner applicationRunner() { return applicationArguments -> { System.out.println("啟動成功!"); }; } }
客戶端
服務端引入了2.2.0版本的依賴,因此客戶端也要引入2.2.0依賴
<!-- 引入admin相關依賴 --> <dependency> <groupId>de.codecentric</groupId> <artifactId>spring-boot-admin-starter-client</artifactId> <version>2.2.0</version> </dependency>
在配置檔案中,開啟埠、配置admin的server地址,以及賬號、密碼
#啟用端點,預設情況下,除shutdown以外的所有端點均已啟用 management.endpoint.shutdown.enabled=true #顯示db、redis、rabbti連線情況等 management.endpoint.health.show-details=always #公開所有端點web介面 management.endpoints.web.exposure.include=* #admin-server地址,以及登入賬號、密碼 spring.boot.admin.client.port=10010 spring.boot.admin.client.url=http://localhost:${spring.boot.admin.client.port} spring.boot.admin.client.username=admin spring.boot.admin.client.password=123456
為了方便測試其他東西
<!--新增springdata-cache依賴 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-cache</artifactId> </dependency> <!--新增MySQL驅動依賴 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency>
同時建立測試介面、定時器、cache快取、非同步任務,就是為了看服務端能否監控到
客戶端是要暴露actuator的web埠的,為了安全,客戶端只允許服務端請求actuator的web介面(通過約定好的請求頭來判斷)
/** * 針對actuator介面做安全限制,只允許服務端呼叫 */ @WebFilter @ServletComponentScan @Component public class ActuatorFilter implements Filter { @Value("${spring.boot.admin.client.port}") private String adminServicePort; @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) servletRequest; //判斷約定好的請求頭引數 if (request.getRequestURI().contains("/actuator") && !adminServicePort.equals(request.getHeader("spring-boot-admin-service"))){ throw new RuntimeException("抱歉,你無許可權訪問,Actuator埠受保護! Sorry, you have no permission to access it,Actuator port protected!"); } filterChain.doFilter(servletRequest, servletResponse); } }
效果演示
安全配置生效
首先先看安全配置都生效了沒有
訪問服務端,需要登入
登入上去,客戶端已經註冊成功
正常監控客戶端中...
瀏覽器直接訪問客戶端的actuator介面,直接丟擲異常
http://localhost:10011/actuator
其他介面正常訪問
自定義通知
注:客戶端首次在服務端註冊,並沒有觸發自定義通知
再看下自定義通知
停掉客戶端服務、重啟啟動客戶端,觸發服務端自定義通知
具體監控項
具體客戶端的監控首頁,有我們在客戶端寫的info資訊、磁碟監控、堆、非堆記憶體監控、程式、執行緒監控、垃圾回收監控
#新增描述 info.describe=SpringBootAdmin,Test Client Service! info.author=huanzi-qch info.version=1.0.0
計劃任務這裡可以看到我們配置的定時器
web對映可以看到所有的web介面
http跟蹤,可以檢視具體請求的響應情況
快取選單,可以看到我們使用到的快取空間
還可以下載jvm dump檔案
其他就不一一列舉,自己把專案跑起來再看
另外,這個版本好像不能檢視非同步任務?我並沒有找到相關頁面
後記
SpringBoot-Admin監控Client有兩種模式:
一種是在Client端引入spring-boot-admin-starter-client依賴,配置好Server的相關資訊。
另一種模式是將所有Client端註冊到服務發現(Eureka)元件中去,同時把Server端也註冊,這樣Server端就可以監控所有Client端了,不用對Client都新增依賴。
SpringBoot系列——admin服務監控暫時先記錄到這,後續有空再進行補充
程式碼開源
程式碼已經開源、託管到我的GitHub、碼雲: