Skalierung
Anleitung zur Skalierung von Duckling für Deployments mit hohem Traffic.
Architektur für Skalierung
graph LR
LB[Lastverteiler]
LB --> B1[Backend 1]
LB --> B2[Backend 2]
LB --> B3[Backend 3]
B1 --> Redis[(Redis-Warteschlange)]
B2 --> Redis
B3 --> Redis
B1 --> PG[(PostgreSQL)]
B2 --> PG
B3 --> PG
B1 --> S3[(S3-Speicher)]
B2 --> S3
B3 --> S3
style LB fill:#f59e0b,color:#fff
style Redis fill:#dc2626,color:#fff
style PG fill:#3b82f6,color:#fff
style S3 fill:#22c55e,color:#fff Horizontale Skalierung
Für Deployments mit hohem Traffic:
- Lastverteiler: nginx, HAProxy oder Cloud-LB verwenden
- Mehrere Backend-Instanzen: Mehrere Gunicorn-Prozesse betreiben
- Gemeinsamer Speicher: NFS oder Objektspeicher für Uploads/Ausgaben
- Datenbank: PostgreSQL für den Verlauf in Betracht ziehen (statt SQLite)
Ressourcenanforderungen
| Deployment | CPU | RAM | Speicher |
|---|---|---|---|
| Entwicklung | 2 Kerne | 4 GB | 10 GB |
| Klein (< 100 Dok./Tag) | 4 Kerne | 8 GB | 50 GB |
| Mittel (< 1000 Dok./Tag) | 8 Kerne | 16 GB | 200 GB |
| Groß (> 1000 Dok./Tag) | 16+ Kerne | 32 GB+ | 500 GB+ |
Lastausgleich mit Nginx
upstream docling_backends {
least_conn;
server 10.0.0.1:5001 weight=1;
server 10.0.0.2:5001 weight=1;
server 10.0.0.3:5001 weight=1;
}
server {
listen 80;
server_name docling.example.com;
location /api/ {
proxy_pass http://docling_backends;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
# Sticky Sessions für Job-Polling
ip_hash;
}
}
Redis-Job-Warteschlange
In der Produktion mit mehreren Workern die threadbasierte Warteschlange durch Redis ersetzen:
Installation
Konfiguration
# celery_config.py
from celery import Celery
celery = Celery(
'docling',
broker='redis://localhost:6379/0',
backend='redis://localhost:6379/0'
)
celery.conf.update(
task_serializer='json',
accept_content=['json'],
result_serializer='json',
timezone='UTC',
enable_utc=True,
task_time_limit=600, # 10 Minuten
task_soft_time_limit=540,
)
Task-Definition
@celery.task(bind=True)
def convert_document(self, job_id: str, file_path: str, settings: dict):
"""Dokument asynchron konvertieren."""
try:
result = converter_service.convert(file_path, settings)
return {'job_id': job_id, 'status': 'completed', 'result': result}
except Exception as e:
self.retry(exc=e, countdown=60, max_retries=3)
Worker ausführen
Migration zu PostgreSQL
Bei mehreren Instanzen von SQLite zu PostgreSQL migrieren:
Konfiguration
# config.py
DATABASE_URL = os.environ.get(
'DATABASE_URL',
'postgresql://user:password@localhost:5432/docling'
)
Migrationsskript
# migrate_to_postgres.py
import sqlite3
import psycopg2
def migrate():
sqlite_conn = sqlite3.connect('history.db')
pg_conn = psycopg2.connect(DATABASE_URL)
# Daten von SQLite nach PostgreSQL kopieren
# ...
Objektspeicher (S3)
S3 oder kompatiblen Speicher für Uploads und Ausgaben verwenden:
Konfiguration
import boto3
s3 = boto3.client(
's3',
aws_access_key_id=os.environ['AWS_ACCESS_KEY_ID'],
aws_secret_access_key=os.environ['AWS_SECRET_ACCESS_KEY'],
region_name='us-east-1'
)
BUCKET_NAME = 'duckling-files'
Dateioperationen
def upload_to_s3(file_path: str, key: str):
s3.upload_file(file_path, BUCKET_NAME, key)
def download_from_s3(key: str, file_path: str):
s3.download_file(BUCKET_NAME, key, file_path)
GPU-Beschleunigung
Für hohes OCR-Volumen:
Docker mit GPU
# docker-compose.gpu.yml
services:
backend:
build: ./backend
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: 1
capabilities: [gpu]
environment:
- NVIDIA_VISIBLE_DEVICES=all
Kubernetes mit GPU
apiVersion: apps/v1
kind: Deployment
metadata:
name: docling-backend
spec:
template:
spec:
containers:
- name: backend
resources:
limits:
nvidia.com/gpu: 1
Monitoring
Prometheus-Metriken
from prometheus_flask_exporter import PrometheusMetrics
metrics = PrometheusMetrics(app)
# Eigene Metriken
conversion_counter = metrics.counter(
'conversions_total',
'Gesamtzahl Konvertierungen',
labels={'status': lambda: 'success'}
)
Grafana-Dashboard
Wichtige Metriken:
- Konversionsrate (Dokumente/Minute)
- Warteschlangentiefe
- Bearbeitungszeit (p50, p95, p99)
- Fehlerrate
- Speicherverbrauch
- CPU-Auslastung
Kubernetes-Deployment
Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: docling-backend
spec:
replicas: 3
selector:
matchLabels:
app: docling-backend
template:
metadata:
labels:
app: docling-backend
spec:
containers:
- name: backend
image: duckling-backend:latest
ports:
- containerPort: 5001
resources:
requests:
memory: "2Gi"
cpu: "500m"
limits:
memory: "4Gi"
cpu: "2000m"
env:
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: docling-secrets
key: database-url
Service
apiVersion: v1
kind: Service
metadata:
name: docling-backend
spec:
selector:
app: docling-backend
ports:
- port: 5001
targetPort: 5001
type: ClusterIP