golang基于eBPF实现TCP网络监控与分析插件tcpdog的使用

Golang基于eBPF实现TCP网络监控与分析插件tcpdog的使用

概述

TCPDog是一个完整的解决方案,通过eBPF从Linux内核高效导出TCP统计信息,并将其存储到Elasticsearch或InfluxDB数据库中,包含Geo和ASN信息。它可以通过简单的yaml配置同时处理所有TCP跟踪点,并提供不同的自定义请求。

架构图

主要特性

  • 通过eBPF TCP跟踪点获取TCP socket统计信息
  • 同时支持所有TCP跟踪点
  • 在内核空间自定义TCP字段
  • 支持Elasticsearch、ClickHouse或InfluxDB作为数据存储
  • 通过gRPC或Kafka进行中央收集
  • 支持内核空间的采样和过滤
  • 通过Maxmind支持Geo和ASN信息

拓扑图

系统要求

  • Linux内核版本4.16及以上
  • Libbcc

安装与使用示例

基本使用示例

package main

import (
	"context"
	"log"
	"time"

	"github.com/mehrdadrad/tcpdog/config"
	"github.com/mehrdadrad/tcpdog/ebpf"
	"github.com/mehrdadrad/tcpdog/egress"
)

func main() {
	// 加载配置文件
	cfg, err := config.Load("config.yaml")
	if err != nil {
		log.Fatal(err)
	}

	// 初始化eBPF
	bpf, err := ebpf.New(cfg)
	if err != nil {
		log.Fatal(err)
	}
	defer bpf.Close()

	// 初始化输出插件(如Elasticsearch)
	egress, err := egress.New(cfg)
	if err != nil {
		log.Fatal(err)
	}

	// 创建上下文
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	// 启动监控
	go bpf.Start(ctx)

	// 处理数据
	for {
		select {
		case <-ctx.Done():
			return
		case data := <-bpf.Chan():
			// 发送数据到输出插件
			if err := egress.Send(data); err != nil {
				log.Printf("发送数据失败: %v", err)
			}
		default:
			time.Sleep(1 * time.Second)
		}
	}
}

配置示例 (config.yaml)

ebpf:
  tracepoints:
    - tcp:tcp_probe
    - tcp:tcp_retransmit_skb
  fields:
    - RTT
    - AdvMSS
    - TotalRetrans
    - SAddr
    - DAddr
    - DPort
    - LPort
    - BytesReceived
    - BytesSent
  sampling: 1

egress:
  type: elasticsearch
  config:
    hosts:
      - "http://localhost:9200"
    index: "tcpdog-%{+2006.01.02}"
    flush_interval: 10s
    geo:
      enabled: true
      path: "/usr/share/GeoIP/GeoLite2-City.mmdb"
    asn:
      enabled: true
      path: "/usr/share/GeoIP/GeoLite2-ASN.mmdb"

数据输出示例

JSON Lines格式输出

[RTT,AdvMSS,TotalRetrans,SAddr,DAddr,DPort,LPort,BytesReceived,BytesSent,timestamp]
[172,1460,0,"10.0.2.15","103.17.108.173",80,0,456,73,1612298721]
[55,1460,0,"10.0.2.15","187.141.67.60",80,0,389,74,1612298722]
[140,1460,0,"10.0.2.15","154.118.230.171",443,0,5209,551,1612298723]
[118,1460,0,"10.0.2.15","88.204.157.165",443,0,4445,514,1612298724]
[8,1460,0,"10.0.2.15","47.254.92.5",80,0,760,70,1612298731]
[1,1460,0,"10.0.2.15","184.51.206.209",443,0,4820,577,1612298735]
[238,1460,0,"10.0.2.15","164.100.61.151",80,0,141,71,1612298737]
[171,1460,0,"10.0.2.15","77.238.121.220",80,0,158,74,1612298742]

Kibana可视化示例

Kibana地图视图

Kibana表格视图

许可证

该项目使用MIT许可证,请阅读LICENSE文件。

贡献

欢迎任何形式的贡献,请按照以下步骤进行:

  1. 在github.com上fork该项目
  2. 创建一个新的分支
  3. 将更改提交到新分支
  4. 发送pull请求

更多关于golang基于eBPF实现TCP网络监控与分析插件tcpdog的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang基于eBPF实现TCP网络监控与分析插件tcpdog的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


基于eBPF的TCP网络监控与分析工具tcpdog

tcpdog是一个基于eBPF技术的TCP网络监控与分析工具,它能够高效地捕获和分析TCP网络流量,提供详细的连接统计和性能指标。

tcpdog简介

tcpdog利用Linux内核的eBPF功能,无需修改内核代码即可实现对TCP连接的监控,具有以下特点:

  • 低开销:在内核空间进行数据过滤和处理
  • 高精度:能够捕获微秒级的TCP事件
  • 丰富指标:提供RTT、重传、窗口大小等关键指标

安装与依赖

首先确保系统满足以下要求:

  • Linux内核版本 >= 4.9
  • 已安装LLVM和clang
  • 已安装libbpf和BPF Compiler Collection (BCC)
# 安装依赖
sudo apt-get install -y make gcc libelf-dev clang llvm libbpf-dev bpfcc-tools

基本使用示例

以下是使用tcpdog的基本示例代码:

package main

import (
	"fmt"
	"os"
	"os/signal"
	"syscall"

	"github.com/mehrdadrad/tcpdog"
)

func main() {
	// 创建tcpdog配置
	cfg := tcpdog.Config{
		Fields: []string{"saddr", "daddr", "sport", "dport", "rtt", "retrans"},
		EBPF: tcpdog.EBPFConfig{
			Interface: "eth0",
			Filter:    "port 80 or port 443",
		},
	}

	// 初始化tcpdog
	td, err := tcpdog.New(cfg)
	if err != nil {
		fmt.Printf("Failed to initialize tcpdog: %v\n", err)
		return
	}
	defer td.Close()

	// 创建通道接收TCP事件
	ch := make(chan map[string]interface{}, 100)
	go td.Start(ch)

	// 设置信号处理
	sig := make(chan os.Signal, 1)
	signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM)

	// 处理TCP事件
	for {
		select {
		case m := <-ch:
			fmt.Printf("TCP Event: %+v\n", m)
		case <-sig:
			fmt.Println("Received signal, exiting...")
			return
		}
	}
}

高级功能实现

1. 自定义BPF程序

// 自定义BPF程序示例
const customBPF = `
#include <uapi/linux/ptrace.h>
#include <net/sock.h>
#include <bcc/proto.h>

BPF_HASH(stats, u32);

int trace_tcp_retrans(struct pt_regs *ctx, struct sock *sk) {
    u32 pid = bpf_get_current_pid_tgid();
    u64 *count, zero = 0;
    
    count = stats.lookup_or_init(&pid, &zero);
    (*count)++;
    
    return 0;
}
`

cfg := tcpdog.Config{
    EBPF: tcpdog.EBPFConfig{
        CustomProg: customBPF,
    },
}

2. 性能指标聚合

// 聚合统计示例
type TCPStats struct {
    Count      int
    TotalRTT   time.Duration
    Retrans    int
}

stats := make(map[string]*TCPStats)

for m := range ch {
    key := fmt.Sprintf("%s:%d->%s:%d", 
        m["saddr"], m["sport"], m["daddr"], m["dport"])
    
    if _, ok := stats[key]; !ok {
        stats[key] = &TCPStats{}
    }
    
    stats[key].Count++
    stats[key].TotalRTT += time.Duration(m["rtt"].(uint64)) * time.Microsecond
    stats[key].Retrans += m["retrans"].(int)
    
    // 定期打印统计
    if stats[key].Count%100 == 0 {
        avgRTT := stats[key].TotalRTT / time.Duration(stats[key].Count)
        fmt.Printf("Connection %s: AvgRTT=%v, Retrans=%d\n", 
            key, avgRTT, stats[key].Retrans)
    }
}

实际应用场景

1. 网络延迟分析

// 高延迟连接检测
highLatencyThreshold := 100 * time.Millisecond

for m := range ch {
    rtt := time.Duration(m["rtt"].(uint64)) * time.Microsecond
    if rtt > highLatencyThreshold {
        fmt.Printf("High latency detected: %s:%d->%s:%d RTT=%v\n",
            m["saddr"], m["sport"], m["daddr"], m["dport"], rtt)
    }
}

2. 重传率监控

// 计算重传率
type ConnRetrans struct {
    TotalPackets int
    Retrans      int
}

retransStats := make(map[string]*ConnRetrans)

for m := range ch {
    key := fmt.Sprintf("%s:%d->%s:%d", 
        m["saddr"], m["sport"], m["daddr"], m["dport"])
    
    if _, ok := retransStats[key]; !ok {
        retransStats[key] = &ConnRetrans{}
    }
    
    retransStats[key].TotalPackets++
    retransStats[key].Retrans += m["retrans"].(int)
    
    retransRate := float64(retransStats[key].Retrans) / float64(retransStats[key].TotalPackets)
    if retransRate > 0.05 { // 5%重传率阈值
        fmt.Printf("High retrans rate: %s %.2f%%\n", key, retransRate*100)
    }
}

性能优化建议

  1. 减少用户空间-内核空间数据传输

    • 只收集必要的字段
    • 使用BPF聚合数据后再传递到用户空间
  2. 合理设置缓冲区大小

    cfg := tcpdog.Config{
        EBPF: tcpdog.EBPFConfig{
            PerfBufferSize: 128, // 每CPU缓冲区页数
            PollTimeout:    100, // 毫秒
        },
    }
    
  3. 使用批处理处理事件

    // 批处理示例
    const batchSize = 100
    var batch []map[string]interface{}
    
    for m := range ch {
        batch = append(batch, m)
        if len(batch) >= batchSize {
            processBatch(batch)
            batch = batch[:0]
        }
    }
    

总结

tcpdog结合eBPF技术为Golang开发者提供了强大的TCP网络监控能力。通过本文的示例,您可以快速实现TCP连接监控、性能分析以及网络问题诊断等功能。eBPF的高效性和灵活性使其成为现代网络监控的理想选择,而Golang的简洁语法和强大并发模型则让开发这类工具变得更加容易。

回到顶部