行百里er 行百里er
首页
  • 分类
  • 标签
  • 归档
设计模式
  • JVM
  • Java基础
MySQL
Elastic Stack
Redis
  • Kafka
  • RocketMQ
分布式
Spring Cloud Alibaba
云原生
数据结构与算法
关于
GitHub (opens new window)

行百里er

Java程序员一枚
首页
  • 分类
  • 标签
  • 归档
设计模式
  • JVM
  • Java基础
MySQL
Elastic Stack
Redis
  • Kafka
  • RocketMQ
分布式
Spring Cloud Alibaba
云原生
数据结构与算法
关于
GitHub (opens new window)
  • 系统架构演进与Spring Cloud Alibaba简介
  • 万字长文:Spring Cloud Alibaba组件之Nacos实战及Nacos客户端服务注册源码解析
  • 服务容错的必要性与Spring Cloud Alibaba Sentinel 限流配置实战
  • Spring Cloud Alibaba Sentinel 熔断降级策略实战
  • Spring Cloud Alibaba:将 Sentinel 熔断限流规则持久化到 Nacos 配置中心
  • Sentinel限流降级如何优雅的返回?SentinelResource注解之blockHander和fallback
  • 微服务间的远程接口调用:OpenFeign 的使用
  • 强强联合:OpenFeign 整合 Sentinel
  • 网关 Spring Cloud Gateway - API 调用的组织者
  • Spring Cloud Gateway 网关限流
  • Spring Cloud Sleuth 整合 Zipkin 进行服务链路追踪
  • 高级版的 jvisualvm :Spring Boot Admin 监控 Spring Boot 微服务项目
    • 前奏:先说一下 Java VisualVM
    • 序曲:Spring Boot Actuator 监控
    • 高潮:Spring Boot Admin
      • 创建 Spring Boot Admin Server
      • 将微服务注册到 Spring Boot Admin
      • 开启 Spring Boot Admin 认证
      • 集成 Nacos 进行服务发现
    • 小结:为啥要监控?
  • 分布式事务解决方案之 Seata(一):分布式事务的常见解决方案及 Seata 简介
  • Seata 番外篇:使用 docker-compose 部署 Seata Server(TC)及 K8S 部署 Seata 高可用
  • 分布式事务解决方案之 Seata(二):Seata AT 模式
  • Spring Cloud Alibaba
行百里er
2022-08-29
目录

高级版的 jvisualvm :Spring Boot Admin 监控 Spring Boot 微服务项目

作者:行百里er

博客:https://chendapeng.cn (opens new window)

提示

这里是 行百里er 的博客:行百里者半九十,凡事善始善终,吾将上下而求索!

# 前奏:先说一下 Java VisualVM

Java VisualVM 是一个能够监控 JVM 的 jdk 自带的图形化工具:

image-20220828164318671.png

在 $JAVA_HOME/bin 目录下,可直接运行它。

要想监控远程服务器上的 Java 程序,可以在启动项目的时候添加 jmx 启动参数,我提前准备了一个 spring-boot-admin-server-0.0.1-SNAPSHOT.jar jar 包,上传到我的 Linux 服务器上,添加 jmx 启动参数启动它:

java -jar -Djava.rmi.server.hostname=192.168.242.112 -Dcom.sun.management.jmxremote.port=1888 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false spring-boot-admin-server-0.0.1-SNAPSHOT.jar
1

现在打开 jvisualvm ,监控该程序非常简单:

image-20220828165434650.png

连接上之后,就可以对程序进行监控了,各种指标一览无余:

image-20220828165532244.png

image-20220828165556502.png

单体项目,使用 jvisualvm 进行监控完全够用了!

# 序曲:Spring Boot Actuator 监控

Spring Boot 的 Actuator 是一个用于监控和管理自身应用信息的模块,使用该模块非常简单,只需要加入 spring-boot-starter-actuator 依赖即可:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
1
2
3
4

我们在 SpringCloudAlibabaDemo 工程下创建一个子工程 spring-boot-admin-server,引入上述依赖,然后启动项目,访问:http://localhost:8082/actuator :

image-20220828154513357.png

这是默认配置下,访问 Actuator 时的信息。

Actuator 端点(Endpoints)可以监视应用程序并与之交互。 Spring Boot 包含许多内置端点,并允许添加自己的端点。例如,health 端点提供基本的应用程序健康信息。

每个单独的端点都可以通过 HTTP 或 JMX 启用或禁用和远程访问。大多数应用程序选择通过 HTTP 对外暴露信息,访问端点的 URL 由 /actuator 前缀以及端点的 ID 组成。例如,默认情况下,health 端点映射到 /actuator/health ,即查看应用程序的健康状况可以访问 URL http://localhost:8082/actuator/health :

image-20220828155556190.png

返回信息:

{
    "status": "UP"
}
1
2
3

UP 表示当前应用处于健康状态,如果是 DOWN 则表示不健康,增加 management.endpoints.health.show-details=ALWAYS 可以查看应用健康状况的详细信息:

management:
  endpoint:
    health:
      show-details: always
1
2
3
4

image-20220828162539633.png

Actuator 提供了很多端点信息,如下所示:

HTTP方法 端点路径 含义 是否默认暴露
GET /actuator/configprops 显示所有 @ConfigurationProperties 的配置列表。 false
GET /actuator/beans 查看 Bean 及其关系列表 false
GET /actuator/heapdump 下载堆栈信息 false
GET /actuator/env 查看所有环境变量 false
GET /actuator/health 查看应用的健康指标 true
GET /actuator/info 查看应用信息 false
GET /actuator/mappings 查看所有 URL 映射 false
GET /actuator/httptrace 追踪信息 false
GET /actuator/loggers loggers 配置 false
GET /actuator/scheduledtasks 显示定时任务 false
GET /actuator/threaddump 显示线程信息 false
GET /actuator/sessions 允许从 Spring Session 支持的会话存储中检索和删除用户会话 false

完整列表见 Spring 官网:https://docs.spring.io/spring-boot/docs/2.6.3/reference/html/actuator.html#actuator (opens new window) 。注意选择的 Spring Boot 版本信息。

从这个表可以看出,大部分的端点默认是不暴露的,我们可以通过如下配置进行合理的端点暴露(多个用逗号分开):

management:
  endpoints:
    web:
      exposure:
        include: beans,threaddump
1
2
3
4
5

暴露全部的话,直接进行如下配置即可:

management:
  endpoints:
    web:
      exposure:
        include: '*'
1
2
3
4
5

当然,我们也可以扩展 actuator 端点,拿 health 端点为例,我们先看一下其返回的结果:

{
    "status": "UP",
    "components": {
        "diskSpace": {
            "status": "UP",
            "details": {
                "total": 18238930944,
                "free": 11510571008,
                "threshold": 10485760,
                "exists": true
            }
        },
        "ping": {
            "status": "UP"
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

可以看到,返回结果中有 components 下的 diskSpace ,我们从 spring-boot-actuator 源码中找到该返回结果的定义,在 spring-boot-actuator 中搜 diskSpace 关键字:

image-20220828170644769.png

进入 DiskSpaceHealthIndicator 类:

image-20220828171018416.png

可以看到该类继承 AbstractHealthIndicator 类,并在 doHealthCheck() 方法中定义了返回详情,那么我们自定义一个自己的健康检查类,输出自定义的信息的话,我们也创建一个 Component ,让他继承 AbstractHealthIndicator 实现输出自定义的信息。

/**
 * 博客:https://chendapeng.cn - 行百里者半九十,凡是善始善终,吾将上下而求索!
 * 公众号:行百里er
 *
 * @author 行百里者
 * @date 2022-08-28 17:13
 */
@Component
public class ChenDapengHealthIndicator extends AbstractHealthIndicator {

    /**
     * 自定义健康检查输出信息
     */
    @Override
    protected void doHealthCheck(Health.Builder builder) throws Exception {
        builder.up()
                .withDetail("status", "Oj8K!")
                .withDetail("whoami", "外星人")
                .withDetail("uptime", new Date());
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

再次访问健康状况,结果如下:

image-20220828171936525.png

# 高潮:Spring Boot Admin

有了 Actuator 的监控信息,我们总不能每次都站在干岸上看那些无聊的 JSON 数据吧?当然不能委屈自己,目下就有一个能够将 Actuator 的信息进行图形化展示的监控管理软件,没错,他就是 Spring Boot Admin 。

更让人兴奋的是,Spring Boot Admin 还能监控注册中心中的所有微服务的情况,并且还提供实时警报功能,这个使用 jvisualvm 就没办法搞了。

Spring Boot Admin 是一个开源项目,项目地址:https://github.com/codecentric/spring-boot-admin (opens new window) 。

# 创建 Spring Boot Admin Server

Spring Boot Admin 分为 Server 端和 Client 端。

Server 端引入 spring-boot-admin-starter-server 的依赖:

<dependency>
    <groupId>de.codecentric</groupId>
    <artifactId>spring-boot-admin-starter-server</artifactId>
    <version>2.5.1</version>
</dependency>
1
2
3
4
5

并且在启动类上加 @EnableAdminServer 注解:

@SpringBootApplication
@EnableAdminServer
public class SpringBootAdminServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringBootAdminServerApplication.class, args);
    }
}
1
2
3
4
5
6
7

启动项目后,输入 http://localhost:8082/ 访问:

image-20220828174535440.png

这样一个 admin server 就起来了。

# 将微服务注册到 Spring Boot Admin

Spring Boot Admin 怎么去监控服务呢,得有服务注册到 Admin Server 上来才行,所以我们将之前的几个微服务注册进来。

需要注册到 Admin Server 上的服务我们暂且称之为客户端,那么客户端需要怎么做呢?

1, 每个需要注册到 Admin Server 的服务都引入如下依赖:

<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>
    <version>2.5.1</version>
</dependency>
1
2
3
4
5
6
7
8
9

2, 配置连接到 Admin Server 的 url :

spring:
  boot:
    admin:
      client:
        url: http://localhost:8082
1
2
3
4
5

3, 配置对外暴露所有 Actuator 端点:

management:
  endpoints:
    web:
      exposure:
        include: '*'
1
2
3
4
5

启动服务:

image-20220828183431176.png

然后看监控:

image-20220828183509057.png

what!竟然全部灰色,意思是全部离线,可是我的所有服务都正常启动了啊,点进去看一下:

image-20220828184338625.png

看这个提示,应该能明白的差不多了,应该需要我们把应用的 url 在 admin 中显示为 ip 地址应该就可以了,果然有这个配置:

spring:
  boot:
    admin:
      client:
        url: http://localhost:8082
        # 注册时 admin 中显示IP地址不显示主机名
        prefer-ip: true
1
2
3
4
5
6
7

然后再重启:

image-20220828184926914.png

舒服了,全部在线!找一个服务点进去看细节:

image-20220828185025897.png

这个图是不是似曾相识啊!

没错,这个如就是和前面我们提到的 jvisualvm 的监控界面差不多,都有对 进程 、线程 、垃圾回收 、内存 等的监控,还有 JVM 各种指标的监控,想要康的东西应有尽有!

# 开启 Spring Boot Admin 认证

Spring Boot Admin 服务很有可能需要在外网访问,不可能让所有人输入一个网址就能随随便便看到我们服务的信息,因此需要登录功能。

Spring Boot Admin 官方说,由于有多种方法可以解决分布式 Web 应用程序中的身份验证和授权,因此 Spring Boot Admin 没有提供默认方法。我们借助于 spring-boot-starter-security 就可以实现开启登录认证功能。

1, 引入依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
1
2
3
4

2, 在 application.yml 配置文件中配置:

spring:
  security:
    user:
      name: admin
      password: admin123
1
2
3
4
5

3, 自定义安全配置类:

@Configuration
public class MySecurityConfig extends WebSecurityConfigurerAdapter {

    private final AdminServerProperties adminServer;

    private final SecurityProperties security;

    public MySecurityConfig(AdminServerProperties adminServer, SecurityProperties security) {
        this.adminServer = adminServer;
        this.security = security;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        SavedRequestAwareAuthenticationSuccessHandler successHandler = new SavedRequestAwareAuthenticationSuccessHandler();
        successHandler.setTargetUrlParameter("redirectTo");
        successHandler.setDefaultTargetUrl(this.adminServer.path("/"));

        http.authorizeRequests(
                (authorizeRequests) -> authorizeRequests.antMatchers(this.adminServer.path("/assets/**")).permitAll()
                        .antMatchers(this.adminServer.path("/actuator/info")).permitAll()
                        .antMatchers(this.adminServer.path("/actuator/health")).permitAll()
                        .antMatchers(this.adminServer.path("/login")).permitAll().anyRequest().authenticated()
        ).formLogin(
                (formLogin) -> formLogin.loginPage(this.adminServer.path("/login")).successHandler(successHandler).and()
        ).logout((logout) -> logout.logoutUrl(this.adminServer.path("/logout"))).httpBasic(Customizer.withDefaults())
                .csrf((csrf) -> csrf.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
                        .ignoringRequestMatchers(
                                new AntPathRequestMatcher(this.adminServer.path("/instances"),
                                        HttpMethod.POST.toString()),
                                new AntPathRequestMatcher(this.adminServer.path("/instances/*"),
                                        HttpMethod.DELETE.toString()),
                                new AntPathRequestMatcher(this.adminServer.path("/actuator/**"))
                        ))
                .rememberMe((rememberMe) -> rememberMe.key(UUID.randomUUID().toString()).tokenValiditySeconds(1209600));
    }

    // Required to provide UserDetailsService for "remember functionality"
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication().withUser(security.getUser().getName())
                .password("{noop}" + security.getUser().getPassword()).roles("USER");
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44

该配置类是 Spring Boot Admin 官网提供的:https://codecentric.github.io/spring-boot-admin/2.5.1/#_securing_spring_boot_admin_server (opens new window)

再次访问 admin 的时候,就需要登录了:

image-20220828191056379.png

最后,需要注意的是,既然 admin server 开启了登录认证,那么向 server 中注册的服务也必须得提供用户名密码才能注册上去,在客户端添加如下配置即可:

spring.boot.admin.client:
   username: admin
   password: admin123
1
2
3

# 集成 Nacos 进行服务发现

不知道大家发现了没有,我们要想让 Admin Server 监控我们的微服务,所有的微服务都得引入 admin 的相关依赖并且都得配置 admin server 的地址,用户名,密码等。这样太繁琐了!

其实我们可以将 admin server 也注册到 Nacos 注册中心,然后 admin server 自动从 Nacos 中获取服务信息来统一查看。

在 admin server 中引入 nacos 依赖,以及配置注册中心地址:

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
1
2
3
4
sping:
    cloud:
        nacos:
          discovery:
            # Nacos 集群
            server-addr: 192.168.242.112:81
1
2
3
4
5
6

这样就不用每个客户端都要写一大堆的配置了!

# 小结:为啥要监控?

因为面试官可能会问:“你平时是怎么调优的?” 呵呵,当然不是。

不过我们平时工作中,真遇到 OOM问题排查 、项目参数调优 等问题的时候,或许可以这么做:

  • 如果是单一项目,通过 JDK 自带的 jvisualvm 监控工具对项目进行监控,通过查看到具体装了多少个类进来,包括多少个线程以及线程运行的时间,通过图形化界面和容易就能找到是哪个类占用的内存比较多,然后再定位具体的问题。
  • 如果是多个项目我们可以通过 Spring Boot Admin 这类工具进行微服务项目监控,可以看到注册到注册中心(比如 Nacos)的所有服务的状况,然后再具体问题具体分析。

为了排查和解决问题,为了优化程序,我们需要监控。


首发公众号 行百里er ,欢迎各位关注阅读指正。

#Spring Cloud Alibaba#微服务
上次更新: 2022/10/04, 18:14:30
Spring Cloud Sleuth 整合 Zipkin 进行服务链路追踪
分布式事务解决方案之 Seata(一):分布式事务的常见解决方案及 Seata 简介

← Spring Cloud Sleuth 整合 Zipkin 进行服务链路追踪 分布式事务解决方案之 Seata(一):分布式事务的常见解决方案及 Seata 简介→

最近更新
01
重要数据不能丢!MySQL数据库定期备份保驾护航!
05-22
02
分布式事务解决方案之 Seata(二):Seata AT 模式
09-09
03
Seata 番外篇:使用 docker-compose 部署 Seata Server(TC)及 K8S 部署 Seata 高可用
09-05
更多文章>
Theme by Vdoing | Copyright © 2020-2023 行百里er | MIT License | 豫ICP备2022020385号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式