November 18, 2025

Лучшие практики трассировки производительности для Linux

Это перевод оригинальной статьи Expert Guide to BPF Performance Monitoring in Linux

Перевод сделан специально для телеграм-канала Мониторим ИТ. Подписывайтесь! Там еще больше полезных постов о мониторинге.

Подробные примеры кода для превосходной трассировки

Для эффективного профилирования использования CPU на работающем сервере Linux, незаменимым инструментом является perf. Приведённый ниже пример собирает данные для flame graph в течение 30 секунд, фиксируя стеки вызовов с целью выявления "горячих точек" в приложении или ядре:

sudo perf record -F 99 -a -g -- sleep 30
sudo perf script > out.perf
# To generate a flame graph, one would typically use Brendan Gregg's stackcollapse-perf.pl and flamegraph.pl scripts.
# For example:
# stackcollapse-perf.pl out.perf | flamegraph.pl > perf-flamegraph.svg

Для более глубокого анализа системных вызовов можно использовать strace или ltrace. При мониторинге критически важного сервиса понимание взаимодействия с системными вызовами даёт важный контекст. Ниже показано, как отследить системные вызовы, выполняемые процессом с определённым идентификатором (PID), и регистрировать их:

sudo strace -p <PID_OF_SERVICE> -o /var/log/service_strace.log -yy -f -T
# -p specifies the PID
# -o redirects output to a file
# -yy prints path for FDs and sockets
# -f traces child processes
# -T shows time spent in system calls

Этот вывод помогает диагностировать взаимоблокировки, проблемы с правами доступа к файлам или непредвиденные сетевые взаимодействия.

В средах Kubernetes агенты на основе eBPF обеспечивают контроль производительности узлов и контейнеров, без вмешательств в код приложения. С помощью DaemonSet можно развернуть агент трассировки на базе eBPF на всех узлах кластера. Ниже представлен манифест для развертывания гипотетического контейнера с агентом eBPF:

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: ebpf-tracing-agent
  namespace: kube-system
spec:
  selector:
    matchLabels:
      app: ebpf-tracing-agent
  template:
    metadata:
      labels:
        app: ebpf-tracing-agent
    spec:
      hostPID: true
      hostNetwork: true
      containers:
      - name: agent
        image: your_registry/ebpf-tracing-agent:latest
        securityContext:
          privileged: true
        volumeMounts:
        - name: sys-kernel-debug
          mountPath: /sys/kernel/debug
        - name: lib-modules
          mountPath: /lib/modules
        - name: usr-src
          mountPath: /usr/src
      volumes:
      - name: sys-kernel-debug
        hostPath:
          path: /sys/kernel/debug
      - name: lib-modules
        hostPath:
          path: /lib/modules
      - name: usr-src
        hostPath:
          path: /usr/src

Такой агент предоставляет метрики производительности на уровне узлов, включая сетевую задержку, частоту системных вызовов и загрузку процессора, что критически важно для диагностики проблем в распределённой системе и повышения наблюдаемости. Однако существуют риски, связанные с предоставлением привилегированного доступа, поэтому строгая защита образов и регулярное сканирование на уязвимости крайне важны.

Для контейнеризированных приложений Dockerfile позволяет интегрировать библиотеки трассировки или агенты непосредственно в образ. Это обеспечивает единообразную настройку трассировки во всех экземплярах. Здесь продемонстрировано добавление SDK OpenTelemetry в контейнер приложения Python:

# Use a slim base image for security and size optimization
FROM python:3.9-slim-buster

WORKDIR /app

# Install OpenTelemetry SDK
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt \
    opentelemetry-sdk \
    opentelemetry-exporter-otlp

COPY . .

# Set environment variables for OpenTelemetry collector endpoint
ENV OTEL_EXPORTER_OTLP_ENDPOINT="http://opentelemetry-collector:4317"
ENV OTEL_RESOURCE_ATTRIBUTES="service.name=my-app,environment=production"

CMD ["python", "app.py"]

Этот Dockerfile создает неизменяемый компонент инфраструктуры, в который трассировка встроена с момента создания, поддерживая распределенную трассировку и упрощая интеграцию наблюдаемости для безопасности выполнения контейнера и проверки производительности.

Автоматизировать сбор и анализ данных о производительности на экземплярах AWS EC2 можно с помощью AWS CLI или SDK. В этом примере показана установка perf В этом примере показана установка perf и сбор короткой трассировки на экземпляре:

#!/bin/bash
# Script to install perf and collect basic CPU profile on an EC2 instance
sudo yum update -y # For Amazon Linux 2
# For Debian/Ubuntu based systems: sudo apt update && sudo apt install -y linux-tools-$(uname -r)

sudo yum install -y perf

echo "Collecting perf data for 10 seconds..."
sudo perf record -F 99 -a -g -- sleep 10

echo "Generating perf report..."
sudo perf report > /tmp/perf_report.txt

# Optionally, upload the report to S3 for centralized analysis
# aws s3 cp /tmp/perf_report.txt s3://your-perf-data-bucket/ec2-$(hostname)-$(date +%Y%m%d%H%M%S)_perf_report.txt

Этот сценарий обеспечивает автоматизированный сбор данных, что бесценно для реагирования на инциденты и непрерывного мониторинга производительности в автоматизированной инфраструктуре.

Python можно использовать для обработки данных perf или взаимодействия с инструментами BPF для пользовательского анализа. В этом примере показано, как с помощью pyroute2 взаимодействовать с eBPF-программами (требует предварительно загруженной eBPF-программы):

from pyroute2 import IPRoute
import socket

# This is a conceptual example for interacting with BPF programs.
# A real scenario would involve loading a BPF program (e.g., via bcc or libbpf)
# and then potentially using pyroute2 to attach/detach or query maps.

def interact_with_bpf_map(map_id, key):
    with IPRoute() as ip:
        # Example: Get a BPF map by ID
        # map_info = ip.bpf_map_get(map_id=map_id)
        # print(f"BPF Map Info: {map_info}")

        # Example: Lookup a key in a BPF map
        # This requires knowing the map's type and structure.
        # For demonstration, let's assume a basic map interaction.
        print(f"Attempting to interact with BPF map ID: {map_id}")
        print(f"Looking up key: {key}")
        # In a real scenario, you'd use specific library functions to
        # query the map, e.g., via bcc.BPF().get_table("map_name")

# Example usage (replace with actual map ID and key)
# Assuming a map with ID 123 and a key 'some_value'
interact_with_bpf_map(123, b"some_value")

Это взаимодействие с Python демонстрирует, как продвинутые инженеры могут программно запрашивать карты eBPF, собирая пользовательские метрики и осуществлять динамический контроль над агентами трассировки, легко интегрируясь в конвейеры наблюдения.

Наконец, с помощью Terraform можно управлять развертыванием компонентов инфраструктуры распределённой трассировки, таких как OpenTelemetry Collector в AWS. Это гарантирует применение принципов IaC к системам наблюдаемости:

resource "kubernetes_deployment" "otel_collector" {
  metadata {
    name = "otel-collector"
    namespace = "observability"
  }
  spec {
    replicas = 2
    selector {
      match_labels = {
        app = "otel-collector"
      }
    }
    template {
      metadata {
        labels = {
          app = "otel-collector"
        }
      }
      spec {
        container {
          name = "collector"
          image = "otel/opentelemetry-collector-contrib:latest"
          args = [ "--config=/etc/otel-collector-config.yaml" ]
          port {
            container_port = 4317 # OTLP gRPC
            name = "otlp-grpc"
          }
          port {
            container_port = 4318 # OTLP HTTP
            name = "otlp-http"
          }
          volume_mount {
            name = "otel-config"
            mount_path = "/etc/otel-collector-config.yaml"
            sub_path = "otel-collector-config.yaml"
          }
        }
        volume {
          name = "otel-config"
          config_map {
            name = "otel-collector-config"
          }
        }
      }
    }
  }
}

resource "kubernetes_config_map" "otel_collector_config" {
  metadata {
    name = "otel-collector-config"
    namespace = "observability"
  }
  data = {
    "otel-collector-config.yaml" = <<-EOT
receivers:
  otlp:
    protocols:
      grpc:
      http:
exporters:
  logging:
    loglevel: debug
  # Add your preferred exporter (e.g., Jaeger, Prometheus, AWS CloudWatch)
processors:
  batch:
service:
  pipelines:
    traces:
      receivers: [otlp]
      processors: [batch]
      exporters: [logging]
    metrics:
      receivers: [otlp]
      processors: [batch]
      exporters: [logging]
    logs:
      receivers: [otlp]
      processors: [batch]
      exporters: [logging]
EOT
  }
}

Такая конфигурация Terraform гарантирует, что сборщик OpenTelemetry, являющийся важной частью любой распределенной системы трассировки, будет последовательно развернут и настроен в Kubernetes, следуя принципам «инфраструктура как код» и обеспечивая бесперебойный прием данных из различных источников трассировки.

Этот Bash-скрипт демонстрирует автоматизированный сбор данных perf для определенных процессов в часы пик с загрузкой результатов в контейнер S3. Этот шаблон упрощает проактивный мониторинг и анализ аварийных ситуаций для обеспечения надежности распределенной системы.

#!/bin/bash
# Automated perf collection script for critical services
SERVICE_NAME="my_critical_service_process" # Replace with actual process name or pattern
S3_BUCKET="s3://your-enterprise-perf-bucket"
HOSTNAME=$(hostname -s)
TIMESTAMP=$(date +%Y%m%d%H%M%S)
OUTPUT_DIR="/tmp/perf_data"
REPORT_FILE="${OUTPUT_DIR}/${HOSTNAME}_${SERVICE_NAME}_${TIMESTAMP}_perf_report.txt"
PERF_DATA_FILE="${OUTPUT_DIR}/${HOSTNAME}_${SERVICE_NAME}_${TIMESTAMP}_perf.data"

mkdir -p "$OUTPUT_DIR"

# Find PIDs of the critical service
PIDS=$(pgrep -d ',' -f "$SERVICE_NAME")

if [ -z "$PIDS" ]; then
    echo "No processes found for service: $SERVICE_NAME"
    exit 1
fi

echo "Collecting perf data for PIDs: $PIDS for 60 seconds..."
sudo perf record -F 99 -p "$PIDS" -g --output "$PERF_DATA_FILE" -- sleep 60

echo "Generating perf report..."
sudo perf report -i "$PERF_DATA_FILE" > "$REPORT_FILE"

echo "Uploading perf report to S3..."
aws s3 cp "$REPORT_FILE" "$S3_BUCKET/" --region us-east-1

echo "Cleaning up local files..."
rm -rf "$OUTPUT_DIR"
echo "Perf data collection and upload complete."

С помощью Python можно реализовать парсинг собранных логов или метрик и передачи их в централизованную систему отчётности. Этот фрагмент кода демонстрирует взаимодействие с клиентом Prometheus:

from prometheus_client import Gauge, start_http_server
import random
import time

# Metrics for tracing compliance
tracing_agent_status = Gauge('tracing_agent_status', 'Status of tracing agent (0=down, 1=up)', ['hostname', 'service'])
tracing_data_ingestion_rate = Gauge('tracing_data_ingestion_rate', 'Rate of tracing data ingestion (spans/sec)', ['hostname', 'service'])

def update_compliance_metrics():
    # In a real scenario, this would query an actual tracing system or parse logs
    # For demonstration, we'll simulate data.
    host = "web-server-01"
    svc = "frontend-api"

    # Simulate agent status (e.g., check process or endpoint)
    status = random.choice([0, 1])
    tracing_agent_status.labels(hostname=host, service=svc).set(status)

    # Simulate ingestion rate
    ingestion_rate = random.uniform(50.0, 500.0)
    tracing_data_ingestion_rate.labels(hostname=host, service=svc).set(ingestion_rate)

    print(f"Updated metrics for {host}/{svc}: Agent Status={status}, Ingestion Rate={ingestion_rate}")

if __name__ == '__main__':
    start_http_server(8000)
    print("Prometheus metrics server started on port 8000")
    while True:
        update_compliance_metrics()
        time.sleep(30) # Update every 30 seconds

В этом примере Python показано, как предоставить показатели производительности с помощью Prometheus, поддерживая мониторинг, ориентированный на наблюдаемость.

Для обеспечения безопасного выполнения контейнера Dockerfile можно задать более строгие привилегии пользователя для агентов трассировки, придерживаясь принципа наименьших привилегий, что особенно важно в среде нулевого доверия.

FROM ubuntu:22.04

RUN apt update && apt install -y \
    procps \
    iproute2 \
    strace \
    # Install minimal tools required for tracing, avoid full perf/bcc for small agents unless needed
    # libcap-ng-utils # For capsh if needed to drop capabilities at runtime
    && rm -rf /var/lib/apt/lists/*

# Create a non-root user for the agent
RUN useradd -ms /bin/bash tracinguser

# Copy agent binaries/scripts
COPY tracing_agent.sh /opt/tracing_agent.sh
RUN chown tracinguser:tracinguser /opt/tracing_agent.sh
RUN chmod +x /opt/tracing_agent.sh

# Switch to the non-root user
USER tracinguser

# Define entrypoint or command to run the agent
ENTRYPOINT ["/opt/tracing_agent.sh"]

В этом Dockerfile особое внимание уделяется безопасности выполнения контейнера за счет запуска агента трассировки от имени пользователя, не являющегося пользователем root, что является фундаментальной практикой для снижения рисков безопасности, связанных с привилегированными контейнерами.

Подписывайтесь на телеграм-канал Мониторим ИТ, там еще больше полезной информации о мониторинге!