【Prometheus】【Blackbox_Exporter】ICMP探测与性能监控

本文将通过Blackbox_Exporter的ICMP探测功能的源代码,逐步分析其各个部分的实现逻辑及其在实际应用中的作用。我们将从代码的基本结构入手,详细解释每一行的功能,并为你提供如何在实际环境中使用这一功能的思路。

目标与背景

这个函数 ProbeICMP 旨在通过发送ICMP请求包(Echo Request)并等待ICMP响应包(Echo Reply),来检测目标主机的连通性。代码利用了Go语言的标准库以及 prometheus 用于性能监控。

函数定义

func ProbeICMP(ctx context.Context, target string, module config.Module, registry *prometheus.Registry, logger *slog.Logger) (success bool)
  • ctx: 上下文对象,通常用于控制超时和取消操作。
  • target: 目标主机地址。
  • module: 配置模块,包含ICMP探测的相关参数。
  • registry: Prometheus监控注册表,用于记录和导出性能指标。
  • logger: 日志记录器,记录操作过程中的各种信息。

1. 定义局部变量

var (
    requestType     icmp.Type
    replyType       icmp.Type
    icmpConn        *icmp.PacketConn
    v4RawConn       *ipv4.RawConn
    hopLimitFlagSet bool = true

    durationGaugeVec = prometheus.NewGaugeVec(prometheus.GaugeOpts{
        Name: "probe_icmp_duration_seconds",
        Help: "Duration of icmp request by phase",
    }, []string{"phase"})

    hopLimitGauge = prometheus.NewGauge(prometheus.GaugeOpts{
        Name: "probe_icmp_reply_hop_limit",
        Help: "Replied packet hop limit (TTL for ipv4)",
    })
)
  • requestTypereplyType:分别用于存储请求和响应的ICMP类型。
  • icmpConn:存储用于发送和接收ICMP包的连接。
  • v4RawConn:IPv4原始连接,用于低级别的ICMP操作。
  • hopLimitFlagSet:标记是否成功设置了TTL(IPv4)或Hop Limit(IPv6)。
  • durationGaugeVec:Prometheus的计量向量,用于记录ICMP请求各阶段的时长。
  • hopLimitGauge:Prometheus的计量对象,用于记录目标主机回复包的Hop Limit。

2. 注册Prometheus监控指标

for _, lv := range []string{"resolve", "setup", "rtt"} {
    durationGaugeVec.WithLabelValues(lv)
}
registry.MustRegister(durationGaugeVec)
  • durationGaugeVec 记录三个阶段的时长:解析(resolve)、设置(setup)、往返时延(RTT)。
  • MustRegister 方法确保指标被成功注册到Prometheus注册表。

3. 解析目标地址并选择协议

dstIPAddr, lookupTime, err := chooseProtocol(ctx, module.ICMP.IPProtocol, module.ICMP.IPProtocolFallback, target, registry, logger)
if err != nil {
    logger.Error("Error resolving address", "err", err)
    return false
}
durationGaugeVec.WithLabelValues("resolve").Add(lookupTime)
  • chooseProtocol 函数决定是使用IPv4还是IPv6,并解析目标地址。如果解析失败,返回 false
  • 解析时间(lookupTime)记录到 durationGaugeVec 中。

4. 设置源IP地址

var srcIP net.IP
if len(module.ICMP.SourceIPAddress) > 0 {
    if srcIP = net.ParseIP(module.ICMP.SourceIPAddress); srcIP == nil {
        logger.Error("Error parsing source ip address", "srcIP", module.ICMP.SourceIPAddress)
        return false
    }
    logger.Info("Using source address", "srcIP", srcIP)
}
  • 如果用户在配置中指定了源IP地址,将其解析并使用;否则,使用默认的源地址。

5. 创建ICMP连接(IPv4/IPv6)

根据目标主机是IPv4还是IPv6,选择合适的方式创建ICMP连接。

对于IPv6:
icmpConn, err = icmp.ListenPacket("ip6:ipv6-icmp", srcIP.String())
对于IPv4:
icmpConn, err = icmp.ListenPacket("ip4:icmp", srcIP.String())
  • icmp.ListenPacket 创建ICMP连接。对于Linux和MacOS,可以使用未经授权的套接字来创建UDP连接,减少权限要求。

6. 构建ICMP请求包

body := &icmp.Echo{
    ID:   icmpID,
    Seq:  int(getICMPSequence()),
    Data: data,
}
wm := icmp.Message{
    Type: requestType,
    Code: 0,
    Body: body,
}
  • 构建ICMP回显请求(Echo Request)包,设置唯一的ID和序列号。
  • 通过 icmp.Message 类型构造请求消息。

7. 发送ICMP请求包

_, err = icmpConn.WriteTo(wb, dst)
  • 将构建好的ICMP请求包写入到套接字中并发送到目标地址。

8. 等待并接收ICMP响应包

n, cm, peer, err = icmpConn.IPv6PacketConn().ReadFrom(rb)
  • 等待接收ICMP响应包。
  • 如果收到的包和发送的包匹配,且目标地址与期望地址一致,则返回成功。

9. 设置和读取TTL或Hop Limit

在IPv4和IPv6中,TTL和Hop Limit分别用于表示数据包的跳数限制,这些信息对于网络诊断非常重要。

if cm != nil && hopLimitFlagSet {
    hopLimit = float64(cm.TTL)  // 对于IPv4
}
  • 通过设置控制消息来获取TTL或Hop Limit,并将其记录在Prometheus监控中。

10. 完整的ICMP探测逻辑

if bytes.Equal(rb[:n], wb) {
    durationGaugeVec.WithLabelValues("rtt").Add(time.Since(rttStart).Seconds())
    if hopLimit >= 0 {
        hopLimitGauge.Set(hopLimit)
        registry.MustRegister(hopLimitGauge)
    }
    logger.Info("Found matching reply packet")
    return true
}
  • 如果收到的响应包与发送的请求包相匹配,则计算往返时延(RTT)并记录TTL或Hop Limit。

总结

本文详细解析了一个Go语言实现的ICMP探测函数,通过使用Prometheus进行性能监控,能够监控请求的各个阶段(解析、设置、RTT)以及目标主机的TTL或Hop Limit。该函数在实际应用中非常有用,尤其是在网络故障排查、性能监控和自动化监控工具中。通过对代码的逐步分析,你可以更清晰地理解ICMP探测和性能监控的实现方式,以及如何根据自己的需求进行扩展和调整。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值