927 lines
24 KiB
Markdown
927 lines
24 KiB
Markdown
# ORIGIN_PERFORMANCE_TARGETS.md
|
|
|
|
## 📋 RÉSUMÉ EXÉCUTIF
|
|
|
|
Ce document définit les objectifs de performance mesurables et réalistes pour tous les composants de la plateforme Veza. Il spécifie targets précis pour latence API (p95 < 100ms, p99 < 200ms), database (p95 < 10ms), frontend (Lighthouse Performance ≥ 90, Accessibility ≥ 95), audio streaming (start < 500ms, rebuffering < 0.5%), avec monitoring (Prometheus), plan de mesure (Lighthouse CI, k6, pg_stat_statements), et optimization strategies garantissant expérience utilisateur fluide et scalabilité production.
|
|
|
|
## 🎯 OBJECTIFS
|
|
|
|
### Objectif Principal
|
|
Garantir performance optimale avec latence API < 100ms (p95), temps chargement < 2s, zero buffering audio/vidéo, et scalabilité jusqu'à 100K utilisateurs concurrents avec dégradation gracieuse.
|
|
|
|
### Objectifs Secondaires
|
|
- Optimiser ressources (CPU < 70%, RAM < 80%)
|
|
- Réduire coûts infrastructure (efficient resource utilization)
|
|
- Détecter régressions performance automatiquement (CI/CD)
|
|
- Fournir expérience utilisateur fluide (no jank, 60 FPS)
|
|
|
|
## 📖 TABLE DES MATIÈRES
|
|
|
|
1. [Performance Philosophy](#1-performance-philosophy)
|
|
2. [Backend Performance Targets](#2-backend-performance-targets)
|
|
3. [Frontend Performance Targets](#3-frontend-performance-targets)
|
|
4. [Database Performance Targets](#4-database-performance-targets)
|
|
5. [Network Performance Targets](#5-network-performance-targets)
|
|
6. [Audio Streaming Performance](#6-audio-streaming-performance)
|
|
7. [Monitoring & Alerting](#7-monitoring--alerting)
|
|
8. [Performance Testing](#8-performance-testing)
|
|
9. [Optimization Strategies](#9-optimization-strategies)
|
|
10. [Performance Budgets](#10-performance-budgets)
|
|
|
|
## 🔒 RÈGLES IMMUABLES
|
|
|
|
1. **API Latency**: p95 < 100ms, p99 < 200ms - CI/CD bloque si dépassé
|
|
2. **Database Queries**: p95 < 10ms - N+1 queries interdites
|
|
3. **Frontend Load**: First Contentful Paint < 1.5s, Time to Interactive < 3.5s
|
|
4. **Bundle Size**: Initial JS bundle < 200KB gzipped
|
|
5. **Memory Leaks**: Zero memory leaks tolérés (CI/CD checks)
|
|
6. **Audio Streaming**: Rebuffering < 0.5%, stream start < 500ms
|
|
7. **Throughput**: Min 10K req/s sustained (backend)
|
|
8. **Resource Usage**: CPU < 70%, Memory < 80% (average)
|
|
9. **Cache Hit Rate**: > 90% for frequently accessed data
|
|
10. **Mobile Performance**: Lighthouse Performance score ≥ 90
|
|
|
|
## 1. PERFORMANCE PHILOSOPHY
|
|
|
|
### 1.1 Performance Principles
|
|
|
|
**User-Centric Performance**:
|
|
- **Perceived Performance > Actual Performance**: Users care about what they experience
|
|
- **Critical Rendering Path**: Optimize what users see first
|
|
- **Progressive Enhancement**: Core functionality works fast, enhancements load progressively
|
|
|
|
**Performance Metrics Hierarchy**:
|
|
```
|
|
1. Core Web Vitals (Google)
|
|
- LCP (Largest Contentful Paint) < 2.5s
|
|
- FID (First Input Delay) < 100ms
|
|
- CLS (Cumulative Layout Shift) < 0.1
|
|
|
|
2. Custom Business Metrics
|
|
- Time to First Track Play < 3s
|
|
- Search Results < 500ms
|
|
- Upload Progress Feedback < 100ms
|
|
```
|
|
|
|
### 1.2 Performance SLOs (Service Level Objectives)
|
|
|
|
| Metric | Target | Stretch Goal |
|
|
|--------|--------|--------------|
|
|
| **API Response Time (p95)** | < 100ms | < 50ms |
|
|
| **API Response Time (p99)** | < 200ms | < 100ms |
|
|
| **Database Query (p95)** | < 10ms | < 5ms |
|
|
| **Frontend Load (FCP)** | < 1.5s | < 1s |
|
|
| **Frontend Load (TTI)** | < 3.5s | < 2s |
|
|
| **Audio Stream Start** | < 500ms | < 300ms |
|
|
| **Search Results** | < 500ms | < 200ms |
|
|
| **Uptime** | 99.9% | 99.99% |
|
|
|
|
## 2. BACKEND PERFORMANCE TARGETS
|
|
|
|
### 2.1 API Response Times
|
|
|
|
**Endpoints Performance Targets**:
|
|
|
|
| Endpoint Category | p50 | p95 | p99 | Examples |
|
|
|-------------------|-----|-----|-----|----------|
|
|
| **Simple Reads** | < 20ms | < 50ms | < 100ms | GET /users/{id}, GET /tracks/{id} |
|
|
| **Complex Reads** | < 50ms | < 100ms | < 200ms | GET /tracks (with filters), GET /search |
|
|
| **Writes** | < 50ms | < 150ms | < 300ms | POST /users, PUT /tracks/{id} |
|
|
| **File Uploads** | < 2s | < 5s | < 10s | POST /tracks (upload) |
|
|
| **Aggregations** | < 100ms | < 300ms | < 500ms | GET /analytics/dashboard |
|
|
|
|
**Critical Endpoints** (Strict Targets):
|
|
- `GET /tracks/{id}`: p95 < 30ms
|
|
- `POST /tracks/{id}/play`: p95 < 20ms
|
|
- `GET /search?q=`: p95 < 200ms
|
|
- `POST /auth/login`: p95 < 100ms
|
|
- `GET /feed`: p95 < 150ms
|
|
|
|
### 2.2 Throughput Targets
|
|
|
|
| Endpoint | Target RPS | Peak RPS | Concurrent Users |
|
|
|----------|------------|----------|------------------|
|
|
| **GET /tracks** | 5,000 | 10,000 | 50,000 |
|
|
| **POST /tracks/{id}/play** | 10,000 | 20,000 | 100,000 |
|
|
| **GET /search** | 2,000 | 5,000 | 20,000 |
|
|
| **POST /auth/login** | 500 | 1,000 | 5,000 |
|
|
| **WebSocket connections** | 10,000 | 20,000 | 20,000 |
|
|
|
|
### 2.3 Resource Utilization
|
|
|
|
**Per Service Limits**:
|
|
```yaml
|
|
backend-api:
|
|
cpu_usage: < 70% (average), < 90% (peak)
|
|
memory_usage: < 80% (average), < 95% (peak)
|
|
goroutines: < 10,000
|
|
database_connections: < 100 (per instance)
|
|
|
|
chat-server:
|
|
cpu_usage: < 60%
|
|
memory_usage: < 70%
|
|
websocket_connections: < 10,000 (per instance)
|
|
message_throughput: > 50,000 msg/s
|
|
|
|
stream-server:
|
|
cpu_usage: < 80% (audio processing intensive)
|
|
memory_usage: < 75%
|
|
concurrent_streams: > 5,000
|
|
bandwidth: > 10 Gbps
|
|
```
|
|
|
|
### 2.4 Error Rates
|
|
|
|
| Error Type | Target | Alert Threshold |
|
|
|------------|--------|-----------------|
|
|
| **4xx Errors** | < 1% | > 2% |
|
|
| **5xx Errors** | < 0.1% | > 0.5% |
|
|
| **Timeouts** | < 0.01% | > 0.1% |
|
|
| **Database Errors** | < 0.01% | > 0.05% |
|
|
|
|
## 3. FRONTEND PERFORMANCE TARGETS
|
|
|
|
### 3.1 Core Web Vitals
|
|
|
|
**Lighthouse Scores** :
|
|
- **Performance**: ≥ 90
|
|
- **Accessibility**: ≥ 95
|
|
- **Best Practices**: ≥ 90
|
|
- **SEO**: ≥ 90
|
|
|
|
**Detailed Metrics**:
|
|
|
|
| Metric | Good | Needs Improvement | Poor | Target |
|
|
|--------|------|-------------------|------|--------|
|
|
| **LCP (Largest Contentful Paint)** | ≤ 2.5s | 2.5s - 4.0s | > 4.0s | **< 2s** |
|
|
| **FID (First Input Delay)** | ≤ 100ms | 100ms - 300ms | > 300ms | **< 50ms** |
|
|
| **CLS (Cumulative Layout Shift)** | ≤ 0.1 | 0.1 - 0.25 | > 0.25 | **< 0.05** |
|
|
| **FCP (First Contentful Paint)** | ≤ 1.8s | 1.8s - 3.0s | > 3.0s | **< 1.5s** |
|
|
| **TTI (Time to Interactive)** | ≤ 3.8s | 3.8s - 7.3s | > 7.3s | **< 3.5s** |
|
|
| **TBT (Total Blocking Time)** | ≤ 200ms | 200ms - 600ms | > 600ms | **< 150ms** |
|
|
| **Speed Index** | ≤ 3.4s | 3.4s - 5.8s | > 5.8s | **< 3s** |
|
|
|
|
### 3.2 Bundle Size
|
|
|
|
**JavaScript Bundles**:
|
|
```
|
|
Initial Bundle (gzipped):
|
|
├── vendor.js (React, Router, etc.): < 150 KB
|
|
├── main.js (App code): < 50 KB
|
|
└── TOTAL: < 200 KB
|
|
|
|
Lazy-Loaded Bundles:
|
|
├── dashboard.js: < 30 KB
|
|
├── player.js: < 40 KB
|
|
├── upload.js: < 25 KB
|
|
└── admin.js: < 50 KB
|
|
|
|
CSS:
|
|
├── main.css (Tailwind): < 20 KB (purged)
|
|
└── fonts: < 50 KB (subset)
|
|
```
|
|
|
|
**Image Optimization**:
|
|
- **Hero Images**: < 100 KB (WebP)
|
|
- **Thumbnails**: < 20 KB (WebP)
|
|
- **Avatars**: < 10 KB (WebP)
|
|
- **Icons**: Inline SVG or sprite sheet < 5 KB
|
|
|
|
### 3.3 Runtime Performance
|
|
|
|
**Frame Rate**:
|
|
- **Animations**: 60 FPS (16.67ms per frame)
|
|
- **Scrolling**: Smooth (no jank)
|
|
- **Interactions**: < 100ms response time
|
|
|
|
**Memory Usage**:
|
|
- **Initial Load**: < 50 MB
|
|
- **Peak Usage**: < 150 MB
|
|
- **Memory Leaks**: Zero (CI/CD checks)
|
|
|
|
### 3.4 Mobile Performance
|
|
|
|
**Mobile-Specific Targets** (4G connection):
|
|
- **FCP**: < 2.5s
|
|
- **TTI**: < 5s
|
|
- **Bundle Size**: < 150 KB initial
|
|
- **Lighthouse Performance**: ≥ 90
|
|
|
|
## 4. DATABASE PERFORMANCE TARGETS
|
|
|
|
### 4.1 Query Performance
|
|
|
|
**Query Latency Targets**:
|
|
|
|
| Query Type | p50 | p95 | p99 | Examples |
|
|
|------------|-----|-----|-----|----------|
|
|
| **Simple SELECT** | < 2ms | < 5ms | < 10ms | SELECT * FROM users WHERE id = ? |
|
|
| **JOIN (2 tables)** | < 5ms | < 10ms | < 20ms | Users JOIN Tracks |
|
|
| **JOIN (3+ tables)** | < 10ms | < 20ms | < 50ms | Complex queries |
|
|
| **Aggregations** | < 10ms | < 30ms | < 100ms | COUNT, SUM, AVG |
|
|
| **Full-Text Search** | < 20ms | < 50ms | < 100ms | GIN index searches |
|
|
| **INSERT** | < 3ms | < 10ms | < 20ms | Single row insert |
|
|
| **UPDATE** | < 5ms | < 15ms | < 30ms | Single row update |
|
|
|
|
**Slow Query Threshold**: > 100ms (logged and investigated)
|
|
|
|
### 4.2 Connection Pool
|
|
|
|
**PgBouncer Configuration**:
|
|
```ini
|
|
[pgbouncer]
|
|
pool_mode = transaction
|
|
max_client_conn = 1000
|
|
default_pool_size = 25
|
|
min_pool_size = 10
|
|
reserve_pool_size = 5
|
|
max_db_connections = 100
|
|
|
|
# Performance
|
|
query_timeout = 30
|
|
idle_transaction_timeout = 60
|
|
```
|
|
|
|
**Metrics Targets**:
|
|
- **Connection Utilization**: < 80%
|
|
- **Wait Time**: < 10ms
|
|
- **Connection Errors**: < 0.01%
|
|
|
|
### 4.3 Index Performance
|
|
|
|
**Index Requirements**:
|
|
- **Index Hit Rate**: > 99%
|
|
- **Sequential Scans on Large Tables**: Zero (always use indexes)
|
|
- **Index Size**: < 20% of table size
|
|
|
|
**Monitoring Queries**:
|
|
```sql
|
|
-- Index usage
|
|
SELECT schemaname, tablename, indexname, idx_scan
|
|
FROM pg_stat_user_indexes
|
|
WHERE idx_scan < 100
|
|
ORDER BY idx_scan;
|
|
|
|
-- Missing indexes (high seq scans)
|
|
SELECT schemaname, tablename, seq_scan, seq_tup_read
|
|
FROM pg_stat_user_tables
|
|
WHERE seq_scan > 1000
|
|
ORDER BY seq_tup_read DESC;
|
|
```
|
|
|
|
### 4.4 Cache Hit Ratio
|
|
|
|
**PostgreSQL Cache**:
|
|
- **Shared Buffers Hit Rate**: > 95%
|
|
- **Index Hit Rate**: > 99%
|
|
|
|
**Application Cache (Redis)**:
|
|
- **Hit Rate**: > 90%
|
|
- **Latency**: < 1ms (p95)
|
|
- **Eviction Rate**: < 5%
|
|
|
|
## 5. NETWORK PERFORMANCE TARGETS
|
|
|
|
### 5.1 API Response Sizes
|
|
|
|
**Payload Sizes**:
|
|
```
|
|
Endpoints:
|
|
GET /users/{id}: < 2 KB
|
|
GET /tracks: < 50 KB (20 items)
|
|
GET /tracks/{id}: < 5 KB
|
|
GET /search: < 100 KB (50 results)
|
|
GET /feed: < 200 KB (100 items)
|
|
|
|
Images (served via CDN):
|
|
Thumbnail (200x200): < 20 KB (WebP)
|
|
Cover (800x800): < 100 KB (WebP)
|
|
Banner (1920x400): < 150 KB (WebP)
|
|
```
|
|
|
|
### 5.2 CDN Performance
|
|
|
|
**CDN Metrics**:
|
|
- **Cache Hit Ratio**: > 95%
|
|
- **Latency (p95)**: < 50ms
|
|
- **Bandwidth**: > 10 Gbps
|
|
- **Geographic Coverage**: < 100ms from any location
|
|
|
|
**CDN Configuration**:
|
|
```nginx
|
|
# Cache headers
|
|
location /static/ {
|
|
expires 1y;
|
|
add_header Cache-Control "public, immutable";
|
|
}
|
|
|
|
location /api/ {
|
|
expires -1;
|
|
add_header Cache-Control "no-cache, no-store, must-revalidate";
|
|
}
|
|
```
|
|
|
|
### 5.3 Compression
|
|
|
|
**Gzip/Brotli Compression**:
|
|
- **Text (HTML, CSS, JS, JSON)**: Enabled (Brotli level 6)
|
|
- **Images**: Pre-compressed (WebP, AVIF)
|
|
- **Audio**: No compression (already compressed)
|
|
|
|
**Compression Ratios**:
|
|
- **JS/CSS**: 70-80% reduction
|
|
- **JSON**: 60-70% reduction
|
|
- **HTML**: 50-60% reduction
|
|
|
|
## 6. AUDIO STREAMING PERFORMANCE
|
|
|
|
### 6.1 Streaming Latency
|
|
|
|
**Latency Targets**:
|
|
- **Stream Start**: < 500ms (target: 300ms)
|
|
- **Buffer Fill**: < 200ms
|
|
- **Seek Time**: < 100ms
|
|
- **Quality Switch**: < 50ms (adaptive bitrate)
|
|
|
|
**Buffering**:
|
|
- **Initial Buffer**: 2 seconds
|
|
- **Rebuffering rate**: < 0.5% des sessions de lecture
|
|
- **Rebuffering Events**: < 0.5% of plays
|
|
|
|
### 6.2 Audio Quality
|
|
|
|
**Adaptive Bitrate Streaming**:
|
|
```
|
|
Network Speed → Bitrate:
|
|
< 500 kbps: 64 kbps (low quality)
|
|
500 kbps - 1 Mbps: 128 kbps (medium quality)
|
|
1 Mbps - 5 Mbps: 256 kbps (high quality)
|
|
> 5 Mbps: 320 kbps (premium quality)
|
|
```
|
|
|
|
**Format Support**:
|
|
- **Lossy**: MP3 (320 kbps), AAC (256 kbps), Opus (128 kbps)
|
|
- **Lossless**: FLAC (16-bit/44.1kHz)
|
|
|
|
### 6.3 Concurrent Streams
|
|
|
|
**Capacity Targets**:
|
|
- **Per Server**: 5,000 concurrent streams
|
|
- **Total Capacity**: 100,000 concurrent streams (20 servers)
|
|
- **Bandwidth**: 10 Gbps per server (avg 256 kbps/stream)
|
|
|
|
## 7. MONITORING & ALERTING
|
|
|
|
### 7.1 Prometheus Metrics
|
|
|
|
**RED Metrics** (Rate, Errors, Duration):
|
|
```promql
|
|
# Request Rate
|
|
rate(http_requests_total[5m])
|
|
|
|
# Error Rate
|
|
rate(http_requests_total{status=~"5.."}[5m]) / rate(http_requests_total[5m])
|
|
|
|
# Duration (Latency)
|
|
histogram_quantile(0.95, rate(http_request_duration_seconds_bucket[5m]))
|
|
```
|
|
|
|
**USE Metrics** (Utilization, Saturation, Errors):
|
|
```promql
|
|
# CPU Utilization
|
|
100 - (avg by (instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)
|
|
|
|
# Memory Utilization
|
|
(node_memory_MemTotal_bytes - node_memory_MemAvailable_bytes) / node_memory_MemTotal_bytes * 100
|
|
|
|
# Disk Saturation
|
|
rate(node_disk_io_time_seconds_total[5m])
|
|
```
|
|
|
|
### 7.2 Alerting Rules
|
|
|
|
**Critical Alerts** (PagerDuty):
|
|
```yaml
|
|
groups:
|
|
- name: critical_alerts
|
|
interval: 30s
|
|
rules:
|
|
- alert: HighErrorRate
|
|
expr: rate(http_requests_total{status=~"5.."}[5m]) / rate(http_requests_total[5m]) > 0.01
|
|
for: 2m
|
|
labels:
|
|
severity: critical
|
|
annotations:
|
|
summary: "High error rate detected ({{ $value }}%)"
|
|
|
|
- alert: HighLatency
|
|
expr: histogram_quantile(0.95, rate(http_request_duration_seconds_bucket[5m])) > 0.1
|
|
for: 5m
|
|
labels:
|
|
severity: critical
|
|
annotations:
|
|
summary: "API latency p95 > 100ms ({{ $value }}s)"
|
|
|
|
- alert: DatabaseDown
|
|
expr: up{job="postgres"} == 0
|
|
for: 1m
|
|
labels:
|
|
severity: critical
|
|
annotations:
|
|
summary: "PostgreSQL is down"
|
|
```
|
|
|
|
**Warning Alerts** (Slack):
|
|
```yaml
|
|
- alert: ModerateCPUUsage
|
|
expr: 100 - (avg by (instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) > 70
|
|
for: 10m
|
|
labels:
|
|
severity: warning
|
|
annotations:
|
|
summary: "CPU usage > 70% for 10 minutes"
|
|
|
|
- alert: SlowQueries
|
|
expr: rate(postgres_slow_queries_total[5m]) > 10
|
|
for: 5m
|
|
labels:
|
|
severity: warning
|
|
annotations:
|
|
summary: "High number of slow queries (> 10/min)"
|
|
```
|
|
|
|
### 7.3 Grafana Dashboards
|
|
|
|
**Dashboard 1: API Performance**
|
|
- Request rate (RPS)
|
|
- Latency (p50, p95, p99)
|
|
- Error rate (4xx, 5xx)
|
|
- Throughput (MB/s)
|
|
- Active connections
|
|
|
|
**Dashboard 2: Database Performance**
|
|
- Query latency (p95, p99)
|
|
- Connection pool usage
|
|
- Cache hit ratio
|
|
- Slow queries (> 100ms)
|
|
- Replication lag
|
|
|
|
**Dashboard 3: Frontend Performance**
|
|
- Lighthouse scores (from CI/CD)
|
|
- Core Web Vitals (LCP, FID, CLS)
|
|
- Bundle sizes
|
|
- Resource loading times
|
|
- Error tracking (Sentry)
|
|
|
|
## 8. PERFORMANCE TESTING
|
|
|
|
### 8.1 Benchmarking
|
|
|
|
**Go Benchmarks**:
|
|
```go
|
|
func BenchmarkGetUserByID(b *testing.B) {
|
|
repo := setupRepo()
|
|
user := createTestUser(repo)
|
|
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
_, err := repo.GetByID(user.ID)
|
|
if err != nil {
|
|
b.Fatal(err)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Target: < 100,000 ns/op (0.1ms)
|
|
// BenchmarkGetUserByID-8 50000 25000 ns/op 1024 B/op 15 allocs/op
|
|
```
|
|
|
|
**Rust Benchmarks**:
|
|
```rust
|
|
use criterion::{black_box, criterion_group, criterion_main, Criterion};
|
|
|
|
fn bench_get_user(c: &mut Criterion) {
|
|
let repo = setup_repo();
|
|
let user_id = create_test_user(&repo);
|
|
|
|
c.bench_function("get_user_by_id", |b| {
|
|
b.iter(|| {
|
|
repo.get_by_id(black_box(&user_id))
|
|
});
|
|
});
|
|
}
|
|
|
|
// Target: < 100μs
|
|
criterion_group!(benches, bench_get_user);
|
|
criterion_main!(benches);
|
|
```
|
|
|
|
### 8.2 Load Testing (k6)
|
|
|
|
**Continuous Load Test**:
|
|
```javascript
|
|
// k6-continuous.js
|
|
import http from 'k6/http';
|
|
import { check } from 'k6';
|
|
|
|
export const options = {
|
|
stages: [
|
|
{ duration: '5m', target: 1000 },
|
|
{ duration: '10m', target: 1000 },
|
|
{ duration: '5m', target: 0 },
|
|
],
|
|
thresholds: {
|
|
http_req_duration: ['p(95)<100', 'p(99)<200'],
|
|
http_req_failed: ['rate<0.01'],
|
|
},
|
|
};
|
|
|
|
export default function () {
|
|
const res = http.get('https://api.veza.app/v1/tracks');
|
|
check(res, {
|
|
'status is 200': (r) => r.status === 200,
|
|
'response time < 100ms': (r) => r.timings.duration < 100,
|
|
});
|
|
}
|
|
```
|
|
|
|
### 8.3 Performance Regression Detection
|
|
|
|
**CI/CD Integration**:
|
|
```yaml
|
|
# .github/workflows/performance.yml
|
|
name: Performance Tests
|
|
|
|
on: [push, pull_request]
|
|
|
|
jobs:
|
|
benchmark:
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@v3
|
|
|
|
- name: Run Go benchmarks
|
|
run: |
|
|
cd veza-backend-api
|
|
go test -bench=. -benchmem > bench-new.txt
|
|
|
|
- name: Compare with baseline
|
|
run: |
|
|
benchstat bench-baseline.txt bench-new.txt
|
|
# Fail if regression > 10%
|
|
|
|
- name: Update baseline (if main branch)
|
|
if: github.ref == 'refs/heads/main'
|
|
run: cp bench-new.txt bench-baseline.txt
|
|
```
|
|
|
|
### 8.4 Plan de Mesure en Production
|
|
|
|
**Prometheus** (métriques actives en production) :
|
|
```yaml
|
|
monitoring:
|
|
prometheus:
|
|
status: actif en production
|
|
scrape_interval: 15s
|
|
retention: 30 jours
|
|
métriques:
|
|
- http_request_duration_seconds (histogram, par endpoint)
|
|
- http_requests_total (counter, par status code)
|
|
- audio_stream_start_duration_seconds (histogram)
|
|
- audio_rebuffering_events_total (counter)
|
|
- db_query_duration_seconds (histogram)
|
|
- active_connections (gauge)
|
|
```
|
|
|
|
**Lighthouse CI** (GitHub Actions, bloquant) :
|
|
```yaml
|
|
lighthouse_ci:
|
|
déclencheur: chaque PR + chaque merge sur main
|
|
urls_testées:
|
|
- / (landing)
|
|
- /dashboard
|
|
- /tracks/{id}
|
|
- /upload
|
|
seuils_bloquants:
|
|
performance: 90
|
|
accessibility: 95
|
|
action: gh-actions (lhci autorun)
|
|
rapport: commentaire automatique sur PR
|
|
```
|
|
|
|
**k6 Load Tests** (CD nightly) :
|
|
```yaml
|
|
k6_load_tests:
|
|
fréquence: nightly (CD pipeline, 02:00 UTC)
|
|
scénarios:
|
|
- smoke: 10 VUs, 1 min (sanity check)
|
|
- load: 500 VUs, 10 min (charge normale)
|
|
- stress: 2000 VUs, 5 min (pic de charge)
|
|
seuils:
|
|
http_req_duration_p95: < 100ms
|
|
http_req_duration_p99: < 200ms
|
|
http_req_failed: < 1%
|
|
rapport: Grafana dashboard + Slack notification si échec
|
|
```
|
|
|
|
**pg_stat_statements** (activé en production) :
|
|
```yaml
|
|
pg_stat_statements:
|
|
status: activé
|
|
paramètres:
|
|
pg_stat_statements.max: 10000
|
|
pg_stat_statements.track: all
|
|
monitoring:
|
|
- requêtes > 10ms p95 signalées automatiquement
|
|
- top 20 requêtes par temps cumulé (dashboard Grafana)
|
|
- reset hebdomadaire des statistiques
|
|
alerte: requête > 100ms exécutée > 100 fois/min → Slack
|
|
```
|
|
|
|
## 9. OPTIMIZATION STRATEGIES
|
|
|
|
### 9.1 Backend Optimizations
|
|
|
|
**Database Query Optimization**:
|
|
```go
|
|
// ❌ BAD - N+1 query problem
|
|
func GetUsersWithTracks() ([]User, error) {
|
|
var users []User
|
|
db.Find(&users)
|
|
|
|
for i := range users {
|
|
db.Model(&users[i]).Association("Tracks").Find(&users[i].Tracks) // N queries
|
|
}
|
|
return users, nil
|
|
}
|
|
|
|
// ✅ GOOD - Single query with eager loading
|
|
func GetUsersWithTracks() ([]User, error) {
|
|
var users []User
|
|
err := db.Preload("Tracks").Find(&users).Error // 2 queries total
|
|
return users, err
|
|
}
|
|
```
|
|
|
|
**Caching Strategy**:
|
|
```go
|
|
// Cache frequently accessed data
|
|
func (s *TrackService) GetTrack(id string) (*Track, error) {
|
|
// Try cache first
|
|
cacheKey := fmt.Sprintf("track:%s", id)
|
|
if cached, err := s.cache.Get(cacheKey); err == nil {
|
|
var track Track
|
|
json.Unmarshal([]byte(cached), &track)
|
|
return &track, nil
|
|
}
|
|
|
|
// Cache miss - fetch from database
|
|
track, err := s.repo.GetByID(id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Store in cache (1 hour TTL)
|
|
data, _ := json.Marshal(track)
|
|
s.cache.Set(cacheKey, string(data), 1*time.Hour)
|
|
|
|
return track, nil
|
|
}
|
|
```
|
|
|
|
### 9.2 Frontend Optimizations
|
|
|
|
**Code Splitting**:
|
|
```typescript
|
|
// Lazy load routes
|
|
const Dashboard = lazy(() => import('./pages/Dashboard'));
|
|
const Upload = lazy(() => import('./pages/Upload'));
|
|
const Profile = lazy(() => import('./pages/Profile'));
|
|
|
|
function App() {
|
|
return (
|
|
<Suspense fallback={<LoadingSpinner />}>
|
|
<Routes>
|
|
<Route path="/dashboard" element={<Dashboard />} />
|
|
<Route path="/upload" element={<Upload />} />
|
|
<Route path="/profile/:id" element={<Profile />} />
|
|
</Routes>
|
|
</Suspense>
|
|
);
|
|
}
|
|
```
|
|
|
|
**Image Optimization**:
|
|
```typescript
|
|
// Use next-gen formats with fallback
|
|
<picture>
|
|
<source srcSet="/avatar.avif" type="image/avif" />
|
|
<source srcSet="/avatar.webp" type="image/webp" />
|
|
<img src="/avatar.jpg" alt="Avatar" loading="lazy" />
|
|
</picture>
|
|
|
|
// Or with responsive sizes
|
|
<img
|
|
src="/cover-800.webp"
|
|
srcSet="/cover-400.webp 400w, /cover-800.webp 800w, /cover-1600.webp 1600w"
|
|
sizes="(max-width: 640px) 400px, (max-width: 1024px) 800px, 1600px"
|
|
alt="Track cover"
|
|
loading="lazy"
|
|
/>
|
|
```
|
|
|
|
**Memoization**:
|
|
```typescript
|
|
// Memoize expensive calculations
|
|
const expensiveValue = useMemo(() => {
|
|
return tracks.filter(/* complex filter */).sort(/* expensive sort */);
|
|
}, [tracks]); // Only recalculate when tracks change
|
|
|
|
// Memoize components
|
|
const TrackItem = memo(({ track }: { track: Track }) => {
|
|
return <div>{track.title}</div>;
|
|
});
|
|
```
|
|
|
|
### 9.3 Database Optimizations
|
|
|
|
**Index Optimization**:
|
|
```sql
|
|
-- Add indexes for frequent queries
|
|
CREATE INDEX idx_tracks_user_genre ON tracks(user_id, genre) WHERE deleted_at IS NULL;
|
|
CREATE INDEX idx_tracks_published ON tracks(published_at DESC) WHERE is_public = true AND deleted_at IS NULL;
|
|
|
|
-- Partial index for active users
|
|
CREATE INDEX idx_users_active ON users(created_at DESC) WHERE is_active = true AND deleted_at IS NULL;
|
|
|
|
-- GIN index for full-text search
|
|
CREATE INDEX idx_tracks_search ON tracks USING GIN(to_tsvector('english', title || ' ' || artist)) WHERE deleted_at IS NULL;
|
|
```
|
|
|
|
**Query Optimization**:
|
|
```sql
|
|
-- Use EXPLAIN ANALYZE to identify slow queries
|
|
EXPLAIN ANALYZE
|
|
SELECT t.*, u.username
|
|
FROM tracks t
|
|
JOIN users u ON t.user_id = u.id
|
|
WHERE t.genre = 'electronic'
|
|
AND t.is_public = true
|
|
ORDER BY t.play_count DESC
|
|
LIMIT 20;
|
|
|
|
-- Optimize: Add covering index
|
|
CREATE INDEX idx_tracks_genre_plays ON tracks(genre, play_count DESC) INCLUDE (title, artist) WHERE is_public = true;
|
|
```
|
|
|
|
## 10. PERFORMANCE BUDGETS
|
|
|
|
### 10.1 Frontend Budgets
|
|
|
|
**JavaScript Budget**:
|
|
```json
|
|
{
|
|
"budget": [
|
|
{
|
|
"resourceSizes": [
|
|
{
|
|
"resourceType": "script",
|
|
"budget": 200
|
|
},
|
|
{
|
|
"resourceType": "stylesheet",
|
|
"budget": 20
|
|
},
|
|
{
|
|
"resourceType": "image",
|
|
"budget": 500
|
|
},
|
|
{
|
|
"resourceType": "font",
|
|
"budget": 50
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
**Lighthouse Budget (lighthouse-budget.json)**:
|
|
```json
|
|
{
|
|
"timings": [
|
|
{
|
|
"metric": "interactive",
|
|
"budget": 3500
|
|
},
|
|
{
|
|
"metric": "first-contentful-paint",
|
|
"budget": 1500
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
### 10.2 Backend Budgets
|
|
|
|
**Per-Endpoint Budget**:
|
|
```yaml
|
|
endpoints:
|
|
GET /tracks:
|
|
latency_p95: 50ms
|
|
latency_p99: 100ms
|
|
database_queries: ≤ 2
|
|
cache_usage: required
|
|
|
|
POST /tracks/{id}/play:
|
|
latency_p95: 20ms
|
|
latency_p99: 50ms
|
|
database_queries: ≤ 1
|
|
cache_usage: optional
|
|
|
|
GET /search:
|
|
latency_p95: 200ms
|
|
latency_p99: 500ms
|
|
database_queries: ≤ 5
|
|
elasticsearch_usage: required
|
|
```
|
|
|
|
## ✅ CHECKLIST DE VALIDATION
|
|
|
|
### Performance Targets
|
|
- [ ] API latency p95 < 100ms, p99 < 200ms
|
|
- [ ] Database queries p95 < 10ms
|
|
- [ ] Frontend Lighthouse Performance score ≥ 90
|
|
- [ ] Frontend Lighthouse Accessibility score ≥ 95
|
|
- [ ] Initial JS bundle < 200KB gzipped
|
|
- [ ] First Contentful Paint < 1.5s
|
|
- [ ] Time to Interactive < 3.5s
|
|
- [ ] Audio streaming start < 500ms
|
|
- [ ] Rebuffering rate < 0.5%
|
|
|
|
### Plan de Mesure
|
|
- [ ] Prometheus actif en production (scrape 15s)
|
|
- [ ] Lighthouse CI dans GitHub Actions (bloquant sur régression)
|
|
- [ ] k6 load tests en CD nightly (smoke + load + stress)
|
|
- [ ] pg_stat_statements activé en production
|
|
- [ ] Grafana dashboards created (API, DB, Frontend, Streaming)
|
|
- [ ] Alerting rules configured (critical → PagerDuty, warning → Slack)
|
|
|
|
### Optimization
|
|
- [ ] Database indexes optimized
|
|
- [ ] N+1 queries eliminated
|
|
- [ ] Caching implemented (Redis)
|
|
- [ ] CDN configured
|
|
- [ ] Image optimization implemented
|
|
- [ ] Code splitting implemented
|
|
- [ ] Lazy loading implemented
|
|
|
|
## 📊 MÉTRIQUES DE SUCCÈS
|
|
|
|
### Performance Metrics
|
|
- **API Latency (p95)**: < 100ms
|
|
- **API Latency (p99)**: < 200ms
|
|
- **DB Query (p95)**: < 10ms
|
|
- **Frontend Load (FCP)**: < 1.5s
|
|
- **Frontend Load (TTI)**: < 3.5s
|
|
- **Lighthouse Performance**: ≥ 90
|
|
- **Lighthouse Accessibility**: ≥ 95
|
|
- **Audio Stream Start**: < 500ms
|
|
- **Rebuffering Rate**: < 0.5%
|
|
- **Bundle JS initial gzip**: < 200KB
|
|
- **Uptime**: > 99.9%
|
|
|
|
### Resource Efficiency
|
|
- **CPU Usage**: < 70% (average)
|
|
- **Memory Usage**: < 80% (average)
|
|
- **Cache Hit Rate**: > 90%
|
|
- **Database Connection Utilization**: < 80%
|
|
|
|
### User Experience
|
|
- **Rebuffering rate**: < 0.5% des sessions
|
|
- **Error Rate**: < 0.1%
|
|
- **Time to First Play**: < 3s
|
|
|
|
## 🔄 HISTORIQUE DES VERSIONS
|
|
|
|
| Version | Date | Changements |
|
|
|---------|------|-------------|
|
|
| 1.0.0 | 2025-11-02 | Version initiale - Performance targets complets |
|
|
| 2.0.0 | 2026-03-04 | Audit : targets Lighthouse réalistes (Perf ≥ 90, A11y ≥ 95), rebuffering < 0.5%, ajout plan de mesure complet (Prometheus, Lighthouse CI, k6 nightly, pg_stat_statements), suppression targets ML/inférence |
|
|
|
|
---
|
|
|
|
## ⚠️ AVERTISSEMENT
|
|
|
|
**CES TARGETS SONT IMMUABLES**
|
|
|
|
---
|
|
|
|
**Document créé par**: Performance Team + SRE
|
|
**Date de création**: 2025-11-02
|
|
**Dernière révision**: 2026-03-04 (v2.0.0)
|
|
**Prochaine révision**: Quarterly (2026-06-01)
|
|
**Propriétaire**: Performance Lead
|
|
|
|
**Statut**: ✅ **APPROUVÉ ET VERROUILLÉ**
|
|
|