Aller au contenu

Serverless

Des fonctions stateless invoquees à la demande — zero ops en apparence, compromis réels en pratique.


Le principe

Le serverless (FaaS — Function as a Service) externalise totalement la gestion de l'infrastructure. Le code est déployé sous forme de fonctions stateless, invoquees à la demande. Le fournisseur cloud géré le provisioning, le scaling et la maintenance des serveurs.

Exemples : AWS Lambda, Google Cloud Functions, Azure Functions, Cloudflare Workers.

Le terme "serverless" est trompeur — il y a toujours des serveurs. Ce qui change, c'est que l'équipe ne les géré plus. Le cloud provider les provisionne, les patche, les scale et les remplacé. L'équipe ne deploie que du code et de la configuration.

graph LR
    subgraph Triggers
        API["API Gateway"]
        S3["S3 Upload"]
        CW["CloudWatch\nSchedule"]
        SQS["SQS Message"]
    end
    subgraph Functions
        F1["Process Order"]
        F2["Resize Image"]
        F3["Daily Report"]
        F4["Send Notification"]
    end
    subgraph Services
        DB[("DynamoDB")]
        MAIL["SES"]
        STORE["S3"]
    end
    API --> F1
    S3 --> F2
    CW --> F3
    SQS --> F4
    F1 --> DB
    F2 --> STORE
    F3 --> DB
    F4 --> MAIL

Chaque fonction est déclenchée par un trigger (requête HTTP, message dans une queue, upload de fichier, schedule cron). Elle exécuté sa logique, interagit avec des services manages, et se termine. Pas d'état en mémoire entre deux invocations.


Cold start, warm start, provisioned concurrency

Le cold start est le problème le plus visible du serverless. Quand une fonction n'a pas été invoquee depuis un moment, le cloud provider doit démarrer un nouveau conteneur, charger le runtime et initialiser le code. Ce délai est le cold start.

Runtime Cold start typique Warm start
Node.js 100-300 ms < 5 ms
Python 200-500 ms < 5 ms
Go 50-150 ms < 2 ms
Java (JVM) 1-3 s < 5 ms
.NET 500 ms - 2 s < 5 ms

Facteurs qui aggravent le cold start :

  • Taille du package de déploiement (plus c'est gros, plus c'est lent)
  • Nombre de dépendances a charger
  • Initialisation de connexions (base de données, APIs externes)
  • Runtimes avec compilation JIT (Java, .NET)

Stratégies d'attenuation :

Stratégie Description Coût
Warm start naturel Garder un trafic minimum pour éviter l'eviction du conteneur Gratuit si le trafic existe
Provisioned concurrency Pre-allouer N conteneurs toujours prets (AWS Lambda) Payant — supprimé l'avantage scale-to-zero
Package minimal Réduire la taille du déploiement, lazy-load des dépendances Effort de développement
GraalVM native image Compiler Java en natif pour un démarrage < 100ms Complexité de build, certaines limitations
SnapStart (AWS) Snapshot de la JVM après initialisation, restauration rapide Spécifique AWS, Java uniquement

Le cold start n'est pas un bug

Le cold start est une conséquence directe du modèle scale-to-zero. Si on a besoin de latence garantie < 50ms à chaque requête, le serverless n'est pas le bon modèle — ou il faut payer pour du provisioned concurrency, ce qui annule une partie de l'avantage économique.


Limitations

Le serverless impose des contraintes strictes qui ne sont pas negociables.

Limite AWS Lambda Cloud Functions Impact
Durée max d'exécution 15 minutes 9 minutes (HTTP), 60 min (event) Pas de traitements longs
Mémoire max 10 Go 32 Go Limite pour le ML, traitement d'images lourdes
Taille du package 250 Mo (decompresse) 500 Mo (sources) Pas de grosses dépendances
Connexions concurrentes 1000 par défaut (extensible) 1000 par défaut Peut saturer une base de données
État en mémoire Aucun entre invocations Aucun Tout doit être externalise
Timeout de réponse API GW 29 secondes 60 secondes Pas de requêtes longues

État et persistence

Chaque invocation est indépendante. Il n'y a pas de mémoire partagee entre deux invocations de la même fonction. Tout état doit être persiste dans un service externe : base de données, cache, stockage objet.

Cette contrainte force un style d'architecture spécifique. Les websockets long-lived, les sessions en mémoire, les caches locaux — tout ca n'existe pas en serverless. Des services comme API Gateway WebSocket (AWS) ou Firebase Realtime Database (GCP) fournissent des alternatives, mais avec leur propre complexité.

Vendor lock-in

Le lock-in en serverless est plus profond qu'en IaaS. Ce n'est pas juste le compute — c'est l'intégration avec les triggers, les services de monitoring, les policies IAM, les layers, les extensions. Migrer une Lambda qui utilise DynamoDB, SQS, S3 et CloudWatch vers GCP n'est pas un portage — c'est une reecriture.

Des frameworks comme Serverless Framework ou SST abstraient une partie du déploiement, mais l'abstraction a ses limites. Le code applicatif peut être portable, l'infrastructure rarement.


Modèle de coût

Le serverless facture à l'invocation et à la durée d'exécution, pas à la capacité réservée. Ce modèle est avantageux pour du trafic irrégulier mais peut devenir coûteux a fort volume constant.

Comparaison pour un endpoint HTTP :

Scenario Serverless (Lambda) Conteneur (ECS Fargate) VM (EC2)
1K requêtes/jour ~0.01 $/mois ~30 $/mois ~15 $/mois
100K requêtes/jour ~5 $/mois ~30 $/mois ~15 $/mois
10M requêtes/jour ~200 $/mois ~60 $/mois ~30 $/mois
100M requêtes/jour ~2000 $/mois ~200 $/mois ~100 $/mois

Le point de bascule se situe généralement entre 1M et 10M requêtes/jour. En dessous, le serverless est presque toujours moins cher. Au-dessus, les services always-on deviennent plus économiques.

Le coût cache du serverless

Le coût de compute est visible. Les coûts caches sont les services annexes : API Gateway (~3.50$/M requêtes), DynamoDB, CloudWatch Logs, NAT Gateway (si VPC). Pour certaines architectures, ces coûts annexes depassent le coût Lambda.


Cas d'usage ou le serverless excelle

APIs a trafic variable :

  • Trafic de 0 a 10 000 requêtes/minute avec des pics imprévisibles
  • Pas de coût quand il n'y a pas de trafic (scale to zero)
  • Scaling automatique sans configuration

Tâches event-driven ponctuelles :

  • Traitement d'images à l'upload (redimensionnement, compression)
  • Webhooks entrants (Stripe, GitHub, Slack)
  • Transformation de données dans un pipeline ETL
  • Envoi de notifications declenchees par un événement

Prototypage rapide :

  • Time-to-deploy en minutes, pas en heures
  • Pas besoin de configurer un cluster Kubernetes
  • Idéal pour valider un concept avant d'investir dans l'infrastructure

Scheduled jobs :

  • Rapports quotidiens, nettoyage de données, synchronisation périodique
  • Alternative légère a un cron sur un serveur dédié
  • Pas besoin de maintenir un serveur allume 24h pour 5 minutes de travail par jour

Architectures hybrides

En pratique, le serverless est rarement utilisé seul. Les architectures hybrides combinent des services always-on (conteneurs, VMs) pour le cœur du système avec des fonctions serverless pour les tâches périphériques.

graph TB
    Client["Client"] --> ALB["Load Balancer"]
    ALB --> API["API Service\n(ECS/K8s)"]
    API --> DB[("PostgreSQL")]
    API -->|"event"| SQS["SQS"]
    SQS --> Lambda1["Resize Image\n(Lambda)"]
    SQS --> Lambda2["Send Email\n(Lambda)"]
    Lambda1 --> S3["S3"]
    Lambda2 --> SES["SES"]
    CW["CloudWatch\nSchedule"] --> Lambda3["Daily Report\n(Lambda)"]
    Lambda3 --> DB

Cette architecture prend le meilleur de chaque monde :

  • Le cœur applicatif tourne sur des conteneurs avec une latence prévisible
  • Les tâches event-driven et les jobs schedules utilisent du serverless pour le scale-to-zero
  • Les coûts sont optimises : on ne paie les fonctions que quand elles travaillent

Règles de décision pour l'hybride :

Composant Serverless si... Always-on si...
API principale Trafic < 1M req/jour, latence > 100ms acceptable Trafic constant, latence < 50ms requise
Background jobs Exécution < 15 min, sporadique Exécution longue, continue
Webhooks entrants Volume imprévisible Volume constant et élevé
Streaming Transformations simples, stateless Aggregations avec état, fenêtres temporelles

Chapitre suivant : Critères de choix — tableau comparatif, arbre de décision et signaux d'équipe pour choisir sa topologie.