用Prometheus+Grafana搭建PDF翻译服务监控看板:指标采集与告警实战

如果你的团队正在运行PDF翻译服务(无论是自研还是基于开源方案),监控是保障服务质量的关键。本文介绍如何用Prometheus+Grafana搭建一套完整的PDF翻译服务监控体系,涵盖核心指标采集、可视化看板和告警规则配置。

一、PDF翻译服务需要监控什么?

在搭建监控之前,先明确需要关注的核心指标:

指标类别 具体指标 说明
性能指标 翻译耗时 单页/单文档翻译时间
吞吐量 每分钟处理的页数/文档数
队列深度 待处理任务数量
质量指标 翻译成功率 成功完成翻译的比例
格式保留率 翻译后格式正常的比例
OCR识别准确率 扫描版PDF的文字识别准确度
资源指标 CPU使用率 翻译服务的CPU占用
内存占用 峰值和平均内存使用
磁盘I/O PDF读写操作的I/O负载
业务指标 日活用户数 使用翻译服务的独立用户
文档类型分布 PDF/扫描件/图片等占比
语言对分布 各语言组合的翻译量

二、架构设计

复制代码
┌─────────────────────────────────────────────────────────────┐
│                     PDF翻译服务集群                          │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐                  │
│  │ 翻译节点1 │  │ 翻译节点2 │  │ 翻译节点3 │                  │
│  │  +Exporter│  │  +Exporter│  │  +Exporter│                  │
│  └────┬─────┘  └────┬─────┘  └────┬─────┘                  │
│       └─────────────┴─────────────┘                         │
│                      │                                       │
│                 ┌────┴────┐                                  │
│                 │  Nginx  │  ← 负载均衡+metrics端点           │
│                 └────┬────┘                                  │
└──────────────────────┼──────────────────────────────────────┘
                       │
                       ▼
              ┌────────────────┐
              │   Prometheus   │  ← 时序数据库
              │   (9090端口)    │
              └───────┬────────┘
                      │
                      ▼
              ┌────────────────┐
              │    Grafana     │  ← 可视化看板
              │   (3000端口)    │
              └────────────────┘
                      │
                      ▼
              ┌────────────────┐
              │  Alertmanager  │  ← 告警管理
              └────────────────┘

三、核心组件部署

3.1 自定义Metrics Exporter

PDF翻译服务需要暴露Prometheus格式的指标。以下是一个基于Python的示例Exporter:

python 复制代码
#!/usr/bin/env python3
"""
PDF翻译服务 Prometheus Exporter
"""

from prometheus_client import Counter, Histogram, Gauge, Info, start_http_server
import time
import random
import threading

# 定义指标
TRANSLATION_COUNTER = Counter(
    'pdf_translation_total',
    'Total number of PDF translations',
    ['language_pair', 'document_type', 'status']
)

TRANSLATION_DURATION = Histogram(
    'pdf_translation_duration_seconds',
    'Time spent on PDF translation',
    ['language_pair', 'document_type'],
    buckets=[0.5, 1.0, 2.0, 5.0, 10.0, 30.0, 60.0, 120.0, 300.0]
)

QUEUE_DEPTH = Gauge(
    'pdf_translation_queue_depth',
    'Current number of documents in translation queue'
)

ACTIVE_WORKERS = Gauge(
    'pdf_translation_active_workers',
    'Number of currently active translation workers'
)

FORMAT_PRESERVATION_RATE = Gauge(
    'pdf_format_preservation_rate',
    'Rate of successful format preservation (0-1)',
    ['language_pair']
)

OCR_ACCURACY = Gauge(
    'pdf_ocr_accuracy',
    'OCR recognition accuracy (0-1)',
    ['language']
)

SERVICE_INFO = Info('pdf_translation_service', 'Service information')


class TranslationMetricsCollector:
    """翻译指标收集器"""
    
    def __init__(self):
        self.translation_count = 0
        self.queue_size = 0
        self.active_workers = 0
        
        # 设置服务信息
        SERVICE_INFO.info({
            'version': '2.1.0',
            'model': 'transformer-v3',
            'ocr_engine': 'tesseract-5.0'
        })
    
    def record_translation(self, language_pair, doc_type, duration, success=True):
        """记录一次翻译"""
        status = 'success' if success else 'failure'
        TRANSLATION_COUNTER.labels(
            language_pair=language_pair,
            document_type=doc_type,
            status=status
        ).inc()
        
        TRANSLATION_DURATION.labels(
            language_pair=language_pair,
            document_type=doc_type
        ).observe(duration)
    
    def update_queue_depth(self, depth):
        """更新队列深度"""
        QUEUE_DEPTH.set(depth)
    
    def update_active_workers(self, count):
        """更新活跃工作线程数"""
        ACTIVE_WORKERS.set(count)
    
    def update_format_preservation(self, language_pair, rate):
        """更新格式保留率"""
        FORMAT_PRESERVATION_RATE.labels(
            language_pair=language_pair
        ).set(rate)
    
    def update_ocr_accuracy(self, language, accuracy):
        """更新OCR准确率"""
        OCR_ACCURACY.labels(language=language).set(accuracy)


def simulate_translation_metrics(collector):
    """模拟翻译服务产生指标(实际环境中替换为真实数据)"""
    language_pairs = ['en-zh', 'zh-en', 'ja-zh', 'ko-zh', 'de-zh']
    doc_types = ['text_pdf', 'scanned_pdf', 'image_pdf', 'mixed']
    
    while True:
        # 模拟队列深度变化
        queue_depth = random.randint(0, 50)
        collector.update_queue_depth(queue_depth)
        
        # 模拟活跃工作者
        active = random.randint(2, 8)
        collector.update_active_workers(active)
        
        # 模拟格式保留率
        for lp in language_pairs:
            rate = random.uniform(0.85, 0.99)
            collector.update_format_preservation(lp, rate)
        
        # 模拟OCR准确率
        for lang in ['en', 'zh', 'ja', 'de']:
            acc = random.uniform(0.90, 0.98)
            collector.update_ocr_accuracy(lang, acc)
        
        # 模拟翻译请求
        if random.random() > 0.3:
            lp = random.choice(language_pairs)
            dt = random.choice(doc_types)
            duration = random.expovariate(1.0/10.0)  # 平均10秒
            success = random.random() > 0.05  # 95%成功率
            collector.record_translation(lp, dt, duration, success)
        
        time.sleep(5)


if __name__ == '__main__':
    # 启动metrics HTTP服务
    start_http_server(9091)
    print("Metrics exporter started on port 9091")
    
    collector = TranslationMetricsCollector()
    
    # 启动模拟数据生成(生产环境移除)
    thread = threading.Thread(target=simulate_translation_metrics, args=(collector,))
    thread.daemon = True
    thread.start()
    
    # 保持运行
    while True:
        time.sleep(1)

保存为 pdf_exporter.py,运行:

bash 复制代码
pip install prometheus_client
python pdf_exporter.py

访问 http://localhost:9091/metrics 查看暴露的指标。

3.2 Prometheus配置

prometheus.yml

yaml 复制代码
global:
  scrape_interval: 15s
  evaluation_interval: 15s

alerting:
  alertmanagers:
    - static_configs:
        - targets: ['localhost:9093']

rule_files:
  - "pdf_translation_rules.yml"

scrape_configs:
  - job_name: 'pdf-translation-service'
    static_configs:
      - targets: ['localhost:9091']
    metrics_path: '/metrics'
    scrape_interval: 5s
  
  - job_name: 'node-exporter'
    static_configs:
      - targets: ['localhost:9100']
  
  - job_name: 'nginx'
    static_configs:
      - targets: ['localhost:9113']

告警规则 pdf_translation_rules.yml

yaml 复制代码
groups:
  - name: pdf_translation_alerts
    rules:
      - alert: HighTranslationFailureRate
        expr: rate(pdf_translation_total{status="failure"}[5m]) / rate(pdf_translation_total[5m]) > 0.1
        for: 2m
        labels:
          severity: critical
        annotations:
          summary: "PDF翻译失败率过高"
          description: "过去5分钟翻译失败率超过10%,当前值: {{ $value }}"
      
      - alert: TranslationQueueBacklog
        expr: pdf_translation_queue_depth > 100
        for: 1m
        labels:
          severity: warning
        annotations:
          summary: "翻译队列积压"
          description: "当前队列深度 {{ $value }},超过阈值100"
      
      - alert: SlowTranslation
        expr: histogram_quantile(0.95, rate(pdf_translation_duration_seconds_bucket[5m])) > 60
        for: 3m
        labels:
          severity: warning
        annotations:
          summary: "翻译耗时异常"
          description: "P95翻译耗时 {{ $value }}秒,超过60秒阈值"
      
      - alert: LowFormatPreservation
        expr: pdf_format_preservation_rate < 0.8
        for: 5m
        labels:
          severity: critical
        annotations:
          summary: "格式保留率过低"
          description: "语言对 {{ $labels.language_pair }} 的格式保留率 {{ $value }}"
      
      - alert: HighMemoryUsage
        expr: (node_memory_MemTotal_bytes - node_memory_MemAvailable_bytes) / node_memory_MemTotal_bytes > 0.9
        for: 2m
        labels:
          severity: warning
        annotations:
          summary: "内存使用率过高"
          description: "节点 {{ $labels.instance }} 内存使用率 {{ $value }}"

3.3 Docker Compose部署

yaml 复制代码
version: '3.8'

services:
  prometheus:
    image: prom/prometheus:latest
    container_name: prometheus
    ports:
      - "9090:9090"
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
      - ./pdf_translation_rules.yml:/etc/prometheus/pdf_translation_rules.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'
      - '--web.enable-lifecycle'
    networks:
      - monitoring

  grafana:
    image: grafana/grafana:latest
    container_name: grafana
    ports:
      - "3000:3000"
    volumes:
      - grafana_data:/var/lib/grafana
      - ./grafana/dashboards:/etc/grafana/provisioning/dashboards
      - ./grafana/datasources:/etc/grafana/provisioning/datasources
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=admin123
      - GF_USERS_ALLOW_SIGN_UP=false
    networks:
      - monitoring

  alertmanager:
    image: prom/alertmanager:latest
    container_name: alertmanager
    ports:
      - "9093:9093"
    volumes:
      - ./alertmanager.yml:/etc/alertmanager/alertmanager.yml
      - alertmanager_data:/alertmanager
    networks:
      - monitoring

  node-exporter:
    image: prom/node-exporter:latest
    container_name: node-exporter
    ports:
      - "9100:9100"
    volumes:
      - /proc:/host/proc:ro
      - /sys:/host/sys:ro
      - /:/rootfs:ro
    command:
      - '--path.procfs=/host/proc'
      - '--path.rootfs=/rootfs'
      - '--path.sysfs=/host/sys'
      - '--collector.filesystem.mount-points-exclude=^/(sys|proc|dev|host|etc)($$|/)'
    networks:
      - monitoring

  pdf-exporter:
    build:
      context: ./exporter
    container_name: pdf-exporter
    ports:
      - "9091:9091"
    networks:
      - monitoring

volumes:
  prometheus_data:
  grafana_data:
  alertmanager_data:

networks:
  monitoring:
    driver: bridge

四、Grafana看板配置

4.1 创建数据源

  1. 登录Grafana (http://localhost:3000,默认账号admin/admin123)
  2. Configuration → Data Sources → Add data source
  3. 选择Prometheus,URL填 http://prometheus:9090
  4. Save & Test

4.2 导入看板JSON

创建 grafana/dashboards/pdf_translation_dashboard.json

json 复制代码
{
  "dashboard": {
    "id": null,
    "title": "PDF翻译服务监控看板",
    "tags": ["pdf", "translation", "monitoring"],
    "timezone": "Asia/Shanghai",
    "panels": [
      {
        "id": 1,
        "title": "实时翻译QPS",
        "type": "stat",
        "targets": [
          {
            "expr": "rate(pdf_translation_total[1m])",
            "legendFormat": "{{language_pair}}"
          }
        ],
        "gridPos": {"h": 4, "w": 6, "x": 0, "y": 0}
      },
      {
        "id": 2,
        "title": "翻译成功率",
        "type": "gauge",
        "targets": [
          {
            "expr": "rate(pdf_translation_total{status=\"success\"}[5m]) / rate(pdf_translation_total[5m])",
            "legendFormat": "成功率"
          }
        ],
        "fieldConfig": {
          "defaults": {
            "min": 0,
            "max": 1,
            "thresholds": {
              "steps": [
                {"color": "red", "value": 0},
                {"color": "yellow", "value": 0.95},
                {"color": "green", "value": 0.99}
              ]
            }
          }
        },
        "gridPos": {"h": 4, "w": 6, "x": 6, "y": 0}
      },
      {
        "id": 3,
        "title": "队列深度",
        "type": "graph",
        "targets": [
          {
            "expr": "pdf_translation_queue_depth",
            "legendFormat": "队列长度"
          }
        ],
        "gridPos": {"h": 4, "w": 6, "x": 12, "y": 0}
      },
      {
        "id": 4,
        "title": "活跃工作节点",
        "type": "stat",
        "targets": [
          {
            "expr": "pdf_translation_active_workers",
            "legendFormat": "活跃节点"
          }
        ],
        "gridPos": {"h": 4, "w": 6, "x": 18, "y": 0}
      },
      {
        "id": 5,
        "title": "翻译耗时分布 (P50/P95/P99)",
        "type": "graph",
        "targets": [
          {
            "expr": "histogram_quantile(0.50, rate(pdf_translation_duration_seconds_bucket[5m]))",
            "legendFormat": "P50"
          },
          {
            "expr": "histogram_quantile(0.95, rate(pdf_translation_duration_seconds_bucket[5m]))",
            "legendFormat": "P95"
          },
          {
            "expr": "histogram_quantile(0.99, rate(pdf_translation_duration_seconds_bucket[5m]))",
            "legendFormat": "P99"
          }
        ],
        "gridPos": {"h": 8, "w": 12, "x": 0, "y": 4}
      },
      {
        "id": 6,
        "title": "各语言对翻译量",
        "type": "piechart",
        "targets": [
          {
            "expr": "sum by (language_pair) (rate(pdf_translation_total[1h]))",
            "legendFormat": "{{language_pair}}"
          }
        ],
        "gridPos": {"h": 8, "w": 12, "x": 12, "y": 4}
      },
      {
        "id": 7,
        "title": "格式保留率趋势",
        "type": "graph",
        "targets": [
          {
            "expr": "pdf_format_preservation_rate",
            "legendFormat": "{{language_pair}}"
          }
        ],
        "gridPos": {"h": 6, "w": 12, "x": 0, "y": 12}
      },
      {
        "id": 8,
        "title": "OCR识别准确率",
        "type": "graph",
        "targets": [
          {
            "expr": "pdf_ocr_accuracy",
            "legendFormat": "{{language}}"
          }
        ],
        "gridPos": {"h": 6, "w": 12, "x": 12, "y": 12}
      }
    ]
  }
}

4.3 配置数据源自动加载

grafana/datasources/prometheus.yml

yaml 复制代码
apiVersion: 1
datasources:
  - name: Prometheus
    type: prometheus
    access: proxy
    url: http://prometheus:9090
    isDefault: true

五、Alertmanager告警配置

alertmanager.yml

yaml 复制代码
global:
  smtp_smarthost: 'smtp.example.com:587'
  smtp_from: 'alerts@example.com'
  smtp_auth_username: 'alerts@example.com'
  smtp_auth_password: 'your-password'

route:
  group_by: ['alertname', 'severity']
  group_wait: 10s
  group_interval: 10s
  repeat_interval: 1h
  receiver: 'default'
  routes:
    - match:
        severity: critical
      receiver: 'critical-alerts'
      continue: true
    - match:
        severity: warning
      receiver: 'warning-alerts'

receivers:
  - name: 'default'
    email_configs:
      - to: 'ops@example.com'
        subject: 'PDF翻译服务告警: {{ .GroupLabels.alertname }}'
        body: |
          {{ range .Alerts }}
          告警: {{ .Annotations.summary }}
          详情: {{ .Annotations.description }}
          时间: {{ .StartsAt }}
          {{ end }}

  - name: 'critical-alerts'
    email_configs:
      - to: 'ops@example.com'
      - to: 'oncall@example.com'
    slack_configs:
      - api_url: 'YOUR_SLACK_WEBHOOK_URL'
        channel: '#critical-alerts'
        title: 'PDF翻译服务严重告警'
        text: '{{ range .Alerts }}{{ .Annotations.summary }}{{ end }}'

  - name: 'warning-alerts'
    email_configs:
      - to: 'ops@example.com'
    slack_configs:
      - api_url: 'YOUR_SLACK_WEBHOOK_URL'
        channel: '#warnings'

六、实际集成代码示例

将Metrics收集集成到你的PDF翻译服务中:

python 复制代码
from prometheus_client import start_http_server
from pdf_exporter import TranslationMetricsCollector
import time

class PDFTranslationService:
    def __init__(self):
        self.collector = TranslationMetricsCollector()
        # 启动metrics端点
        start_http_server(9091)
    
    def translate_document(self, file_path, source_lang, target_lang):
        """翻译文档"""
        doc_type = self.detect_document_type(file_path)
        language_pair = f"{source_lang}-{target_lang}"
        
        start_time = time.time()
        
        try:
            # 更新队列深度
            self.collector.update_queue_depth(self.queue.qsize())
            self.collector.update_active_workers(self.active_workers)
            
            # 执行翻译
            result = self._do_translate(file_path, source_lang, target_lang)
            
            # 记录成功
            duration = time.time() - start_time
            self.collector.record_translation(
                language_pair=language_pair,
                doc_type=doc_type,
                duration=duration,
                success=True
            )
            
            # 记录格式保留率
            format_rate = self.evaluate_format_preservation(result)
            self.collector.update_format_preservation(language_pair, format_rate)
            
            return result
            
        except Exception as e:
            # 记录失败
            duration = time.time() - start_time
            self.collector.record_translation(
                language_pair=language_pair,
                doc_type=doc_type,
                duration=duration,
                success=False
            )
            raise

七、总结

本文介绍了完整的PDF翻译服务监控方案:

  1. 指标设计:覆盖性能、质量、资源、业务四个维度
  2. Exporter开发:用Python自定义Prometheus指标暴露
  3. Prometheus配置:采集规则、告警规则
  4. Grafana看板:8个核心面板,全方位可视化
  5. Alertmanager:分级告警,邮件+Slack通知

部署步骤:

bash 复制代码
# 1. 克隆配置
git clone <repo-url>
cd pdf-translation-monitoring

# 2. 启动服务
docker-compose up -d

# 3. 访问看板
# Grafana: http://localhost:3000
# Prometheus: http://localhost:9090

通过这套监控体系,你可以实时掌握PDF翻译服务的运行状态,及时发现并解决问题,保障服务质量。


相关推荐

相关推荐
circuitsosk11 分钟前
多智能体协同在能源数据分析中的实践:分配-执行-校验闭环架构设计
python·数据分析·wpf·能源·并行计算·多智能体系统·agent协作
niuniudengdeng14 分钟前
从小程序到 WebView:一个理发店管理系统的全栈架构设计与落地实践
java·python
心易行者21 分钟前
html在线运行搭AI编程验证流水线:5步走完从生成到到上线全流程
人工智能·python·ai编程
一晌小贪欢25 分钟前
Python办公17:暴力拆分——按页数或指定范围提取 PDF 核心页面
java·开发语言·python·pdf·excel·数据可视化·python办公
青 春 记 忆27 分钟前
零基础入门python31:Django商城第一步——创建项目并跑通第一个请求
python·django·后端开发
孫治AllenSun27 分钟前
【LangChain4J-06】Prompt 工程与模板化开发
开发语言·python·prompt
qq_4260039628 分钟前
多语言新增语种全量测试策略
前端·javascript·python·pycharm·自动化
^酸酸29 分钟前
Prometheus 监控架构部署实战:二进制与 Docker 双方案
docker·架构·prometheus
AuLuo-31 分钟前
SearXNG 物理机部署搭建免费搜索引擎服务
python·搜索引擎