SpringBoot - 运行性能监控
前言
方式一: Spring Boot Actuator + Micrometer + Prometheus + Grafana
方式二: Spring Boot Actuator + Spring Boot Admin
方式一 Micrometer + Prometheus + Grafana
pom.xml
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>io.micrometer</groupId> <artifactId>micrometer-registry-prometheus</artifactId> </dependency>
如果使用了 Spring Security 等权限框架需要放开
web.ignoring().antMatchers("/actuator", "/actuator/**");
management: endpoints: web: exposure: include: 'prometheus' metrics: tags: application: ${spring.application.name}
浏览器测试
http://localhost:8080/actuator/prometheus
Prometheus
Prometheus 是一款开源的监控 + 时序数据库 + 报警软件
Prometheus 官网 下载,或者访问 docker 进行安装
docker pull prom/statsd-exporter docker run -d -p 9090:9090 \ -v $(pwd)/prometheus.yml:/etc/prometheus/prometheus.yml \ prom/prometheus --config.file=/etc/prometheus/prometheus.yml
需编写 prometheus.yml
新增
scrape_configs: - job_name: 'springboot' scrape_interval: 15s scrape_timeout: 10s metrics_path: '/actuator/prometheus' static_configs: - targets: ['localhost:8080']
如果不是采用的 docker 方式,直接找到安装目录下的 prometheus.yml,在 scrape_configs 新增
scrape_configs: - job_name: 'springboot' # metrics_path defaults to '/metrics' # scheme defaults to 'http'. metrics_path: '/actuator/prometheus' static_configs: - targets: ['localhost:8080']
targets 对应需要监控的服务地址
浏览器访问测试
http://localhost:9090
至此,已经用 Prometheus 实现了监控数据的可视化,然而使用体验并不好。下面来用 Grafana 实现更友好、更贴近生产的监控可视化。
grafana
Grafana 是一个开源的跨平台度量分析和可视化 + 告警工具
使用 docker 安装
docker run -d --name=grafana -p 3000:3000 grafana/grafana
Windows 的话下载 zip 或者安装包直接安装即可
登录:访问 http://localhost:3000 ,初始账号/密码为:admin/admin
绑定 Prometheus
左侧菜单选择 Configuration-datasources-Add data source
添加 Prometheus 地址
点击 save&test,测试成功即可
创建监控 Dashboard
左侧菜单选择+Create-Import,输入 id 为 4701 ,这个是为 Micrometer 提供的增强包。有兴趣可以前往 Grafana Lab - Dashboards ,输入关键词即可搜索指定 Dashboard, 详情页的右上角找到 id
比较好用的 Dashboard
- JVM (Micrometer)
- JVM (Actuator)
- Spring Boot Statistic
注意是以 Prometheus 作为数据源,支持 Micrometer 的 Dashboard
点击右侧 load 后,选择 prometheus,确认后 import
如果选择项是空的,注意是否开启了 prometheus
可查看监控的服务 jvm 等情况
告警
Grafana 支持的告警渠道非常丰富,例如邮件、钉钉、Slack、Webhook 等,有兴趣可以了解下
方式二 Spring Boot Admin
Spring Boot Admin 是一个开源社区项目,用于管理和监控 SpringBoot 应用程序。 应用程序作为 Spring Boot Admin Client 向为 Spring Boot Admin Server 注册(通过 HTTP)或使用 SpringCloud 注册中心(例如 Eureka,Consul)发现。 UI 是的 AngularJs 应用程序,展示 Spring Boot Admin Client 的 Actuator 端点上的一些监控。
搭建
创建两个 SpringBoot 项目,一个作为监控端(admin-server-demo),一个作为被监控端(admin-client-demo)
server 端
pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.4.0</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.jonesun</groupId> <artifactId>admindemo</artifactId> <version>0.0.1-SNAPSHOT</version> <name>admin-server-demo</name> <description>Demo project for Spring Boot</description> <properties> <java.version>14</java.version> <spring-boot-admin.version>2.3.1</spring-boot-admin.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>de.codecentric</groupId> <artifactId>spring-boot-admin-starter-server</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-mail</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>de.codecentric</groupId> <artifactId>spring-boot-admin-dependencies</artifactId> <version>${spring-boot-admin.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
application.yml
server: port: 8001 spring: application: name: admin-server boot: admin: notify: mail: # 收件人列表(多个使用,分隔) to: xxx@163.com # 是否开启(如果暂时不需要通知,可关闭) enabled: true # 抄送 cc: 111@163.com,222@163.com # 发件人 from: xxx<aaa@163.com> mail: host: smtp.163.com # port: 25 username: aaa@163.com default-encoding: utf-8 password: xxxxxx
QQ、163 等邮箱需要设置授权码,password 填生成好的授权码,如果不需要邮件告警,去除 mail 相关配置即可
AdminServerDemoApplication.java
@EnableAdminServer @SpringBootApplication public class AdminServerDemoApplication { public static void main(String[] args) { SpringApplication.run(AdminServerDemoApplication.class, args); } }
注意,一定要加上 @EnableAdminServer
client 端
新建 Spring Boot 项目
pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.4.0</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.jonesun</groupId> <artifactId>admin-client-demo</artifactId> <version>0.0.1-SNAPSHOT</version> <name>admin-client-demo</name> <description>Demo project for Spring Boot</description> <properties> <java.version>14</java.version> <spring-boot-admin.version>2.3.1</spring-boot-admin.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>de.codecentric</groupId> <artifactId>spring-boot-admin-starter-client</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>de.codecentric</groupId> <artifactId>spring-boot-admin-dependencies</artifactId> <version>${spring-boot-admin.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
application.yml
spring: application: name: admin-client boot: admin: client: url: http://localhost:8001 instance: # 客户端实例 url service-url: http://127.0.0.1:8002 prefer-ip: true # 客户端实例名称 name: cts-vivo-preview server: port: 8002 management: endpoints: web: exposure: include: '*' endpoint: health: show-details: ALWAYS
运行验证
分别启动两个服务,然后浏览器中打开 server 端的网址: http://localhost:8001/
即可查看监控信息,和服务的详细情况
如果存在 Spring Security,则需要添加自定义安全配置,以允许对端点进行未经身份验证的访问
@Configuration public class ActuatorSecurity extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.requestMatcher(EndpointRequest.toAnyEndpoint()).authorizeRequests() .anyRequest().permitAll() } }
查看日志
如果想在 admin-server 中查看 client 的日志,则需在 client 的 application.yml 中加入配置:
logging: pattern: file: "%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(%5p) %clr(${PID}){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n%wEx" file: # 日志所在路径(需与日志框架中配置的路径一致) name: C:/tmp/admin-client/spring-log.log
注意 logging.file.name 不支持表达式,所以项目中无论是使用默认 logback 还是 log4j2,都需要匹配好日志路径及名称。如果需要配置相对路径则可配置为./log/xxx.log,表示为项目所在目录下的 log 文件夹中的 xxx.log 文件 低版本的 springBoot 没有 logging.file.name,可直接配置为 logging.file
这样就可以在 admin-server 中查看日志,无需登录到服务器上查看了,甚至可以利用日志配置,在线实时调整日志的显示级别(内部原理也是 actuator),方便在出现异常情况下查看详细的日志打印
告警
结合 spring-boot-starter-mail(admin-server 中配置) 进行告警,主要是 Spring Boot Actuator 的使用,这里举个例子:
当服务器中的磁盘容量不足 5GB 时,进行邮件告警
修改 client-server 中的 application.yml
management: endpoints: web: exposure: include: '*' exclude: env,beans jmx: exposure: include: health,info endpoint: health: show-details: ALWAYS health: diskspace: # 当磁盘容量不足 5GB 时告警 threshold: 5GB
实际项目中肯定不能将所有 endpoint 都暴露,根据项目自己调整
这边我们设置 diskspace 的阈值为 5GB, 即如果运行环境的磁盘容量不足 5GB 时进行告警(本地测试的话为看到邮件通知可调整为较大的数值如 150GB)
重新启动项目后, 就会收到邮件通知,并且 admin-server 中对应的 diskspace 状态会为 DOWN
权限验证
当使用 Spring Boot Actuator 和 Spring Boot Admin, 实际项目中肯定不能直接暴露到让人随意访问,这里我们加入 Spring Security
- admin-server 中
pom.xml 中加入
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency>
application.yml 中加入测试账户(实际项目中可结合数据库进行配合),不过一般项目写死也可以,毕竟服务器配置一般不会外传
spring: security: user: name: admin password: admin123
加入权限配置 SecurityConfig:
@Configuration public class SecurityConfig extends WebSecurityConfigurerAdapter { private final String contextPath; public SecurityConfig(AdminServerProperties adminServerProperties) { this.contextPath = adminServerProperties.getContextPath(); } @Override protected void configure(HttpSecurity http) throws Exception { // 跨域设置,SpringBootAdmin 客户端通过 instances 注册,见 InstancesController http.csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()) .ignoringAntMatchers(contextPath + "/instances"); http.authorizeRequests().anyRequest().authenticated(); // 所有请求必须通过认证 http.formLogin().loginPage("/login").permitAll(); http.logout().logoutUrl("/logout").logoutSuccessUrl("/login"); // 启用 basic 认证,SpringBootAdmin 客户端使用的是 basic 认证 http.httpBasic(); } }
- client-server 中
application.yml 中加入配置
spring: boot: admin: client: username: admin password: admin123
分别重启两个项目,浏览器访问 admin-server,可以发现需要登录才可以查看
如果 client-server 也使用了 security
则首先需支持 HTTP BASIC 方式访问端点(默认是支持的),然后将元数据提供给 admin-server
client-server 中 application.yml 加入:
spring: boot: admin: client: instance: metadata: user.name: ${spring.security.user.name} user.password: ${spring.security.user.password}
如果不支持的话,则可以定制 HttpHeadersProvider 来达到效果
示例源码
Spring Cloud 下的应用
集成了 Spring Cloud Discovery (如 eureka) 到应用程序后,则不需要 Spring Boot Admin 客户端。 只需在 DiscoveryClient 中添加 Spring Boot Admin Server,其他新增应用的话直接注册到 DiscoveryServer 即可。
示例源码
与 Spring Boot Admin 类似的还有 Apache Skywalking 利用的 java agent, 可以监控任意的 java 应用,感兴趣可以了解下
常见问题
- 监控页面对应信息一栏显示: 未提供任何信息,需要使用 spring-boot 的插件,运行 spring-boot:build-info,生成 Actuator 使用的构建信息文件 build-info.properties, 再次运行就可以看到了
或者在 application.yml 中加入:
info: version: @project.version@ name: @project.artifactId@ group: @project.groupId@ description: @project.description@ #还可以自定义信息 author: jone sun blog: https://jonesun.github.io/
如果运行后出现类似:
org.yaml.snakeyaml.scanner.ScannerException: while scanning for the next token found character '@' that cannot start any token. (Do not use @ for indentation) in 'reader', line 39, column 12: version: @project.version@
错误,先检查下 pom.xml 中是否存在对应值,尤其有些项目没有写 description,再在 build 标签下新增:
<resources> <resource> <directory>src/main/resources</directory> <!--开启过滤,用指定的参数替换 directory 下的文件中的参数--> <filtering>true</filtering> </resource> </resources>
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论