Prometheus+Loki+Grafana 打造SpringCloud微服务监控面板

前言

最近研究微服务的服务健康监控,发现大多是集成Spring Boot Admin,优点是配置简单比较轻量化,缺点包含:(1) 界面比较简单,且不那么美观; (2) 它的实时查看日志功能是读取服务器上的日志文件,那当我的微服务与admin-server所在的服务不处于同一服务器上时就读不到了,换言之就是对分布式支持较差。 (3) 监控到的服务状态只能维持较短时间段,难以回溯较早的信息。

搜索比对市面上解决方案最终采用 Prometheus + Loki + Grafana这套方案来集成一下到SpringCloud,实现更加美观且功能更全面的监控中心。看起来用到的东西比较多,但是他们是相辅相成的,简单来说:

Prometheus和是一个开源的系统监控和警报工具,用于收集和存储应用程序和系统的时间序列数据。
Loki是一个水平可扩展,高可用性,多租户的日志聚合系统,受到Prometheus的启发。它的设计非常经济高效且易于操作,因为它不会为日志内容编制索引,而是为每个日志流编制一组标签。官方介绍说到:Like Prometheus, but for logs。
Grafana是一款开源的数据可视化工具,使用Grafana可以非常轻松的将数据转成图表的展现形式来做到数据监控以及数据统计。且Grafana内置了对PrometheusLoki的支持,可以只需几步配置就把他们收集到的信息转化为好看的图表进行展现。

以下为集成后效果图:

集成过程中踩了不少坑,也搜索了很多文档,在此整合一下,希望需要用到的朋友能够少走些弯路。

环境说明

本次集成属于尝鲜性质,使用最新版本的开源组件集成到现有项目上。注册中心使用Nacos

raw 复制代码
# 开源组件版本
grafana latest
loki latest
prometheus latest

# 项目相关
SpringCloud: 2021.0.3
SpringBoot: 2.7.1
JDK: 1.8
Nacos: 2.2.0

任务拆解

经过以上分析,本次集成过程将按照以下几步步骤进行:

  1. 安装部署

  2. grafana集成 SpringCloud实现监控服务信息,并配合Nacos进行服务发现。

  3. loki集成微服务收集日志。

  4. 配置grafana,以图表方式展示服务信息和服务日志。

集成过程

安装部署

本次需要到的开源组件有三个:grafana, loki, prometheus。每一个官网都提供了至少两种安装部署方式:二进制文件安装和 docker部署, 这里直接贴出笔者经过整合的docker-compose配置文件,一步搞定,省去繁琐的配置过程,如果想要以其他方式安装部署,可以参考官方文档或者搜索其他博客。

grafana+loki 官方文档 | grafana.com/docs/loki/v...

prometheus 官方文档 | prometheus.io/docs/promet...

查看后不难发现官方也是推荐使用docker方式进行部署,下面我们使用docker-compose来快速部署。(需要服务器安装好dockerdocker-compose,不会装的可以搜下其他博客)。

  1. 找一个路径,准备存放docker-compose.yaml配置文件,执行命令:
shell 复制代码
vim docker-compose.yaml

打开vim编辑器后粘贴一下内容进去:

yml 复制代码
version: "3"

networks:
  loki:

services:
  loki:
    image: grafana/loki:latest
    ports:
      - "3100:3100"
    command: -config.file=/etc/loki/local-config.yaml
    networks:
      - loki

  promtail:
    image: grafana/promtail:latest
    volumes:
      - /var/log:/var/log
    command: -config.file=/etc/promtail/config.yml
    networks:
      - loki

  grafana:
    environment:
      - GF_PATHS_PROVISIONING=/etc/grafana/provisioning
      - GF_AUTH_ANONYMOUS_ENABLED=true
      - GF_AUTH_ANONYMOUS_ORG_ROLE=Admin
    entrypoint:
      - sh
      - -euc
      - |
        mkdir -p /etc/grafana/provisioning/datasources
        cat <<EOF > /etc/grafana/provisioning/datasources/ds.yaml
        apiVersion: 1
        datasources:
        - name: Loki
          type: loki
          access: proxy
          orgId: 1
          url: http://loki:3100
          basicAuth: false
          isDefault: true
          version: 1
          editable: false
        EOF
        /run.sh
    image: grafana/grafana:latest
    ports:
      - "3000:3000"
    networks:
      - loki

  prometheus:
    image: prom/prometheus:latest
    container_name: prometheus
    hostname: prometheus
    restart: always
    volumes:
        - /home/apps-docker/prometheus/config/prometheus.yml:/etc/prometheus/prometheus.yml
    ports:
        - "9090:9090"
    networks:
        - loki

粘贴完后保存文件内容。 可以看到该compose文件内包含了四个服务的整合:loki, promtail, grafana, prometheus,前三个是loki官网提供出来的配置文件里内置的,我只修改了版本号,需要注意promtailprometheus容易造成混淆,promtail是配合loki使用的,其配置文件格式和prometheus极其有很多相似的地方,他是一个为loki主动收集日志的组件,其理念也类似prometheus, 但是我们集成使用的方式是通过微服务调用loki的日志上传接口,并不需要他去主动收集日志,所以这次是没有用到的,但可以先安装上备用;prometheus部分的配置是我从其他博客参考后整理到里面的,简化了配置,但是其中用到了一个映射:

这是因为我们需要在安装prometheus后修改一部分配置文件,映射到服务器上比较方便,这个路径要改成你自己存放该配置文件的路径。也就是接下来要做的事:

找一个路径,预备存放prometheus.yml配置文件,然后输入:

shell 复制代码
vim prometheus.yml

粘贴如下内容进去:

vim 复制代码
# my global config
global:
  scrape_interval: 15s # Set the scrape interval to every 15 seconds. Default is every 1 minute.
  evaluation_interval: 15s # Evaluate rules every 15 seconds. The default is every 1 minute.
  # scrape_timeout is set to the global default (10s).

# Alertmanager configuration
alerting:
  alertmanagers:
    - static_configs:
        - targets:
          # - alertmanager:9093

# Load rules once and periodically evaluate them according to the global 'evaluation_interval'.
rule_files:
  # - "first_rules.yml"
  # - "second_rules.yml"

# A scrape configuration containing exactly one endpoint to scrape:
# Here it's Prometheus itself.
scrape_configs:
  # The job name is added as a label `job=<job_name>` to any timeseries scraped from this config.
  - job_name: "prometheus"
    # metrics_path defaults to '/metrics'
    # scheme defaults to 'http'.
    static_configs:
      - targets: ["localhost:9090"]

保存后修改上面的docker-compose.yaml内的映射路径为该文件的路径。

然后回到docker-compose.yaml所在目录,执行:

shell 复制代码
docker-compose -f docker-compose.yaml up

即可一键安装loki + promtail + grafana + prometheus,看到有日志打印等待片刻后可以按ctrl + Z退出,然后输入以下命令查看服务情况:

shell 复制代码
docker ps

观察到四个容器在运行即为安装部署成功,且服务都已经成功启动。

其中promtail的容器如果不使用可以把它停掉。

Prometheus集成 SpringCloud监控服务信息

SpringBoot开放监控信息查询接口

  1. 选择一个测试用的SpringBoot服务,在pom里添加如下依赖:
yml 复制代码
<dependency>
	<groupId>org.mybatis.spring.boot</groupId>
	<artifactId>spring-boot-starter-actuator</artifactId>
	<version>2.2.1.RELEASE</version>
</dependency>
<dependency>
	<groupId>io.micrometer</groupId>
	<artifactId>micrometer-registry-prometheus</artifactId>
	<version>1.3.1</version>
</dependency>
  1. 然后配置yml文件添加如下内容:
yml 复制代码
management:
  endpoints:
    web:
      exposure:
        include: '*'
  metrics:
    tags:
      application: ${spring.application.name}

启动服务,访问如下路径:

raw 复制代码
http://ip:端口/actuator/prometheus

如果能看到类似如下结果,说明接口开放成功:

Prometheus配置收集服务信息

  1. prometheus.yml配置文件最下面添加如下配置:
yml 复制代码
  - job_name: "springboot"
    metrics_path: '/actuator/prometheus'
    static_configs:
      - targets: ["ip:port"]

ip和端口处改为你实际启动的SpringBoot服务的信息,即可使prometheus定时去采集服务信息。

  1. 访问 http://{prometheus所在的服务器的ip}:9090/targets,在列表内看到自己启动的服务即为成功,点击列表里的链接同样可以看到SpringBoot开放的接口返回的内容。

优化配置,集成Nacos服务发现

通过上面简单两步已经实现了prometheus与SpringBoot的集成,但是我们的目标是监控微服务集群,如果采用上面的配法,需要在static_configs下的targets数组配置里手动添加各个微服务节点的ip和端口,每次有新的微服务添加都需要手动修改配置文件然后重启prometheus,这显然不靠谱。那么区别于静态服务注册,prometheus还提供了数种服务发现方案,包含通过文件、DNS、k8s、consul注册中心来动态发现服务的方式,但是遗憾的是,我们项目中所采用的ErukaNacos不在其列,而好消息是,Eruka和Nacos本身有和consul注册中心类似的接口,只要对Eruka或Nacos获取的数据进行改造,就可以伪装成 consul与prometheus对接。这部分内容已有大佬研究实现,可参考博客:

CSDN博客| blog.csdn.net/LCBUSHIHAHA...

github:nacos适配 | github.com/weixiaohui-...

github:eureka适配 | github.com/twinformati...

下面以使用Nacos为例,介绍接入方法:

在以上步骤的基础上,在gateway的pom里添加如下引用:

xml 复制代码
    <dependency>
        <groupId>io.github.chen-gliu</groupId>
        <artifactId>nacos-consul-adapter</artifactId>
        <version>version</version>
    </dependency> 

然后修改prometheus.yml配置文件,将之前配置的静态job部分修改为基于consul服务发现的如下配置:

yml 复制代码
 - job_name: 'consul-service-discovery'
    metrics_path: '/actuator/prometheus'
    consul_sd_configs:
    - server: gateway服务ip:端口
      services: []

server部分需要改成你的项目中的网关服务的运行ip和端口,配置完成后重启prometheus服务即可。之后可以多添加几个SpringBoot节点上来,通过http://{prometheus所在的服务器的ip}:9090/targets查看是否注册成功。

以下为prometheus.yml配置文件完整示例,仅供参考:

yaml 复制代码
# my global config
global:
  scrape_interval: 15s # Set the scrape interval to every 15 seconds. Default is every 1 minute.
  evaluation_interval: 15s # Evaluate rules every 15 seconds. The default is every 1 minute.
  # scrape_timeout is set to the global default (10s).

# Alertmanager configuration
alerting:
  alertmanagers:
    - static_configs:
        - targets:
          # - alertmanager:9093

# Load rules once and periodically evaluate them according to the global 'evaluation_interval'.
rule_files:
  # - "first_rules.yml"
  # - "second_rules.yml"

# A scrape configuration containing exactly one endpoint to scrape:
# Here it's Prometheus itself.
scrape_configs:
  # The job name is added as a label `job=<job_name>` to any timeseries scraped from this config.
  - job_name: "prometheus"
    # metrics_path defaults to '/metrics'
    # scheme defaults to 'http'.
    static_configs:
      - targets: ["localhost:9090"]
  # consul service discovery
  - job_name: "consul-service-discovery"
    metrics_path: '/actuator/prometheus'
    consul_sd_configs:
    - server: 192.168.20.80:8080
      services: []

SpringCloud集成Loki上传日志

SpringCloud集成Loki实质上是将LokiLogback进行集成,在产生日志时调用Loki的push接口,将微服务日志上传到Loki服务器,故而可以实现分布式日志监控。

SpringBoot引入loki-logback-appender

这个包的引入和配置方式根据Java环境有所不同,可参考官方文档:

loki4j logback | loki4j.github.io/loki-logbac...

以下以Java8为例,介绍引入步骤。

  1. 选择一个测试微服务,在pom内引入如下依赖:
xml 复制代码
<dependency>
    <groupId>com.github.loki4j</groupId>
    <artifactId>loki-logback-appender-jdk8</artifactId>
    <version>1.4.2</version>
</dependency>
<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
    <version>4.5.14</version>
</dependency>
  1. 修改或创建项目的logback**.xml文件, 添加如下片段:

红框圈出的是与Loki相关的配置,需要添加到本来的配置文件代码中,这里除常规内容外,我多配置打印了服务器的IP和端口,以及服务名称,为的是与prometheus保持一致,使得通过服务名称IP:端口两个指标,可以找到指定微服务节点的服务信息和日志,其中服务名称通过spring.application.name配置项获取,端口通过server.port项获取,如果原服务缺失这俩配置项,要记得规范配置。此外,还添加了通过loki.enableloki.url参数来动态控制是否启用Loki上传以及根据不同环境可配置不同的Loki地址的功能。由于这部分使用了if标签,需要添加额外的pom引用:

xml 复制代码
<!--logback语法扩展-->
<dependency>
    <groupId>org.codehaus.janino</groupId>
    <artifactId>janino</artifactId>
    <version>3.0.6</version>
</dependency>

logback配置信息(按图示添加):

xml 复制代码
<!-- loki日志上传 -->
<springProperty name="serverIP" scope="context" source="spring.cloud.client.ip-address" defaultValue="0.0.0.0"/>
<springProperty name="serverPort" scope="context" source="server.port" defaultValue="0000"/>
<springProperty name="appName" scope="context" source="spring.application.name"/>
<springProperty name="lokiEnable" scope="context" source="loki.enable"/>
<springProperty name="lokiUrl" scope="context" source="loki.url"/>

<property name="APP_NAME" value="${appName}"/>
<property name="LOKI_URL" value="${lokiUrl}"/>

<if condition='Boolean.valueOf(property("lokiEnable"))'>
    <then>
        <appender name="LOKI" class="com.github.loki4j.logback.Loki4jAppender">
            <http class="com.github.loki4j.logback.ApacheHttpSender">
                <url>${LOKI_URL}/loki/api/v1/push</url>
            </http>
            <format>
                <label>
                    <pattern>app=${APP_NAME},host=${HOSTNAME},instance=${serverIP}:${serverPort}, level=%level</pattern>
                </label>
                <message>
                    <pattern>l=%level h=${HOSTNAME} i=${serverIP}:${serverPort} c=%logger{20} t=%thread | %msg %ex</pattern>
                </message>
                <sortByTime>true</sortByTime>
            </format>
        </appender>
    </then>
</if>
<!-- 日志输出级别 -->
<root level="INFO">
    <appender-ref ref="STDOUT"/>
    <appender-ref ref="INFO"/>
    <appender-ref ref="ERROR"/>
    <if condition='Boolean.valueOf(property("lokiEnable"))'>
        <then>
            <appender-ref ref="LOKI"/>
        </then>
    </if>
</root>
  1. SpringBoot服务的yml配置文件里添加如下配置项:
yml 复制代码
# loki配置
loki:
  url: http://192.168.20.84:3100
  enable: true

url部分的IP改为你自己的loki服务所在的服务器IP,然后启动服务。正常上传的话是不会打印成功日志的,但是我测试发现,当在自己本机启动SpringBoot服务时,只上传了几行后就会报错上传失败,目前还不知道原因:

所以当你看到以上报错时,尽快将服务打包到linux服务器上,等待完成后续步骤。

Grafana展示监控信息

前置工作已准备完毕,接下来我们使用Grafana来配置展示服务信息和日志信息。

访问http://grafana服务器ip:3000/login,进入登录页,默认用户名密码都是admin,首次登录会引导进行密码修改。

Grafana接入Prometheus,展示服务信息

  1. 点击设置处的Datasource,添加数据源。

修改IP为你的prometheus服务器IP,点击最底下的Save & Test,出现下面提示就成功了。

  1. 导入模板展示JVM信息。

Grafana提供允许开发者上传优秀模板,在官网可以挑选模板:

arduino 复制代码
Grafana 模板 | https://grafana.com/grafana/dashboards/

记录你中意的模板ID,本文按理使用的模板ID是12856。在Grafana内进行导入。

修改你想要的面板名称,数据源选择刚才添加的Prometheus数据源,点击Import即可导入。

导入后大致长这样,有很全的JVM监控信息,可以手动调整每个区域位置和大小。

但是还没有服务日志,下面我们引入Loki进行展示。

Grafana接入Loki,打印服务日志

  1. 添加Loki数据源

添加方式类似上面的,不多做赘述。

这里内置一个Loki数据源了,我们直接修改他。

  1. Loki日志调试

测试成功后,我们点击Explore调试一下:

如图为调试面板,选择一个比较久的时间范围,然后查询语句按照示例查询下你注册的服务,点击Run query能查出来对应日志即为成功。

这里页面有个BUG,这个查询语句框输入字符时经常失焦,建议在外面编辑器编辑好后粘贴进来。

  1. 以Panel形式添加到监控面板。

返回首页,找到之前添加的JVM监控面板。

先添加一个折叠行。

然后把这一个Row拖到你想要展示日志的地方去。然后再添加一个日志Panel

参考下面图片对该Panel进行配置后,点击右上角Apply应用。

然后把改日志面板调整大小,拖动到刚才添加的折叠行下面,刷新页面就可以整合进去。整体效果如图:

  1. Loki配置调整

如果你的日志量比较大,可能会触发Loki的数据传输限制,会上传日志出错以及查不到日志,这个时候需要修改下Loki的配置后重启服务。但是我们部署的时候,loki配置是在容器内部的,路径如下:

这里可以先把配置文件从容器内部复制出来,修改后再复制回去。

(1) docker ps :查看docker容器id

(2) 复制到服务器

sudo docker cp 容器id:/etc/loki/local-config.yml /home/app-dockers/loki/loki-config.yml

(3) 编辑配置文件

yml 复制代码
grpc_server_max_recv_msg_size: 104857600
grpc_server_max_send_msg_size: 104857600

(4) 复制回服务器

sudo docker cp /home/app-dockers/loki/loki-config.yml 容器id:/etc/loki/local-config.yml

(5) 重启容器

docker restart 容器id

配置项整合优化

看到效果以后,回顾一下集成过程还有哪些可优化之处。在集成Promethus及Loki时,需要每个微服务都引入一些jar包,可以统一抽到项目上层pom中;对于每个微服务都需要添加的配置,可以在nacos内创建一个公共配置文件存储,诸如此类优化,都会使你的项目在一次次集成后不至于臃肿。

结语

到这里整套监控中心就算集成完成了,在面对分布式集群部署时,可以通过服务名称实例的IP端口来监控到具体机器节点上的JVM信息和日志。

而这只是Grafana这个组件的冰山一角,你可以学习GrafanaLoki的查询语句语法以及配置方式实现更加炫酷易用的Dashbord,还可以上传到官方模板供他人使用, 总之扩展上限还是比较高的; 不仅Grafana还有待探索,Prometheus除了监控服务外,还可配置服务异常告警; Loki除了收集SpringBoot日志,还可以收集docker日志,以及通过多种查询语句快速定位日志。

这些工具功能虽强大,在初步使用过程也发现了一些不足,如Loki编写查询语句失焦很影响体验,日志量较大时查询反应较慢等。同时我们也应当思考,这套组合在带来便利的同时,代价是什么。定时上传日志会不会影响线上服务性能;Loki服务器应当采取怎样的配置,保留多长时间的日志文件为佳,等等。本文所介绍的只是入门级别的简单配置,如果想要上线使用,应该是需要钻研下每个组件更多的配置项,进行更多的配置优化的。

全文较长,图片也比较多,耐心看完的朋友相信会有所收获,同时也欢迎大家分享交流使用过程中发生的问题及解决方案。我本人也是刚接触到这些开源方案,文章中错误及不足之处也请不吝赐教。

相关推荐
黄俊懿3 小时前
【架构师从入门到进阶】第一章:架构设计基础——第五节:架构演进(缓存到微服务)
分布式·后端·缓存·微服务·架构·系统架构·架构设计
Mrlibai14 小时前
【软考】系统分析师第二版 新增章节 第20章微服务系统分析与设计
微服务·架构·软件工程·系统分析师
susemm17 小时前
19. 架构重要需求
java·微服务·架构·软件架构
心勤则明17 小时前
SpringCloudAlibabaSidecar整合异构微服务
微服务·云原生·架构
未命名冀18 小时前
微服务day04
java·数据库·微服务
JDS_DIJ18 小时前
微服务相关问题
java·前端·微服务
掘金-我是哪吒2 天前
微服务mysql,redis,elasticsearch, kibana,cassandra,mongodb, kafka
redis·mysql·mongodb·elasticsearch·微服务
茶馆大橘2 天前
微服务系列六:分布式事务与seata
分布式·docker·微服务·nacos·seata·springcloud
玄明Hanko2 天前
微服务拆分的 “坑”:实战复盘与避坑指南
后端·spring cloud·微服务