6.2-监控与调优 — GPU推理优化 性能管理 本节导读:本节深入讲解大模型推理服务的监控体系、性能分析和调优策略,帮助读者建立完整的推理服务性能管理和优化能力。 学习目标 掌握推理服务监控体系的构建方法 理解关键性能指标和监控维度 学会性能瓶颈分析和诊断技巧 掌握推理服务性能调优的实用方法 核心概念 监控体系基础 监控的重要性: 大模型推理服务的监控是确保系统稳定性和性能优化的核心环节。完善的监控系统能够及时发现性能问题,预防系统故障,为优化提供数据支撑。
本节导读:本节深入讲解大模型推理服务的监控体系、性能分析和调优策略,帮助读者建立完整的推理服务性能管理和优化能力。
监控的重要性:
大模型推理服务的监控是确保系统稳定性和性能优化的核心环节。完善的监控系统能够及时发现性能问题,预防系统故障,为优化提供数据支撑。
监控维度设计:
TTFT (Time to First Token):
TPOT (Time per Output Token):
Throughput:
Latency:
GPU利用率:
内存使用率:
网络带宽:
CPU利用率:
Prometheus:
Grafana:
DCGM Features:
OpenTelemetry Features:
硬件要求:
软件要求:
搭建基础的推理服务监控系统:
# monitoring-compose.yml version: '3.8' services: # Prometheus监控服务器 prometheus: image: prom/prometheus:latest ports: - "9090:9090" volumes: - ./prometheus.yml:/etc/prometheus/prometheus.yml - prometheus_data:/prometheus command: - '--config.file=/etc/prometheus/prometheus.yml' - '--storage.tsdb.path=/prometheus' - '--web.console.libraries=/etc/prometheus/console_libraries' - '--web.console.templates=/etc/prometheus/consoles' - '--storage.tsdb.retention.time=200h' - '--web.enable-lifecycle' networks: - monitoring-network restart: unless-stopped # Grafana可视化平台 grafana: image: grafana/grafana:latest ports: - "3000:3000" environment: - GF_SECURITY_ADMIN_PASSWORD=admin123 - GF_USERS_ALLOW_SIGN_UP=false volumes: - grafana_data:/var/lib/grafana - ./grafana/provisioning:/etc/grafana/provisioning networks: - monitoring-network restart: unless-stopped # Node Exporter系统监控 node_exporter: image: prom/node-exporter:latest ports: - "9100:9100" volumes: - /proc:/host/proc:ro - /sys:/host/sys:ro - /:/rootfs:ro command: - '--path.rootfs=/rootfs' - '--collector.processes' - '--collector.diskstats' - '--collector.filesystem' - '--collector.meminfo' - '--collector.netdev' - '--collector.stat' - '--collector.cpu' - '--collector.diskio' networks: - monitoring-network restart: unless-stopped # DCGM GPU监控 dcgm-exporter: image: nvidia/dcgm-exporter:latest ports: - "9400:9400" environment: - DCGM_EXPORTER_LISTEN=0.0.0.0:9400 volumes: - /var/run/dcgm:/var/run/dcgm networks: - monitoring-network restart: unless-stopped networks: monitoring-network: driver: bridge volumes: prometheus_data: grafana_data:
为推理服务添加监控支持:
# inference_monitor.py import time import psutil import GPUtil from prometheus_client import start_http_server, Counter, Histogram, Gauge import threading import json from typing import Dict, List, Any class InferenceMonitor: """推理服务监控类""" def __init__(self, port=8080): self.port = port self.start_time = time.time() # Prometheus指标 self.request_counter = Counter( 'inference_requests_total', 'Total number of inference requests', ['model', 'status'] ) self.request_duration = Histogram( 'inference_request_duration_seconds', 'Time spent on inference requests', ['model'] ) self.gpu_utilization = Gauge( 'gpu_utilization_percent', 'GPU utilization percentage' ) self.memory_usage = Gauge( 'gpu_memory_usage_bytes', 'GPU memory usage in bytes' ) self.active_requests = Gauge( 'active_requests', 'Number of active inference requests' ) # 初始化监控 self.setup_monitoring() def setup_monitoring(self): """启动监控服务""" start_http_server(self.port) print(f"Monitoring service started on port {self.port}") # 启动系统监控线程 monitoring_thread = threading.Thread(target=self.system_monitoring_loop) monitoring_thread.daemon = True monitoring_thread.start() def system_monitoring_loop(self): """系统监控循环""" while True: try: # 更新GPU监控 self.update_gpu_metrics() # 更新系统监控 self.update_system_metrics() time.sleep(5) except Exception as e: print(f"Monitoring error: {e}") def update_gpu_metrics(self): """更新GPU指标""" try: gpus = GPUtil.getGPUs() if gpus: # 使用第一个GPU gpu = gpus[0] self.gpu_utilization.set(gpu.load * 100) self.memory_usage.set(gpu.memoryUsed) except Exception as e: print(f"GPU monitoring error: {e}") def update_system_metrics(self): """更新系统指标""" try: # CPU使用率 cpu_percent = psutil.cpu_percent(interval=1) # 内存使用率 memory = psutil.virtual_memory() # 磁盘使用率 disk = psutil.disk_usage('/') # 更新指标(可以添加更多系统指标) print(f"System - CPU: {cpu_percent}%, Memory: {memory.percent}%, Disk: {disk.percent}%") except Exception as e: print(f"System monitoring error: {e}") def record_request(self, model: str, duration: float, status: str = 'success'): """记录推理请求""" self.request_counter.labels(model=model, status=status).inc() self.request_duration.labels(model=model).observe(duration) def get_system_stats(self) -> Dict[str, Any]: """获取系统统计信息""" try: return { 'cpu_percent': psutil.cpu_percent(), 'memory_percent': psutil.virtual_memory().percent, 'disk_percent': psutil.disk_usage('/').percent, 'gpu_utilization': self.gpu_utilization._value._value if hasattr(self.gpu_utilization, '_value') else 0, 'gpu_memory_usage': self.memory_usage._value._value if hasattr(self.memory_usage, '_value') else 0, 'uptime': time.time() - self.start_time } except Exception as e: return {'error': str(e)} # 使用示例 if __name__ == "__main__": monitor = InferenceMonitor() # 模拟推理请求 import time for i in range(10): start_time = time.time() time.sleep(0.1) # 模拟推理时间 duration = time.time() - start_time monitor.record_request( model="llama-2-7b", duration=duration, status="success" ) print(f"Request {i+1}: {duration:.3f}s") # 获取系统状态 stats = monitor.get_system_stats() print("System stats:", stats)
创建推理服务性能分析工具:
# performance_analyzer.py import time import json import statistics from typing import List, Dict, Any from dataclasses import dataclass from collections import defaultdict import matplotlib.pyplot as plt import numpy as np @dataclass class InferenceRequest: """推理请求记录""" request_id: str model: str input_length: int output_length: int ttft: float # Time to First Token (ms) tpot: float # Time per Output Token (ms) total_time: float timestamp: float status: str error_message: str = None @dataclass class SystemMetrics: """系统指标""" timestamp: float cpu_percent: float memory_percent: float gpu_utilization: float gpu_memory_percent: float network_in: float network_out: float class PerformanceAnalyzer: """性能分析器""" def __init__(self): self.requests: List[InferenceRequest] = [] self.system_metrics: List[SystemMetrics] = [] def add_request(self, request: InferenceRequest): """添加推理请求记录""" self.requests.append(request) def add_system_metrics(self, metrics: SystemMetrics): """添加系统指标""" self.system_metrics.append(metrics) def calculate_throughput(self, time_window: int = 3600) -> float: """计算吞吐量 (requests per second)""" if not self.requests: return 0.0 current_time = time.time() recent_requests = [r for r in self.requests if current_time - r.timestamp <= time_window] return len(recent_requests) / time_window def calculate_latency_percentiles(self, percentiles: List[int] = None) -> Dict[int, float]: """计算延迟百分位数""" if percentiles is None: percentiles = [50, 90, 95, 99] if not self.requests: return {p: 0.0 for p in percentiles} total_times = [r.total_time for r in self.requests if r.status == 'success'] if not total_times: return {p: 0.0 for p in percentiles} result = {} for p in percentiles: result[p] = statistics.quantiles(total_times, n=100)[p-1] if p <= 100 else max(total_times) return result def calculate_gpu_utilization(self) -> Dict[str, float]: """计算GPU利用率统计""" if not self.system_metrics: return {'avg': 0.0, 'max': 0.0, 'min': 0.0} utilizations = [m.gpu_utilization for m in self.system_metrics] return { 'avg': statistics.mean(utilizations), 'max': max(utilizations), 'min': min(utilizations), 'std': statistics.stdev(utilizations) if len(utilizations) > 1 else 0.0 } def detect_bottlenecks(self) -> List[str]: """检测性能瓶颈""" bottlenecks = [] # GPU利用率分析 gpu_stats = self.calculate_gpu_utilization() if gpu_stats['avg'] < 50: bottlenecks.append("GPU利用率过低,可能存在计算瓶颈") elif gpu_stats['avg'] > 95: bottlenecks.append("GPU利用率过高,可能影响系统稳定性") # 延迟分析 latency_stats = self.calculate_latency_percentiles([95, 99]) if latency_stats[95] > 1000: # 1秒 bottlenecks.append("95%延迟超过1秒,存在性能问题") # 吞吐量分析 throughput = self.calculate_throughput() if throughput < 1.0: bottlenecks.append("吞吐量过低,系统处理能力不足") # 网络分析 if self.system_metrics: avg_network_out = statistics.mean([m.network_out for m in self.system_metrics]) if avg_network_out > 100 * 1024 * 1024: # 100MB/s bottlenecks.append("网络输出带宽过高,可能存在网络瓶颈") return bottlenecks def generate_performance_report(self) -> str: """生成性能报告""" if not self.requests: return "No performance data available" successful_requests = [r for r in self.requests if r.status == 'success'] failed_requests = [r for r in self.requests if r.status == 'failed'] report = [] report.append("=== 推理服务性能报告 ===") report.append(f"总请求数: {len(self.requests)}") report.append(f"成功请求: {len(successful_requests)}") report.append(f"失败请求: {len(failed_requests)}") report.append(f"成功率: {len(successful_requests)/len(self.requests)*100:.2f}%") if successful_requests: # 延迟统计 report.append("\n=== 延迟统计 ===") latency_stats = self.calculate_latency_percentiles() for p, latency in latency_stats.items(): report.append(f"P{p}延迟: {latency:.2f}ms") # 吞吐量统计 report.append("\n=== 吞吐量统计 ===") throughput = self.calculate_throughput() report.append(f"当前吞吐量: {throughput:.2f} requests/s") # GPU统计 gpu_stats = self.calculate_gpu_utilization() if gpu_stats['avg'] > 0: report.append("\n=== GPU利用率统计 ===") report.append(f"平均GPU利用率: {gpu_stats['avg']:.2f}%") report.append(f"最高GPU利用率: {gpu_stats['max']:.2f}%") report.append(f"最低GPU利用率: {gpu_stats['min']:.2f}%") # 瓶颈分析 bottlenecks = self.detect_bottlenecks() if bottlenecks: report.append("\n=== 性能瓶颈 ===") for bottleneck in bottlenecks: report.append(f"- {bottleneck}") return "\n".join(report) # 使用示例 if __name__ == "__main__": analyzer = PerformanceAnalyzer() # 模拟推理请求数据 import random base_time = time.time() for i in range(100): timestamp = base_time + i * 10 # 每10秒一个请求 # 模拟成功请求 request = InferenceRequest( request_id=f"req_{i}", model="llama-2-7b", input_length=random.randint(100, 500), output_length=random.randint(50, 200), ttft=random.uniform(50, 200), tpot=random.uniform(10, 50), total_time=random.uniform(100, 500), timestamp=timestamp, status="success" ) analyzer.add_request(request) # 随机添加一些失败请求 if i % 10 == 0: failed_request = InferenceRequest( request_id=f"failed_req_{i//10}", model="llama-2-7b", input_length=random.randint(100, 500), output_length=0, ttft=0, tpot=0, total_time=0, timestamp=timestamp, status="failed", error_message="GPU out of memory" ) analyzer.add_request(failed_request) # 生成报告 report = analyzer.generate_performance_report() print(report) # 检测瓶颈 bottlenecks = analyzer.detect_bottlenecks() print("\n检测到的瓶颈:", bottlenecks)