Prometheus 教程

Prometheus 服务发现

服务发现,英文全称 Service Discovery,简称 SD

Prometheus 提供通用 HTTP 服务发现功能,使其能够通过 HTTP 端点发现目标(要监控的目标,如:mysql、redis 等)。HTTP 服务发现是对已经支持的服务发现机制的补充,也是基于文件的服务发现的替代方案。

Prometheus 的 HTTP 服务发现是一种动态发现目标主机上监控样本数据(metrics)的机制。Prometheus 通过这种方式能够自动发现集群中的新端点,并将它们加入到监控配置中。服务发现模块专门负责发现需要监控的目标采集点(target)信息,包括协议(scheme)、主机地址和端口(instance)、请求路径(metrics_path)、请求参数(params)等。Prometheus 通过这些信息构建出一个完整的 HTTP 请求,并定时通过 pull 方式去目标采集点拉取监控样本数据。

这种服务发现机制的出现主要是为了解决静态配置方式的不足。在静态配置方式下,如果集群中增加了新的节点或组件,需要手动修改 Prometheus 的配置,并重启 Prometheus,这显然不够灵活和高效。而通过 HTTP 服务发现,Prometheus 能够自动感知到集群中的变化,并动态地更新监控目标列表,从而实现对集群的全面监控。

基于文件与 HTTP 的服务发现比较

下面的表格比较了我们的两种通用服务发现实现:

比较项

基于文件

基于 HTTP

基于事件

是的,通过 inotify

更新频率

及时更新,因为是基于事件监听

刷新间隔

格式

Yaml 或 JSON

JSON

传输方式

本地文件

HTTP/HTTPS

安全性

基于文件的安全性

TLS, Basic auth, Authorization header, OAuth2

什么是 inotify?

Inotify是Linux核心子系统之一,它允许监控程序打开一个独立文件描述符,并针对事件集监控一个或者多个文件。这些事件可以包括文件的打开、关闭、移动/重命名、删除、创建以及属性改变等。Inotify是一个非常灵敏且高效的工具,比传统的cron任务轮询方式要高效得多。

HTTP 服务发现端点的要求

如果你要实现 HTTP SD 端点,需要注意以下几点要求:

(1)HTTP SD 端点的响应,Prometheus 服务将原样读取和使用。在每个刷新间隔(默认值:1 分钟),Prometheus 会向 HTTP SD 端点执行 GET 请求。GET 请求包含一个带有刷新间隔的 X-Prometheus-Refresh-Interval-Seconds 请求头。

(2)HTTP SD 端点必须返回 HTTP 200 状态,HTTP 标头 Content-Type 必须是 application/json。响应必须是 UTF-8 字符格式。如果不传输目标,也必须发送 HTTP 200 状态,并附带一个空列表 []。注意:目标列表是无序的。

(3)Prometheus 会缓存目标列表。如果在获取更新的目标列表时发生错误,Prometheus 会继续使用当前缓存的目标列表,缓存的目标列表在重启时会丢失。prometheus_sd_http_failures_total 计数器指标跟踪刷新失败的次数。

(4)每次抓取都必须返回整个目标列表,不支持增量更新。因为,Prometheus 实例不发送主机名,HTTP SD 端点无法知道 HTTP SD 请求是否是重启后的第一个请求。

(5)HTTP SD 端点的 URL 不是保密的,任何人都可见。因此,身份验证和任何 API 密钥都应通过适当的身份验证机制传递。Prometheus 支持 TLS 身份验证、基本身份验证(Basic auth)、OAuth2 和 Authorization 请求头。

HTTP_SD 格式

[
  {
    "targets": [ "<host>", ... ],
    "labels": {
      "<labelname>": "<labelvalue>", ...
    }
  },
  ...
]

示例:

[
    {
        "targets": ["10.0.10.2:9100", "10.0.10.3:9100", "10.0.10.4:9100", "10.0.10.5:9100"],
        "labels": {
            "__meta_datacenter": "london",
            "__meta_prometheus_job": "node"
        }
    },
    {
        "targets": ["10.0.40.2:9100", "10.0.40.3:9100"],
        "labels": {
            "__meta_datacenter": "london",
            "__meta_prometheus_job": "alertmanager"
        }
    },
    {
        "targets": ["10.0.40.2:9093", "10.0.40.3:9093"],
        "labels": {
            "__meta_datacenter": "newyork",
            "__meta_prometheus_job": "alertmanager"
        }
    }
]

仔细观察上面配置,再和配置文件进行一下对比:

# 抓取配置,其中包含一个要抓取的端点:
# 在这里,它就是 Prometheus 本身
scrape_configs:
  # 定义了一个名为 "prometheus" 的 job,它将在 Prometheus 服务发现中可用。
  # 作业名称作为标签 'job=<job_name>' 添加到从该配置中抓取的任何时间序列中。
  - job_name: "prometheus"

    # 指定了要抓取的目标,这里是 Prometheus 服务器自身,也可以指定 Exporter
    # metrics_path 默认为"/metrics",scheme 默认为 "http"
    static_configs:
      - targets: ["localhost:9090"]

是不是很像,如果将 HTTP SD 端点的返回值配置到 prometheus.yml 配置文件,应该如下:

...
scrape_configs:
  - job_name: "node"
    static_configs:
      - targets: ["10.0.10.2:9100", "10.0.10.3:9100", "10.0.10.4:9100", "10.0.10.5:9100"]      
...

注意:再上面的 HTTP SD 端点返回的示例中,存在  __meta_prometheus_job 和 __meta_datacenter 元数据标签(meta labels),它们通常与服务发现(Service Discovery)结合使用。Prometheus 使用服务发现来自动发现和监控目标。这些目标可能是服务、主机或其他需要监控的资源。其中:

  • __meta_prometheus_job:用于标识 Prometheus 作业(job),它表示 Prometheus 作业的名称。

  • __meta_datacenter:用于标识数据中心(datacenter)或类似的概念。在某些服务发现机制中,特别是像 Consul 这样的分布式配置和服务发现系统中,目标可能分布在不同的数据中心。__meta_datacenter 标签允许 Prometheus 在服务发现过程中获取目标所在的数据中心信息,并将其作为标签添加到时间序列中。这对于跨多个数据中心的监控和警报非常有用,因为它允许 Prometheus 根据数据中心来过滤、聚合或区分时间序列数据。

示例:自定义 HTTP SD 服务

(1)假如在 192.168.0.32 主机的 9100 端口上开启 Exporter 服务,如下图:

编写 http 服务发现

(2)创建一个简单的 Spring Boot 项目,点击查看如何创建 Spring Boot 项目

(3)创建一个 Controller,用来返回目标列表,源码如下:

package com.hxstrive.springboot.prometheus;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Prometheus HTTP SD 服务发现
 * @author hxstrive.com
 */
@Controller
@RequestMapping("/prometheus/sd")
public class PrometheusSdController {

    /**
     * 返回格式:
     * [
     *    {
     *         "targets": ["10.0.40.2:9093", "10.0.40.3:9093"],
     *         "labels": {
     *             "__meta_datacenter": "newyork",
     *             "__meta_prometheus_job": "alertmanager"
     *         }
     *     }
     * ]
     * @return
     */
    @GetMapping("/targets")
    @ResponseBody
    public Object targets() {
        List<Map<String,Object>> retList = new ArrayList<>();
        // 添加一个目标
        retList.add(new HashMap<String,Object>(){
            {
                put("targets", new String[]{"192.168.0.32:9100"});
                put("labels", new HashMap<String,String>(){
                    {
                        put("__meta_datacenter", "localhost");
                        put("__meta_prometheus_job", "remote-host");
                    }
                });
            }
        });
        return retList;
    }

}

启动 Spring Boot 项目,使用浏览器访问 http://localhost:8080/prometheus/sd/targets 地址,输出如下图:

编写 http 服务发现

(4)配置 Prometheus,打开本地的 prometheus.yml 文件,修改配置:

...
scrape_configs:
  ...
  # 我的 HTTP 服务发现作业
  - job_name: "my-sd-job"
    http_sd_configs:
        - url: 'http://localhost:8080/prometheus/sd/targets'
          refresh_interval: 5s
...

(5)重启 Prometheus 服务,访问 http://localhost:9090/targets?search= 地址,如下图:

编写 http 服务发现

说说我的看法
全部评论(
没有评论
关于
本网站专注于 Java、数据库(MySQL、Oracle)、Linux、软件架构及大数据等多领域技术知识分享。涵盖丰富的原创与精选技术文章,助力技术传播与交流。无论是技术新手渴望入门,还是资深开发者寻求进阶,这里都能为您提供深度见解与实用经验,让复杂编码变得轻松易懂,携手共赴技术提升新高度。如有侵权,请来信告知:hxstrive@outlook.com
公众号