构建全面监控体系:Prometheus与Grafana、cAdvisor、Node Exporter、Redis和Java服务的搭建与配置

简介

Prometheus是一个监控服务及具备存储时序数据功能的系统,Prometheus的基本原理是通过HTTP协议周期性抓取被监控组件的状态,组件通过暴露HTTP端口让Prometheus来拉取metres即可接入监控。
下面讲述Prometheus的搭建与配置,并与grafana 、cadvisor、node-exporter、redis、java服务形成一套监控体系。

prometheus配置文件

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

cAdvisor是用来监控Docker容器指标包括CPU、内存、网络、文件系统等资源的使用情况。

node-exporter

node-exporter用来采集服务器主机的运行指标例如CPU内存磁盘等信息。

redis_exporter

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

micrometer-registry-prometheus

job_name为demo的是一个springboot应用。
我们先download一个springboot项目集成度量采集相关依赖,以为后续prometheus抓取springboot应用指标做准备。
引入maven依赖坐标

  	<!--		集成actuator用于开放metrics指标-->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-actuator</artifactId>
		</dependency>
		<!--		集成micrometer将各种度量类型指标转换prometheus识别的格式 -->
		<dependency>
			<groupId>io.micrometer</groupId>
			<artifactId>micrometer-registry-prometheus</artifactId>
		</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数据库中。

运行监控与端点

启动Prometheus、exporter、grafana等

综上,需要监控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

image.png

启动Redis

启动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

image.png

启动springboot应用

为实现springboot metrics的监控,我创建了prometheus-demo工程。
demo项目地址:prometheus-demo
主要完成以下功能的监控:

对Redis操作

准备两个redis数据源
做好配置
image.png
将配置赋予资源对象,创建两个redis模板引擎,并放入到spring容器。(注意:这里放入spring容器的StringRedisTemplate要有一个名为redisTemplate的bean,否则启动会失败)
image.png
为对Redis操作创建服务类
分别对两个redis资源进行写入/读取/过期/删除操作。
第一个Redis进行随机1000000内数作为key不断插入并设置1分钟过期,另一个线程则随机删除1000000内的key;
第二个Redis进行循环添加有序集合操作并设置30秒过期,另一个线程则有间隔地循环删除。
image.png
image.png

对线程池监控

使用Micrometer集成的用于监控和测量ExecutorService的性能指标和统计信息的组件ExecutorServiceMetrics。
先实现一个自定义的线程池,以便定义线程池/线程名称和在初始化时就交给ExecutorServiceMetrics监控。
image.png
并在线程池工具类创建若干线程池
image.png
同时,我们使用线程池简单运行一些线程
例如每隔一时间使用meterExecutor线程池执行一个线程任务,在任务中停留一些时间代表逻辑消耗时间,以便对线程池线程执行情况进行统计。
image.png
另外,让上面Redis操作也使用线程池redisAddExecutor

对本地缓存监控

这里使用高性能的内存缓存框架Caffeine作为本地缓存进行监控。
使用Micrometer集成的用于监控和记录Caffeine缓存性能指标的组件CaffeineCacheMetrics,以便在运行时收集、记录和可视化Caffeine缓存的各种性能数据和统计信息。
构建Caffeine管理类,简单提供Caffeine创建,如设置过期时间、缓存最大条数、初始化缓存空间,并且开启缓存统计信息记录功能(recordStats()),

上面提到的recordStats()开启后会向metrics记录的信息大概包含有:

  • hitCount:缓存命中的次数,表示请求在缓存中找到了所需的值。
  • missCount:缓存未命中的次数,表示请求在缓存中没有找到所需的值。
  • loadSuccessCount:加载缓存项成功的次数,如果缓存支持加载,则表示从加载源(如数据库)加载成功的次数。
  • loadFailureCount:加载缓存项失败的次数,如果缓存支持加载,则表示从加载源加载失败的次数。
  • totalLoadTime:加载缓存项的总时间(以纳秒为单位),如果缓存支持加载,则表示加载所有缓存项所花费的总时间。
  • evictionCount:缓存项被逐出的次数,表示因缓存策略(如最大大小限制)而导致的缓存项被清除的次数。
  • evictionWeight:缓存项被逐出的总权重,如果缓存支持按权重计算大小限制,则表示被清除的缓存项的总权重。

使用cache.stats()方法即可打印查看。

并在创建完交给CaffeineCacheMetrics监控:
image.png
对Cache定时添加和记载缓存项,以便后面我们观察变化的指标信息。
image.png

对接口耗时统计

使用度量类型Timer的相关方法来记录持续时间
image.png
创建一个可供请求的接口
image.png
我们对该目录下的接口作为连接点进行切面
使用Timer的三种方式来记录耗时:

  1. Timer.start(),执行完逻辑,手动stop;
  2. timer.record(Supplier var1)接收一个线程,并等线程执行逻辑结束时自动记录执行耗时;
  3. timer.record(long time, TimeUnit timeUnit)自己计算耗时之后,再将结果传给timer进行记录;

image.png

对一些度量类型操作

定义一些变量
image.png

counter

创建一个Counter,每隔一时间就自增
image.png

guage

通过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会基于第一次传入的那个对象跟踪其变化。
image.png
定期清理下集合,防止集合中的数据无限增加
image.png

应用初始化完成监听

Spring应用程序已经初始化完成,并且所有的Bean已经创建和配置好后,即我们实现ApplicationListener<ApplicationReadyEvent>来完成应用初始化完成监听。
onApplicationEvent中,将我们上述提到的需要运行的方法都加入进去:
image.png
综上所述,我们监听的内容有:

  • Redis相关操作
  • 线程池运行状况
  • 本地缓存执行状况
  • 接口耗时记录
  • 自定义指标Counter、Guage标签的值变化

启动

SpringBoot应用可以打包部署到服务器上,暴露好端口,这里我直接本地运行。
image.png

指标观察

按照上面的端点都启动成功后

Redis-exporter指标列表

通过访问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命令执行次数
image.png
Redis内存使用情况
image.png
Redis过期key数
image.png
Redis的网络I/O情况
image.png
等等…

SpringBoot metrics指标列表

通过访问http://localhost:8081/actuator/prometheus(替换成你的ip端口)可以查看我们启动的SpringBoot demo应用指标信息。
tomcat
image.png
JVM GC
image.png

主要还是查看我们刚刚提交的指标:

我们对线程池meter的测试指标,根据micrometer帮我们命的名则可以猜出这些指标的意思
image.png
image.png

caffeine本地缓存cacheName:flush
例如get加载次数、put次数、缓存项被逐出的总权重等等指标的值都有了
image.png

接口请求耗时
请求下我们刚刚写的接口
image.png
请求成功后到分别查看指标time_consume、time_consume_sample、time_unit
image.png
image.png
image.png
这里可以查看到计时次数、总计时时长、最大计时时长
你可以加入一些标签来标识每次的调用

gauge值
我们刚刚提交的指标collection_size_gauge便可以在其中找到,list integer现在的集合长度已有2366.0
image.png
验证下我们刚刚提到的atomicInteger与Integer的对比,
atomic_integer_gauge的值会增长
image.png
而random_int_gauge无论怎么刷新页面都是第一个存进去的对象的值
在这里插入图片描述

counter值
image.png

因此,我们所有放入到MeterRegistry的指标,micrometer都会帮我们转换成这种Prometheus可以识别的格式。

Prometheus指标列表

访问http://192.168.237.130:9090/targets(替换成你的ip端口)可以查看端点状态
image.png
在graph页可以搜索指标,例如按我们刚刚的自定义指标名称搜索counter_increment
可以匹配相关名称,这里micrometer自动给我们拼了后缀
image.png
所以我们使用counter_increment_total搜索,查看到了我们所递增的指标值,刷新下,它会变化
image.png
也可以切换到视图查看变化
image.png
这里能查看到所有Prometheus监控到的指标
查看redis相关指标名
image.png
线程相关的指标
image.png
JVM相关的
image.png
等等…
这些指标都是我们一开始的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数据源
image.png
image.png
image.png
image.png
添加完毕
image.png
我们可以添加dashboard panel来可视化我们的指标
image.png

自定义查询

使用我们刚刚抓取的指标来分析:
线程池name为meter的完成任务次数
image.png
计算最近五分钟内redis指令执行速率
image.png
计算CPU使用率(它使用irate函数来计算CPU空闲时间的变化率,然后用100减去这个值,得到CPU使用率)
image.png
等等…
我们可以通过更多PromSQL查询语言来查询、转换、分析我们要观测的指标情况。

直接使用模板

我们也可以通过导入现成模板来查看各种指标情况
image.png
image.png
这里要求导入模板编号,我们可以去grafana官网查找dashboard模板
访问https://grafana.com/grafana/dashboards/
搜索我们要监控的端点类型即可找到对应的指标dashboard模板
image.png
找到它的ID
image.png
复制,填入,Load
image.png可以观测到我们部署的两个Redis实例的使用情况
image.png
再来搜索下Springboot指标模板
image.png
image.png
同理,复制ID,导入
查看SpringBoot APM Dashboard
选择我们需要观测的时间区间
查看SpringBoot的内存(包括堆)、CPU、GC、Logback等情况
image.png
image.png
等等…
更多Grafana Databoard等你去探索!

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值