如果你的团队正在运行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 创建数据源
- 登录Grafana (
http://localhost:3000,默认账号admin/admin123) - Configuration → Data Sources → Add data source
- 选择Prometheus,URL填
http://prometheus:9090 - 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翻译服务监控方案:
- 指标设计:覆盖性能、质量、资源、业务四个维度
- Exporter开发:用Python自定义Prometheus指标暴露
- Prometheus配置:采集规则、告警规则
- Grafana看板:8个核心面板,全方位可视化
- 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翻译服务的运行状态,及时发现并解决问题,保障服务质量。
相关推荐:
- PDFTranslator.org --- 在线PDF翻译工具,支持格式保留
- Prometheus官方文档
- Grafana官方文档