ARCHITECTURE
Intermédiaire

Sizing et Performance : Dimensionner son Infrastructure

Florian Courouge
18 min de lecture
3,353 mots
0 vues
Sizing
Performance
Capacity Planning
Infrastructure
Optimisation
Benchmark

Sizing et Performance : Dimensionner son Infrastructure

Le sizing (dimensionnement) est l'art de déterminer les ressources nécessaires pour qu'un système fonctionne de manière optimale. Un mauvais sizing coûte cher : trop peu = problèmes de performance, trop = gaspillage de ressources.

Méthodologie de sizing

Les questions à se poser

┌─────────────────────────────────────────────────────────────────┐
│              QUESTIONS CLÉS DU SIZING                           │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  1. CHARGE DE TRAVAIL                                           │
│     └─ Combien d'utilisateurs/requêtes ?                        │
│     └─ Quelle croissance prévue ?                               │
│     └─ Quels pics de charge ?                                   │
│                                                                  │
│  2. EXIGENCES DE PERFORMANCE                                    │
│     └─ Temps de réponse cible (P50, P95, P99) ?                │
│     └─ Throughput minimum ?                                     │
│     └─ SLA à respecter ?                                        │
│                                                                  │
│  3. DONNÉES                                                     │
│     └─ Volume actuel et croissance ?                            │
│     └─ Rétention nécessaire ?                                   │
│     └─ Patterns d'accès (read/write ratio) ?                    │
│                                                                  │
│  4. CONTRAINTES                                                 │
│     └─ Budget disponible ?                                      │
│     └─ Contraintes réglementaires (localisation) ?              │
│     └─ Compétences de l'équipe ?                                │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

La règle des 70%

:::tip Règle d'or : Ne jamais dépasser 70% d'utilisation en régime nominal pour garder une marge pour les pics et la croissance. :::

Capacité nécessaire = (Charge moyenne × 1.4) + Marge de croissance

Exemple:
- Charge moyenne : 1000 req/s
- Pic prévu : 1.5x = 1500 req/s
- Croissance annuelle : 30%

Capacité = 1000 × 1.4 × 1.3 = 1820 req/s minimum
→ Dimensionner pour ~2000 req/s

Sizing CPU

Comprendre l'utilisation CPU

# Voir le nombre de cœurs
nproc
cat /proc/cpuinfo | grep processor | wc -l

# Charge moyenne (load average)
uptime
# load average: 1.50, 1.20, 1.00
# = moyenne sur 1min, 5min, 15min
# Règle : load < nombre de cœurs = OK

# Analyse détaillée
mpstat -P ALL 1 5    # Stats par cœur
vmstat 1 10          # Vue d'ensemble

# Identifier les processus CPU-intensive
pidstat -u 1 5       # CPU par processus
ps aux --sort=-%cpu | head -10

Formules de calcul CPU

def calculate_cpu_requirements(
    requests_per_second: float,
    avg_processing_time_ms: float,
    target_utilization: float = 0.7,
    safety_margin: float = 1.3
) -> dict:
    """
    Calcule les besoins CPU pour une application web.

    Args:
        requests_per_second: Nombre de requêtes par seconde
        avg_processing_time_ms: Temps de traitement moyen en ms
        target_utilization: Utilisation cible (défaut 70%)
        safety_margin: Marge de sécurité (défaut 30%)
    """
    # Temps CPU nécessaire par seconde
    cpu_time_per_second = requests_per_second * (avg_processing_time_ms / 1000)

    # Nombre de cœurs théoriques
    theoretical_cores = cpu_time_per_second

    # Avec marge de sécurité et utilisation cible
    required_cores = (theoretical_cores * safety_margin) / target_utilization

    return {
        "requests_per_second": requests_per_second,
        "avg_processing_time_ms": avg_processing_time_ms,
        "cpu_seconds_per_second": round(cpu_time_per_second, 2),
        "theoretical_cores": round(theoretical_cores, 2),
        "required_cores": round(required_cores, 1),
        "recommendation": f"{int(required_cores + 0.9)} vCPUs"
    }

# Exemples
print(calculate_cpu_requirements(
    requests_per_second=1000,
    avg_processing_time_ms=50
))
# {'requests_per_second': 1000, 'avg_processing_time_ms': 50,
#  'cpu_seconds_per_second': 50.0, 'theoretical_cores': 50.0,
#  'required_cores': 92.9, 'recommendation': '93 vCPUs'}

# Application légère
print(calculate_cpu_requirements(
    requests_per_second=500,
    avg_processing_time_ms=10
))
# {'required_cores': 9.3, 'recommendation': '10 vCPUs'}

Types de charge CPU

Type Caractéristiques Sizing
CPU-bound Calculs intensifs, compression, crypto Plus de cœurs, fréquence haute
I/O-bound Attente disque/réseau, BDD Moins de cœurs, plus d'I/O
Memory-bound Gros datasets, caches CPU avec gros cache L3
Mixed Applications web typiques Balance CPU/RAM

Sizing mémoire (RAM)

Analyse des besoins mémoire

# Vue d'ensemble
free -h
# total        used        free      shared  buff/cache   available
# Mem:          32Gi       12Gi       8.0Gi       256Mi        11Gi        19Gi

# Détails
cat /proc/meminfo

# Par processus
ps aux --sort=-%mem | head -10
smem -tk              # Mémoire réelle par processus (USS, PSS, RSS)

# Mémoire des conteneurs
docker stats --no-stream

# Pages et swap
vmstat 1 5
# si "si" et "so" > 0, le système swappe = manque de RAM

Calcul des besoins mémoire

def calculate_memory_requirements(
    base_memory_mb: float,
    memory_per_connection_mb: float,
    concurrent_connections: int,
    cache_size_mb: float = 0,
    jvm_heap_ratio: float = None,
    safety_margin: float = 1.3
) -> dict:
    """
    Calcule les besoins mémoire pour une application.

    Args:
        base_memory_mb: Mémoire de base de l'application
        memory_per_connection_mb: Mémoire par connexion active
        concurrent_connections: Nombre de connexions simultanées
        cache_size_mb: Taille du cache applicatif
        jvm_heap_ratio: Ratio heap/total pour JVM (0.5-0.8)
        safety_margin: Marge de sécurité
    """
    # Mémoire applicative
    app_memory = base_memory_mb + (memory_per_connection_mb * concurrent_connections)

    # Avec cache
    total_app = app_memory + cache_size_mb

    # Mémoire totale avec marge
    total_required = total_app * safety_margin

    result = {
        "base_memory_mb": base_memory_mb,
        "connection_memory_mb": memory_per_connection_mb * concurrent_connections,
        "cache_memory_mb": cache_size_mb,
        "subtotal_mb": round(total_app, 0),
        "required_mb": round(total_required, 0),
        "required_gb": round(total_required / 1024, 1)
    }

    # Ajustement JVM si applicable
    if jvm_heap_ratio:
        jvm_total = total_required / jvm_heap_ratio
        result["jvm_total_mb"] = round(jvm_total, 0)
        result["jvm_total_gb"] = round(jvm_total / 1024, 1)
        result["recommended"] = f"{int(jvm_total / 1024 + 0.9)} GB"
    else:
        result["recommended"] = f"{int(total_required / 1024 + 0.9)} GB"

    return result

# Exemple : API REST Java
print(calculate_memory_requirements(
    base_memory_mb=512,          # JVM overhead
    memory_per_connection_mb=2,  # Par thread HTTP
    concurrent_connections=200,
    cache_size_mb=1024,          # 1GB cache
    jvm_heap_ratio=0.75          # Heap = 75% de la RAM allouée
))
# {'required_gb': 2.4, 'jvm_total_gb': 3.2, 'recommended': '4 GB'}

# Exemple : Application Node.js
print(calculate_memory_requirements(
    base_memory_mb=256,
    memory_per_connection_mb=0.5,
    concurrent_connections=1000,
    cache_size_mb=512
))
# {'required_gb': 1.4, 'recommended': '2 GB'}

Sizing mémoire par technologie

applications:
  java_spring:
    heap_min: "512m"
    heap_max: "selon charge"
    metaspace: "256m"
    ratio_heap_total: 0.75
    formula: "RAM = (Heap / 0.75) + OS overhead (500MB)"

  nodejs:
    heap_default: "512MB"
    heap_max: "4GB (V8 limit sur 64-bit)"
    per_connection: "0.5-2MB"
    formula: "RAM = Base(256MB) + Connections × 1MB + Cache"

  python:
    base: "100-500MB"
    per_worker: "150-300MB (gunicorn/uwsgi)"
    formula: "RAM = Workers × 300MB + Cache + 500MB OS"

  go:
    base: "50-100MB"
    per_goroutine: "2KB stack (grow to 1GB)"
    formula: "RAM = Base + Goroutines × 8KB (average) + Heap"

databases:
  postgresql:
    shared_buffers: "25% of RAM"
    effective_cache_size: "75% of RAM"
    work_mem: "4MB-64MB (× max_connections)"
    maintenance_work_mem: "256MB-1GB"
    formula: "RAM = max(4GB, Data × 0.2)"

  mysql:
    innodb_buffer_pool: "70-80% of RAM"
    formula: "RAM = Working Set × 1.2"

  redis:
    maxmemory: "actual data × 1.5-2"
    formula: "RAM = Data + Replication buffer + OS(1GB)"

  elasticsearch:
    heap: "50% of RAM, max 31GB"
    filesystem_cache: "remaining 50%"
    formula: "RAM = min(Data, 64GB) ideally"

kafka:
  heap: "4-8GB typically"
  page_cache: "critical for performance"
  formula: "RAM = Heap(6GB) + PageCache(segments × 2)"

Sizing stockage

Types de stockage et performance

┌─────────────────────────────────────────────────────────────────┐
│               COMPARATIF TYPES DE STOCKAGE                      │
├────────────┬──────────┬──────────┬──────────┬──────────────────┤
│   Type     │  IOPS    │ Latence  │  Débit   │  Cas d'usage     │
├────────────┼──────────┼──────────┼──────────┼──────────────────┤
│ HDD SATA   │ 80-160   │ 5-10ms   │ 100MB/s  │ Archivage, logs  │
│ HDD SAS    │ 150-200  │ 4-8ms    │ 150MB/s  │ BDD legacy       │
│ SSD SATA   │ 20-90K   │ 0.1ms    │ 500MB/s  │ BDD, apps        │
│ SSD NVMe   │ 100-500K │ 0.02ms   │ 3GB/s    │ BDD critique     │
│ Cloud gp3  │ 3-16K    │ ~1ms     │ 125-1000 │ Usage général    │
│ Cloud io2  │ 64K      │ <1ms     │ 4GB/s    │ BDD IOPS-heavy   │
└────────────┴──────────┴──────────┴──────────┴──────────────────┘

Calcul des besoins IOPS

def calculate_storage_requirements(
    read_ops_per_second: int,
    write_ops_per_second: int,
    avg_io_size_kb: int = 8,
    read_write_ratio: float = 0.7,
    raid_overhead: float = 1.0,
    safety_margin: float = 1.3
) -> dict:
    """
    Calcule les besoins de stockage en IOPS et débit.

    Args:
        read_ops_per_second: Opérations de lecture par seconde
        write_ops_per_second: Opérations d'écriture par seconde
        avg_io_size_kb: Taille moyenne d'une I/O en KB
        read_write_ratio: Ratio lecture/total (0.7 = 70% reads)
        raid_overhead: Multiplicateur RAID (1.0 = pas de RAID)
        safety_margin: Marge de sécurité
    """
    # IOPS totaux
    total_iops = (read_ops_per_second + write_ops_per_second * raid_overhead)

    # Avec marge
    required_iops = total_iops * safety_margin

    # Débit
    throughput_mbps = (total_iops * avg_io_size_kb) / 1024

    return {
        "read_iops": read_ops_per_second,
        "write_iops": write_ops_per_second,
        "total_iops": round(total_iops, 0),
        "required_iops": round(required_iops, 0),
        "throughput_mbps": round(throughput_mbps, 1),
        "required_throughput_mbps": round(throughput_mbps * safety_margin, 1),
        "recommended_storage": recommend_storage_type(required_iops)
    }

def recommend_storage_type(iops: float) -> str:
    if iops < 500:
        return "HDD SATA (ou gp2/gp3 minimal)"
    elif iops < 5000:
        return "SSD SATA ou Cloud gp3"
    elif iops < 20000:
        return "SSD NVMe ou Cloud gp3 provisionné"
    elif iops < 64000:
        return "NVMe haute perf ou Cloud io2"
    else:
        return "Multiple NVMe en RAID ou distributed storage"

# Exemple : Base de données transactionnelle
print(calculate_storage_requirements(
    read_ops_per_second=5000,
    write_ops_per_second=2000,
    avg_io_size_kb=8,
    raid_overhead=2.0  # RAID 10
))
# {'required_iops': 11700, 'recommended_storage': 'SSD NVMe ou Cloud gp3 provisionné'}

Sizing capacité disque

def calculate_storage_capacity(
    initial_data_gb: float,
    daily_growth_gb: float,
    retention_days: int,
    replication_factor: int = 1,
    compression_ratio: float = 1.0,
    filesystem_overhead: float = 0.1,
    growth_buffer_percent: float = 0.3
) -> dict:
    """
    Calcule la capacité de stockage nécessaire.

    Args:
        initial_data_gb: Données initiales en GB
        daily_growth_gb: Croissance journalière en GB
        retention_days: Durée de rétention en jours
        replication_factor: Facteur de réplication
        compression_ratio: Ratio de compression (0.5 = 50% de l'original)
        filesystem_overhead: Overhead filesystem (10% par défaut)
        growth_buffer_percent: Marge pour croissance imprévue
    """
    # Données après rétention
    retention_data = daily_growth_gb * retention_days

    # Total logique
    logical_data = initial_data_gb + retention_data

    # Avec compression
    compressed_data = logical_data * compression_ratio

    # Avec réplication
    replicated_data = compressed_data * replication_factor

    # Avec overhead filesystem
    with_overhead = replicated_data * (1 + filesystem_overhead)

    # Avec buffer de croissance
    total_required = with_overhead * (1 + growth_buffer_percent)

    return {
        "initial_data_gb": initial_data_gb,
        "retention_data_gb": round(retention_data, 1),
        "logical_total_gb": round(logical_data, 1),
        "after_compression_gb": round(compressed_data, 1),
        "after_replication_gb": round(replicated_data, 1),
        "required_capacity_gb": round(total_required, 0),
        "required_capacity_tb": round(total_required / 1024, 2)
    }

# Exemple : Logs applicatifs
print(calculate_storage_capacity(
    initial_data_gb=0,
    daily_growth_gb=50,       # 50 GB de logs/jour
    retention_days=30,        # 30 jours de rétention
    replication_factor=3,     # Triple réplication (ES, Kafka...)
    compression_ratio=0.3     # 70% de compression
))
# {'required_capacity_tb': 1.91}

# Exemple : Base de données
print(calculate_storage_capacity(
    initial_data_gb=500,
    daily_growth_gb=5,
    retention_days=365,       # 1 an
    replication_factor=2,     # Primary + replica
    compression_ratio=0.6     # 40% de compression
))
# {'required_capacity_tb': 3.63}

Sizing réseau

Calcul de bande passante

def calculate_bandwidth(
    requests_per_second: int,
    avg_request_size_kb: float,
    avg_response_size_kb: float,
    peak_multiplier: float = 2.0,
    overhead_percent: float = 0.2
) -> dict:
    """
    Calcule les besoins en bande passante.

    Args:
        requests_per_second: Nombre de requêtes par seconde
        avg_request_size_kb: Taille moyenne des requêtes (KB)
        avg_response_size_kb: Taille moyenne des réponses (KB)
        peak_multiplier: Multiplicateur pour les pics
        overhead_percent: Overhead réseau (headers, retransmissions)
    """
    # Bande passante en KB/s
    inbound_kbps = requests_per_second * avg_request_size_kb
    outbound_kbps = requests_per_second * avg_response_size_kb

    # Conversion en Mbps
    inbound_mbps = (inbound_kbps * 8) / 1000
    outbound_mbps = (outbound_kbps * 8) / 1000

    # Avec overhead
    inbound_with_overhead = inbound_mbps * (1 + overhead_percent)
    outbound_with_overhead = outbound_mbps * (1 + overhead_percent)

    # Pour les pics
    peak_inbound = inbound_with_overhead * peak_multiplier
    peak_outbound = outbound_with_overhead * peak_multiplier

    return {
        "steady_state": {
            "inbound_mbps": round(inbound_with_overhead, 1),
            "outbound_mbps": round(outbound_with_overhead, 1),
            "total_mbps": round(inbound_with_overhead + outbound_with_overhead, 1)
        },
        "peak": {
            "inbound_mbps": round(peak_inbound, 1),
            "outbound_mbps": round(peak_outbound, 1),
            "total_mbps": round(peak_inbound + peak_outbound, 1)
        },
        "recommended_link": recommend_network_link(peak_inbound + peak_outbound)
    }

def recommend_network_link(mbps: float) -> str:
    if mbps < 100:
        return "100 Mbps"
    elif mbps < 1000:
        return "1 Gbps"
    elif mbps < 10000:
        return "10 Gbps"
    elif mbps < 25000:
        return "25 Gbps"
    else:
        return "40/100 Gbps ou bonding"

# Exemple : API REST
print(calculate_bandwidth(
    requests_per_second=10000,
    avg_request_size_kb=2,    # Petites requêtes
    avg_response_size_kb=10   # Réponses JSON moyennes
))
# {'peak': {'total_mbps': 2880.0}, 'recommended_link': '10 Gbps'}

# Exemple : Streaming vidéo
print(calculate_bandwidth(
    requests_per_second=1000,
    avg_request_size_kb=1,
    avg_response_size_kb=500  # Chunks vidéo
))
# {'peak': {'total_mbps': 12009.6}, 'recommended_link': '25 Gbps'}

Benchmarking et validation

Outils de benchmark

# CPU
sysbench cpu --threads=4 run
stress-ng --cpu 4 --timeout 60s --metrics

# Mémoire
sysbench memory --threads=4 run
stress-ng --vm 2 --vm-bytes 2G --timeout 60s

# Disque
fio --name=random-rw --ioengine=libaio --iodepth=32 \
    --rw=randrw --bs=4k --size=1G --numjobs=4 \
    --runtime=60 --time_based --group_reporting

# Séquentiel
fio --name=seq-read --ioengine=libaio --iodepth=32 \
    --rw=read --bs=1M --size=1G --numjobs=1 \
    --runtime=60 --time_based

# Réseau
iperf3 -c server_ip -t 30 -P 4    # Client
iperf3 -s                          # Server

# HTTP
wrk -t12 -c400 -d30s http://localhost:8080/api/health
ab -n 10000 -c 100 http://localhost:8080/api/health
hey -n 10000 -c 100 http://localhost:8080/api/health
k6 run loadtest.js

Script de benchmark complet

#!/bin/bash
# Benchmark système complet

echo "=== SYSTEM BENCHMARK ==="
echo "Date: $(date)"
echo "Host: $(hostname)"
echo ""

# Info système
echo "=== SYSTEM INFO ==="
echo "CPU: $(nproc) cores"
echo "RAM: $(free -h | awk '/^Mem:/{print $2}')"
echo "Kernel: $(uname -r)"
echo ""

# Benchmark CPU
echo "=== CPU BENCHMARK ==="
sysbench cpu --threads=$(nproc) run 2>/dev/null | grep -E "(events per second|total time)"
echo ""

# Benchmark mémoire
echo "=== MEMORY BENCHMARK ==="
sysbench memory --threads=$(nproc) run 2>/dev/null | grep -E "(transferred|total time)"
echo ""

# Benchmark disque (si fio installé)
if command -v fio &> /dev/null; then
    echo "=== DISK BENCHMARK ==="
    echo "Random 4K Read/Write:"
    fio --name=test --ioengine=libaio --iodepth=32 \
        --rw=randrw --bs=4k --size=256M --numjobs=4 \
        --runtime=30 --time_based --group_reporting 2>/dev/null | \
        grep -E "(read:|write:|iops)"

    echo ""
    echo "Sequential 1M Read:"
    fio --name=seq --ioengine=libaio --iodepth=32 \
        --rw=read --bs=1M --size=1G --numjobs=1 \
        --runtime=30 --time_based 2>/dev/null | \
        grep -E "(read:|bw=)"
fi
echo ""

echo "=== BENCHMARK COMPLETE ==="

Capacity Planning

Processus de capacity planning

┌─────────────────────────────────────────────────────────────────┐
│              CYCLE DE CAPACITY PLANNING                         │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│   1. MESURER                     2. ANALYSER                    │
│   ┌─────────────┐                ┌─────────────┐               │
│   │ Collecter   │───────────────▶│ Identifier  │               │
│   │ métriques   │                │ tendances   │               │
│   │ actuelles   │                │ et patterns │               │
│   └─────────────┘                └──────┬──────┘               │
│         ▲                               │                        │
│         │                               ▼                        │
│   ┌─────┴─────┐                  ┌─────────────┐               │
│   │ Implémenter│                 │  Prévoir    │               │
│   │ changements│◀────────────────│  besoins    │               │
│   └───────────┘                  │  futurs     │               │
│   4. AGIR                        └─────────────┘               │
│                                  3. PROJETER                    │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

Modèle de projection

import math
from datetime import datetime, timedelta

def project_resource_needs(
    current_value: float,
    monthly_growth_rate: float,
    projection_months: int,
    threshold_percent: float = 0.8
) -> list:
    """
    Projette les besoins futurs et identifie quand le seuil sera atteint.

    Args:
        current_value: Valeur actuelle (ex: utilisation CPU %)
        monthly_growth_rate: Taux de croissance mensuel (0.1 = 10%)
        projection_months: Nombre de mois à projeter
        threshold_percent: Seuil d'alerte (0.8 = 80%)
    """
    projections = []
    today = datetime.now()

    for month in range(projection_months + 1):
        date = today + timedelta(days=30 * month)
        # Croissance composée
        projected = current_value * ((1 + monthly_growth_rate) ** month)

        status = "OK"
        if projected >= threshold_percent * 100:
            status = "WARNING"
        if projected >= 100:
            status = "CRITICAL"

        projections.append({
            "month": month,
            "date": date.strftime("%Y-%m"),
            "projected_percent": round(min(projected, 100), 1),
            "status": status
        })

    # Trouver le mois où le seuil est atteint
    threshold_month = None
    for p in projections:
        if p["status"] != "OK" and threshold_month is None:
            threshold_month = p["month"]
            break

    return {
        "projections": projections,
        "threshold_reached_month": threshold_month,
        "action_required": threshold_month is not None and threshold_month <= 6
    }

# Exemple
result = project_resource_needs(
    current_value=45,          # 45% d'utilisation actuelle
    monthly_growth_rate=0.08,  # 8% de croissance/mois
    projection_months=12,
    threshold_percent=0.8
)

print("Projection CPU:")
for p in result["projections"]:
    print(f"  {p['date']}: {p['projected_percent']}% [{p['status']}]")

if result["action_required"]:
    print(f"\n⚠️  Action requise : seuil atteint dans {result['threshold_reached_month']} mois")

Checklist sizing

## Avant le sizing
- [ ] Définir les SLA/SLO cibles
- [ ] Identifier les pics de charge
- [ ] Estimer la croissance sur 12-24 mois
- [ ] Benchmarker l'application existante
- [ ] Documenter les contraintes budget

## CPU
- [ ] Profiler l'application (CPU-bound vs I/O-bound)
- [ ] Calculer les besoins en régime nominal
- [ ] Prévoir 30% de marge pour les pics
- [ ] Considérer le burst capacity (cloud)

## Mémoire
- [ ] Identifier les consumers (app, cache, OS)
- [ ] Calculer la mémoire par connexion
- [ ] Ajouter la marge pour GC (JVM)
- [ ] Éviter le swap à tout prix

## Stockage
- [ ] Calculer les IOPS nécessaires
- [ ] Projeter la croissance des données
- [ ] Choisir le type adapté (SSD/NVMe)
- [ ] Prévoir la rétention et backups

## Réseau
- [ ] Calculer la bande passante
- [ ] Prévoir les pics (×2 à ×3)
- [ ] Considérer la latence inter-zone
- [ ] Dimensionner les load balancers

## Validation
- [ ] Tests de charge avant mise en prod
- [ ] Monitoring post-déploiement
- [ ] Review trimestrielle du capacity plan

Conclusion

Un bon sizing repose sur :

  1. Des données réelles : Benchmarks, métriques, historique
  2. Des marges de sécurité : 30% minimum pour les imprévus
  3. Une vision long terme : Projeter sur 12-24 mois
  4. Une validation continue : Monitoring et ajustements

:::warning Erreur courante : Dimensionner pour la charge moyenne au lieu de la charge de pointe. Toujours prévoir les pics ! :::


Ressources complémentaires

F

Florian Courouge

Expert DevOps & Kafka | Consultant freelance specialise dans les architectures distribuees et le streaming de donnees.

Articles similaires