简介
- 微服务实践的过程中,我们会发现服务数量众多,如何监测我们哪些服务时正常的、哪些又是亚健康的服务呢?别急,springcloud既然叫微服务全家桶,当然它也有方案啦,我们可以轻松集成springadmin来对我们所有服务的健康状态做监控。
本文将介绍其springadmin如何使用,以及它提供的功能进行说明,内容有
- springadmin都有哪些功能
- 搭建安全的、高可用的springadmin监控服务
- 动态调整日志打印级别
- 配置服务状态变更邮件报警
- 查看服状态,包括CPU、内存、磁盘、缓存、DB、MQ各种服务的连接状态等等
- 查看java虚拟机状态、GC情况和堆栈信息
- 配置监控springboot1.X版本的集群外服务
注:本文基于springcloud2.1.3 Greenwich.RELEASE 版本
1、springadmin都有哪些功能
- springadmin是用来检测springboot服务状态的监控应用,可以利用springbootactuator暴露出来的endpoint查询服务的一些指标信息
- springcloud是基于springboot的应用,当然所有的springcloud服务都天然支持整合springadmin进行监控
- springadmin可以监控服务所在主机的运行状态信息,如cpu、内存、磁盘占用等等
- 可以监控微服务JVM的线程堆栈信息、GC信息、内存占用情况
- 可以检测服务内连接DB、缓存服务器、MQ服务等等服务的状态
- 默认所有的服务连接都是健康状态,整个服务才是UP的,当然我们也可以忽略一些服务的健康检测
- 线上服务发布后,我们还可以动态调整其日志打印级别,不过这不是持久化的,服务重启后失效
- 可以查看服务的环境变量信息
- 服务器的负载情况监测
- 服务暴露的HTTP接口信息查看
- 可以下载应用JVM内存快照信息,用来分析内存泄漏很方便,,由于文件一般都很大,需要下载很久,所以需要为此接口特别配置大一点的超时时间
- 可以配置应用状态变更进行邮件报警
2、搭建安全的、高可用的springadmin监控服务
2.1 服务目录结构如下
┍--- src/main/java
┊
├----- StartServer.java #服务启动类
┊
├-- src/java/test
┊
├-- src/main/resources
┊
├----- application.yml #可以把这些信息放在配置中心,发布后可以动态修改报警邮箱和规则等
┊
├----- bootstrap.yml #服务的基本信息、启动等信息,可以被application.yml中的配置信息覆盖
┊
┕-- pom.xml
2.2 引入依赖信息
- 编辑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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.danyuanblog.springcloud</groupId>
<artifactId>spring-admin-server</artifactId>
<name>spring-admin-server</name>
<url>http://www.danyuanblog.com</url>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.3.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<!-- 定义公共变量 -->
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.RELEASE</spring-cloud.version>
<admin-server.version>2.1.3</admin-server.version>
</properties>
<dependencies>
<!-- springadmin服务器依赖 -->
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-server</artifactId>
<version>${admin-server.version}</version>
</dependency>
<!-- 整合安全服务依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!--整合邮箱报警依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<!-- 监控服务高可用自动集群搭建能力依赖 -->
<dependency>
<groupId>com.hazelcast</groupId>
<artifactId>hazelcast</artifactId>
</dependency>
<!-- Eureka注册中心客户端依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!-- 配置中心客户端依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<!-- 服务监控端点暴露依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- web服务依赖,容器替换tomcat为jetty,由于tomcat会有个bug -->
<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>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
</repository>
<repository>
<id>Sonatype</id>
<name>Sonatype Repository</name>
<url>http://repository.sonatype.org/content/groups/public</url>
<layout>default</layout>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>Central</id>
<name>Central Repository</name>
<url>http://repo1.maven.org/maven2</url>
<layout>default</layout>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<name>oss.sonatype.org</name>
<id>oss.sonatype.org</id>
<url>http://oss.sonatype.org/content/groups/public</url>
</pluginRepository>
</pluginRepositories>
</project>
2.3 启动类信息
- 编辑StartServer.java
package com.danyuanblog.springcloud;
import java.time.Duration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
import org.springframework.security.web.csrf.CookieCsrfTokenRepository;
import com.hazelcast.config.Config;
import com.hazelcast.config.EvictionPolicy;
import com.hazelcast.config.InMemoryFormat;
import com.hazelcast.config.MapConfig;
import com.hazelcast.config.MergePolicyConfig;
import com.hazelcast.map.merge.PutIfAbsentMapMergePolicy;
import de.codecentric.boot.admin.server.config.AdminServerProperties;
import de.codecentric.boot.admin.server.config.EnableAdminServer;
import de.codecentric.boot.admin.server.domain.entities.InstanceRepository;
import de.codecentric.boot.admin.server.notify.Notifier;
import de.codecentric.boot.admin.server.notify.RemindingNotifier;
//启用adminServer服务
@EnableAdminServer
//启用服务发现客户端
@EnableDiscoveryClient
@SpringBootApplication
public class StartServer {
public static void main(String[] args) {
SpringApplication.run(StartServer.class, args);
}
@Bean
public Config hazelcastConfig() {//集群配置
MapConfig mapConfig = new MapConfig("spring-boot-admin-event-store").setInMemoryFormat(InMemoryFormat.OBJECT)
.setBackupCount(1)
.setEvictionPolicy(EvictionPolicy.NONE)
.setMergePolicyConfig(new MergePolicyConfig(
PutIfAbsentMapMergePolicy.class.getName(),
100
));
return new Config().setProperty("hazelcast.jmx", "true").addMapConfig(mapConfig);
}
@Configuration
public class NotifierConfiguration {
@Autowired
private InstanceRepository repository;
@Autowired
private Notifier notifier;
@Primary
@Bean(initMethod = "start", destroyMethod = "stop")
public RemindingNotifier remindingNotifier() {//告警邮件发送频率配置
RemindingNotifier notifier1 = new RemindingNotifier(notifier, repository);
// The reminders will be sent every 10 minutes
notifier1.setReminderPeriod(Duration.ofMinutes(10));
// Schedules sending of due reminders every 10 seconds.
notifier1.setCheckReminderInverval(Duration.ofSeconds(10));
return notifier1;
}
}
@Configuration
public static class SecuritySecureConfig extends WebSecurityConfigurerAdapter {
private final String adminContextPath;
public SecuritySecureConfig(AdminServerProperties adminServerProperties) {
this.adminContextPath = adminServerProperties.getContextPath();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
//配置springadmin web控制台登录信息和监控端点访问授权开放
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()
.httpBasic().and()
.csrf()
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
.ignoringAntMatchers(
adminContextPath + "/instances",
adminContextPath + "/actuator/**"
);
}
}
}
2.4 配置信息
- 编辑bootstap.yml
spring:
application:
name: admin-server
cloud:
#配置中心相关配置
config:
discovery:
enabled: true
service-id: config-server
profile: ${env:dev} #运行环境,可以通过环境变量进行切换dev,test,stage,prod
label: master
fail-fast: true
retry:
initial-interval: 2000 #首次重试间隔时间,默认1000毫秒
multiplier: 1.1D #下一次重试间隔时间的乘数,比如开始1000,下一次就是1000*1.1=1100
max-interval: 5000 #最大重试时间,默认2000
max-attempts: 50 #最大重试次数,默认6次
#注册中心相关配置
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8763/eureka/
instance:
prefer-ip-address: true
leaseRenewalIntervalInSeconds: 10
health-check-url-path: /actuator/health
#服务端点安全控制,通过eureka来发现服务,自然要配置这里
metadata-map:
user.name: ${spring.security.user.name}
user.password: ${spring.security.user.password}
#容器端口配置
server:
port: ${port:1202}
#监控端点配置
management:
endpoint:
#启用动态刷新配置功能
bus-refresh:
enabled: true
#监控端点配置为全覆盖
health:
show-details: ALWAYS
#暴露所有服务端点
endpoints:
web:
exposure:
include: "*"
- 编辑application.yml
spring:
security:
user: #springadmin登录账号密码配置
name: admin
password: 123456
boot:
admin:
monitor: #检测周期和超时时间配置
period: 180000
status-lifetime: 180000
read-timeout: 120000
ui:
title: SIMO-E2业务平台服务监控后台
mail:
host: smtp.xxx.com
username: xxx@xxx.com
password: xxxxxx
default-encoding: UTF-8
properties:
mail:
#这里配置为不开启SSL
smtp:
auth: false
starttls:
enable: false
required: false
spring.boot.admin.notify.mail:
#配置报警通知邮箱号列表,以逗号分隔
to: xxx@xxx.com,xxx@xxx.com,xxx@xxx.com
#邮件发送者
from: xxx@xxx.com
#开启邮件报警功能
enabled: true
#配置应用某些状态变更不通知,A状态->B状态,中间以冒号分隔,常用的如下所示
#ignore-changes: UNKNOWN:UP,OFFLINE:UP,DOWN:UP,UP:UNKNOWN,OFFLINE:OFFLINE,DOWN:DOWN
ignore-changes: UNKNOWN:UP
2.5 springcloud服务监控端点配置
- 微服务只需注册到注册中心,并开启监控端点暴露即可
- 配置信息如下:
management:
endpoint:
bus-refresh:
enabled: true
health:
show-details: ALWAYS
endpoints:
web:
exposure:
include: "*" #端点全部开启
3、动态调整日志打印级别
- 登录进入springadmin web控制台
- 打开日志选项卡
- 可以看到很多类或包配置的日志打印级别
- 现在某个条目的某个日志级别按钮,即可对该包名下或该类的日志级别进行动态调整
4、配置服务状态变更邮件报警说明
服务状态变更均会进行报警,服务有如下几种状态
- 关闭状态(DOWN)
- 健康在线状态(UP)
- 服务已下线(OFFLINE)
- 未知状态(UNKNOWN)
我们可以配置某些状态变更时不触发邮件报警,具体根据实际情况去配置即可,推荐使用默认的配置即可
5、查看服状态,包括CPU、内存、磁盘、缓存、DB、MQ各种服务的连接状态等等
从springadmin监控后台进入,选择某个实例,进入实例详情页,既可看到这些指标信息
如果发现哪些指标是DOWN的状态,就需要去排查我们的服务哪里有问题了
6、查看java虚拟机状态、GC情况和堆栈信息
通过监控后台页面,我们可以很容易的查看这些信息判断服务的健康情况。
如果还需要更精确的分析服务的健康状态,最好还是使用专业的jvm分析工具。
7、配置监控springboot1.X和2.X版本的集群外服务
7.1 集群外springboot2.X版本的应用监控
- 引入依赖
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-client</artifactId>
<version>${admin-client.version}</version>
</dependency>
- 编辑application.yml
spring:
application:
name: service-name
boot:
admin: #监控服务相关配置
client:
url: http://localhost:1202 #springadminserver地址
username: admin #spring admin server用户名
password: 123456 #spring admin server密码
instance:
name: ${spring.application.name} #该服务在springadmin中展示的名字配置
service-url:http://localhost:8282 #此服务暴露给springadmin的地址,用来拉取此服务的健康指标信息
metadata:
user.name: admin
user.password: 123456
#监控端点暴露
management:
endpoint:
health:
show-details: ALWAYS
endpoints:
web:
exposure:
include: "*"
7.2 集群外springboot1.X版本的应用监控
- 引入依赖,admin-client.version跟随项目本身的springboot版本一致就行了
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-client</artifactId>
<version>${admin-client.version}</version>
</dependency>
- 编辑application.yml
spring:
application:
name: service-name
boot:
admin:
client:
url: http://localhost:1202
username: admin #spring admin server用户名
password: 123456 #spring admin server密码
instance:
name: ${spring.application.name}
metadata:
user.name: ${adminUser:simo}
user.password: ${adminPass:simo}
endpoints:
enabled: true
info.enabled: true
health.enabled:true
security.enabled:false
- springboot1.x版本监控端点暴露配置
参考:springboot1.x endpoint配置说明,需要监控其他端点,可以参考这个文档即可