Prometheus是一个监控服务及具备存储时序数据功能的系统,Prometheus的基本原理是通过HTTP协议周期性抓取被监控组件的状态,组件通过暴露HTTP端口让Prometheus来拉取metres即可接入监控。
下面讲述Prometheus的搭建与配置,并与grafana 、cadvisor、node-exporter、redis、java服务形成一套监控体系。
prometheus.yml包含了一系列配置,用于定义Prometheus的行为、监控目标及规则等。
先准备prometheus.yml配置文件
global: #这个部分是全局配置,用于指定全局参数
scrape_interval: 1s #设置了抓取数据的时间间隔,每1秒抓取一次数据
evaluation_interval: 1s #设置了规则评估的时间间隔,每1秒进行一次规则评估
scrape_configs: #这个部分是定义了要抓取的目标以及相关配置的列表
- job_name: 'prometheus' #定义一个监控任务的名称为'prometheus',这个任务用于监控Prometheus自身。
static_configs: #指定静态目标配置,即直接配置目标的地址。
- targets: ['192.168.237.130:9090'] #指定Prometheus服务器的地址为192.168.237.130,监听端口为9090,这是Prometheus自身的监控地址。
- job_name: 'cadvisor' #定义一个监控任务的名称为'cadvisor',用于监控容器的性能指标。
static_configs: # 指定静态目标配置。
- targets: ['192.168.237.130:8899'] #指定cAdvisor的地址为192.168.237.130,监听端口为8899。
- job_name: 'node-exporter' #定义一个监控任务的名称为'node-exporter',用于监控主机的性能指标。
static_configs: #指定静态目标配置。
- targets: ['192.168.237.130:9100'] #定Node Exporter的地址为192.168.237.130,监听端口为9100。
- job_name: 'redis_exporter_targets' #定义一个监控任务的名称为'redis_exporter_targets',用于监控多个Redis实例。
static_configs: #指定静态目标配置。
- targets: #这里列出了多个Redis实例的地址,以Redis URL的形式指定。
- redis://192.168.237.130:6379
- redis://192.168.237.130:6378
# file_sd_configs:
# - files:
# - targets-redis-instances.json #使用 json 文件来提供多个Redis实例目标
metrics_path: /scrape #指定抓取数据的路径为/scrape。
relabel_configs: #用于重标签(relabel)配置,对抓取到的数据进行处理。
- source_labels: [__address__] #指定源标签为__address__。
target_label: __param_target #将源标签的值复制到新的标签__param_target。
- source_labels: [__param_target] #指定源标签为__param_target。
target_label: instance #将__param_target的值复制到新的标签instance。
- target_label: __address__ #指定目标标签为__address__。
replacement: 192.168.237.130:9121 #将目标标签的值替换为192.168.237.130:9121。
- job_name: 'redis_exporter' #定义一个监控任务的名称为'redis_exporter',用于监控Redis实例。
static_configs: #指定静态目标配置。
- targets: #指定Redis Exporter的地址为192.168.237.130,监听端口为9121。
- 192.168.237.130:9121
- job_name: 'demo' #定义一个监控任务的名称为'demo',用于监控示例目标。
static_configs: #指定静态目标配置。
- targets: ['192.168.3.80:8081'] #指定示例目标的地址为192.168.3.80,监听端口为8081。
#targets可以并列写入多个节点,用逗号隔开,主机名+端口号
metrics_path: /actuator/prometheus #指定抓取数据的路径为/actuator/prometheus。
以上ip根据自己的ip自行修改,port使用了每个服务默认的端口。
cAdvisor是用来监控Docker容器指标包括CPU、内存、网络、文件系统等资源的使用情况。
node-exporter用来采集服务器主机的运行指标例如CPU内存磁盘等信息。
redis_exporter用来监控redis的指标例如命令执行次数、内存使用、过期key数量、网络IO情况等信息。
上面的prometheus.yml是使用指定多个Redis监控的配置方式,这时redis_exporter抓取的端点是/scrape而不是/metrics(metrics_path默认为/metrics),即依赖Prometheus来将多个Redis地址分别分发给redis_exporter来监控。
通过Web请求可访问 http://exporterhost:9121/scrape 得到所有监控的Redis目标的metrics信息,通过http://exporterhost:9121/scrape?target=redis-host:redis-port 来访问指定Redis目标的metrics信息。
实际上一个redis_exporter只对应管理一个指定的Redis,即在运行redis_exporter时指定目标Redis(这种方式仅限于一个redis_exporter对一个Redis实例)
docker run -d --name redis_exporter -p 9121:9121 --network monitor --network-alias redis_exporter oliver006/redis_exporter --redis.addr redis://redis:6379 --redis.user root --redis.password '123456'
或者是在docker-compose中指定环境变量environment
redis-exporter:
image: oliver006/redis_exporter
container_name: redis-exporter
hostname: redis-exporter
restart: always
ports:
- "9121:9121"
networks:
- monitor
environment:
- REDIS_ADDR=redis://redis:6379
- REDIS_USER=root
- REDIS_PASSWORD=123456
这种一对一的方式则通过http://exporterhost:9121/metrics来得到监控的Redis的metrics信息。
prometheus.yml涉及到的targets-redis-instances.json的格式如下
[
{
"targets": [ "redis://redis-host-01:6379", "redis://redis-host-02:6379"],
"labels": { }
}
]
更多关于redis_exporter的配置信息可以参考https://github.com/oliver006/redis_exporter
job_name为demo的是一个springboot应用。
我们先download一个springboot项目集成度量采集相关依赖,以为后续prometheus抓取springboot应用指标做准备。
引入maven依赖坐标
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-actuatorartifactId>
dependency>
<dependency>
<groupId>io.micrometergroupId>
<artifactId>micrometer-registry-prometheusartifactId>
dependency>
这里需要开启三个配置,暴露metrics端点,这允许将指标被导入到Prometheus中
management.endpoints.web.exposure.include=* #首先需要暴露/actuator/prometheus端点,可以通过填写prometheus就可以,但这里直接指定暴露所有端点,暴露的端点可以通过HTTP请求访问(通过访问http://ip:port/actuator可查看端点列表)
management.endpoint.prometheus.enabled=true #springboot启动prometheus端点,会开放一个专门的HTTP端点,即/actuator/prometheus,prometheus可以通过请求该端点来获取指标数据
management.metrics.export.prometheus.enabled=true #用于将springboot内部度量数据导出为Prometheus格式的指标,可供Prometheus服务器收集和存储
Micrometer收集到的指标数据也会显示在/actuator/prometheus中,与springboot actuator的metrics集成在一块。
Micrometer支持多种度量类型,例如:
Counter(计数器):Counter 用于记录递增的计数值,通常用于度量事件发生的次数,如请求数、错误数等。
Gauge(仪表):Gauge 用于记录可变的数值,通常用于度量一些可变的状态或属性,如内存使用率、队列长度等。
Timer(计时器):Timer 用于度量某个操作的执行时间,它可以提供平均响应时间、响应时间分布等信息。
Distribution Summary(分布摘要):Distribution Summary 用于度量事件的分布情况,例如请求的响应大小或处理时间的分布。
至此,我们就开放了/actuator/prometheus端口,我们直接访问http://ip:port/actuator/prometheus可以查看Prometheus格式的度量指标,通过我们在prometheus.yml配置指定了抓取该metrics_path,便可以将应用的metres记录到Prometheus数据库中。
综上,需要监控cAdvisor、redis_exporter、node-exporter等,需要把这些环境搭建起来,下面使用docker-compose一键启动。
version: "3.7"
networks:
monitor:
driver: bridge
services:
prometheus:
image: prom/prometheus
container_name: prometheus
hostname: prometheus
restart: always
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
# - ./node_down.yml:/usr/local/etc/node_down.yml:rw
ports:
- "9090:9090"
networks:
- monitor
alertmanager:
image: prom/alertmanager
container_name: alertmanager
hostname: alertmanager
restart: always
# volumes:
# - ./alertmanager.yml:/usr/local/etc/alertmanager.yml
ports:
- "9093:9093"
networks:
- monitor
grafana:
image: grafana/grafana
container_name: grafana
hostname: grafana
restart: always
ports:
- "3000:3000"
networks:
- monitor
node-exporter:
image: quay.io/prometheus/node-exporter
container_name: node-exporter
hostname: node-exporter
restart: always
ports:
- "9100:9100"
networks:
- monitor
cadvisor:
image: google/cadvisor:latest
container_name: cadvisor
hostname: cadvisor
restart: always
# volumes:
# - /:/rootfs:ro
# - /var/run:/var/run:rw
# - /sys:/sys:ro
# - /var/lib/docker/:/var/lib/docker:ro
ports:
- "8899:8080"
networks:
- monitor
redis-exporter:
image: oliver006/redis_exporter
container_name: redis-exporter
hostname: redis-exporter
restart: always
ports:
- "9121:9121"
networks:
- monitor
启动Redis,这里准备了两个Redis来测试
version: "3.7"
networks:
monitor:
driver: bridge
services:
redis-6379:
image: redis
container_name: redis-6379
hostname: redis-6379
restart: always
ports:
- 6379:6379
networks:
- monitor
# volumes:
# - ./redis-6379.conf:/etc/redis/redis.conf
redis-6378:
image: redis
container_name: redis-6378
hostname: redis-6378
restart: always
ports:
- 6378:6379
networks:
- monitor
# volumes:
# - ./redis-6378.conf:/etc/redis/redis.conf
为实现springboot metrics的监控,我创建了prometheus-demo工程。
demo项目地址:prometheus-demo
主要完成以下功能的监控:
准备两个redis数据源
做好配置
将配置赋予资源对象,创建两个redis模板引擎,并放入到spring容器。(注意:这里放入spring容器的StringRedisTemplate要有一个名为redisTemplate的bean,否则启动会失败)
为对Redis操作创建服务类
分别对两个redis资源进行写入/读取/过期/删除操作。
第一个Redis进行随机1000000内数作为key不断插入并设置1分钟过期,另一个线程则随机删除1000000内的key;
第二个Redis进行循环添加有序集合操作并设置30秒过期,另一个线程则有间隔地循环删除。
使用Micrometer集成的用于监控和测量ExecutorService的性能指标和统计信息的组件ExecutorServiceMetrics。
先实现一个自定义的线程池,以便定义线程池/线程名称和在初始化时就交给ExecutorServiceMetrics监控。
并在线程池工具类创建若干线程池
同时,我们使用线程池简单运行一些线程
例如每隔一时间使用meterExecutor
线程池执行一个线程任务,在任务中停留一些时间代表逻辑消耗时间,以便对线程池线程执行情况进行统计。
另外,让上面Redis操作也使用线程池redisAddExecutor
这里使用高性能的内存缓存框架Caffeine作为本地缓存进行监控。
使用Micrometer集成的用于监控和记录Caffeine缓存性能指标的组件CaffeineCacheMetrics,以便在运行时收集、记录和可视化Caffeine缓存的各种性能数据和统计信息。
构建Caffeine管理类,简单提供Caffeine创建,如设置过期时间、缓存最大条数、初始化缓存空间,并且开启缓存统计信息记录功能(recordStats()),
上面提到的recordStats()开启后会向metrics记录的信息大概包含有:
- hitCount:缓存命中的次数,表示请求在缓存中找到了所需的值。
- missCount:缓存未命中的次数,表示请求在缓存中没有找到所需的值。
- loadSuccessCount:加载缓存项成功的次数,如果缓存支持加载,则表示从加载源(如数据库)加载成功的次数。
- loadFailureCount:加载缓存项失败的次数,如果缓存支持加载,则表示从加载源加载失败的次数。
- totalLoadTime:加载缓存项的总时间(以纳秒为单位),如果缓存支持加载,则表示加载所有缓存项所花费的总时间。
- evictionCount:缓存项被逐出的次数,表示因缓存策略(如最大大小限制)而导致的缓存项被清除的次数。
- evictionWeight:缓存项被逐出的总权重,如果缓存支持按权重计算大小限制,则表示被清除的缓存项的总权重。
使用cache.stats()方法即可打印查看。
并在创建完交给CaffeineCacheMetrics监控:
对Cache定时添加和记载缓存项,以便后面我们观察变化的指标信息。
使用度量类型Timer的相关方法来记录持续时间
创建一个可供请求的接口
我们对该目录下的接口作为连接点进行切面
使用Timer的三种方式来记录耗时:
通过meterRegistry.gauge监控String集合list的元素数量,并不断往String list插入值。
通过meterRegistry.gaugeCollectionSize来创建一个List并监控集合长度,并不断往integer list插入值。
我们将自己创建的map交给meterRegistry.gaugeMapSize并监控map大小,并不断往map里放入键值对。
创建一个AtomicInteger交给meterRegistry.gauge监控,并且自增atomicInteger的值,并且每atomicInteger的值取模30等于0则重新回归到0值。
监控完AtomicInteger,还继续创建了Integer类型的监控,往meterRegistry.gauge交替放入两个不同的Integer值,这是为了和AtomicInteger做对比,到后面我们观察metrics可视化就会发现,即使放入不同的Integer值,但最终只会记录第一次记录的Integer值,而对于AtomicInteger则会显示每次记录的值,这是由于AtomicInteger修改的是同一个对象,而Integer每次都是不同的对象,度量仪表gauge会基于第一次传入的那个对象跟踪其变化。
定期清理下集合,防止集合中的数据无限增加
Spring应用程序已经初始化完成,并且所有的Bean已经创建和配置好后,即我们实现ApplicationListener
来完成应用初始化完成监听。
在onApplicationEvent
中,将我们上述提到的需要运行的方法都加入进去:
综上所述,我们监听的内容有:
SpringBoot应用可以打包部署到服务器上,暴露好端口,这里我直接本地运行。
按照上面的端点都启动成功后
通过访问http://192.168.237.130:9121/metrics(替换成你的ip端口),默认为这个,但是我们需要查看具体的Redis,所以我们使用http://192.168.237.130:9121/scrape?target=192.168.237.130:6379和http://192.168.237.130:9121/scrape?target=192.168.237.130:6378,即可分别查看redis-exporter采集到的我们启动的两个Redis的指标。
例如:
Redis命令执行次数
Redis内存使用情况
Redis过期key数
Redis的网络I/O情况
等等…
通过访问http://localhost:8081/actuator/prometheus(替换成你的ip端口)可以查看我们启动的SpringBoot demo应用指标信息。
tomcat
JVM GC
主要还是查看我们刚刚提交的指标:
我们对线程池meter的测试指标,根据micrometer帮我们命的名则可以猜出这些指标的意思
caffeine本地缓存cacheName:flush
例如get加载次数、put次数、缓存项被逐出的总权重等等指标的值都有了
接口请求耗时
请求下我们刚刚写的接口
请求成功后到分别查看指标time_consume、time_consume_sample、time_unit
这里可以查看到计时次数、总计时时长、最大计时时长
你可以加入一些标签来标识每次的调用
gauge值
我们刚刚提交的指标collection_size_gauge便可以在其中找到,list integer现在的集合长度已有2366.0
验证下我们刚刚提到的atomicInteger与Integer的对比,
atomic_integer_gauge的值会增长
而random_int_gauge无论怎么刷新页面都是第一个存进去的对象的值
因此,我们所有放入到MeterRegistry的指标,micrometer都会帮我们转换成这种Prometheus可以识别的格式。
访问http://192.168.237.130:9090/targets(替换成你的ip端口)可以查看端点状态
在graph页可以搜索指标,例如按我们刚刚的自定义指标名称搜索counter_increment
可以匹配相关名称,这里micrometer自动给我们拼了后缀
所以我们使用counter_increment_total
搜索,查看到了我们所递增的指标值,刷新下,它会变化
也可以切换到视图查看变化
这里能查看到所有Prometheus监控到的指标
查看redis相关指标名
线程相关的指标
JVM相关的
等等…
这些指标都是我们一开始的prometheus.yml配置文件配置的所有端点ip:port的metrics_path获取来的指标。
例如springboot暴露的metrics_path为/actuator/prometheus,Prometheus就会定时去这个metrics_path上面抓取指标(例如它会定时访问http://ip:port/actuator/prometheus来获取指标列表),并记录下来。
借助Grafana来实现可视化界面
访问http://192.168.237.130:3000/dashboards(替换成你的ip端口),初始账号admin 密码admin
进入Grafana后点击这里添加Prometheus数据源
添加完毕
我们可以添加dashboard panel来可视化我们的指标
使用我们刚刚抓取的指标来分析:
线程池name为meter的完成任务次数
计算最近五分钟内redis指令执行速率
计算CPU使用率(它使用irate函数来计算CPU空闲时间的变化率,然后用100减去这个值,得到CPU使用率)
等等…
我们可以通过更多PromSQL查询语言来查询、转换、分析我们要观测的指标情况。
我们也可以通过导入现成模板来查看各种指标情况
这里要求导入模板编号,我们可以去grafana官网查找dashboard模板
访问https://grafana.com/grafana/dashboards/
搜索我们要监控的端点类型即可找到对应的指标dashboard模板
找到它的ID
复制,填入,Load
可以观测到我们部署的两个Redis实例的使用情况
再来搜索下Springboot指标模板
同理,复制ID,导入
查看SpringBoot APM Dashboard
选择我们需要观测的时间区间
查看SpringBoot的内存(包括堆)、CPU、GC、Logback等情况
等等…
更多Grafana Databoard等你去探索!