Aller au contenu principal

Module 7 — Points de terminaison, trafic partagé et mise à l'échelle

Le registre du module 6 contient deux versions du modèle fraude : v1 en production depuis août, v2 fraîchement entraînée. Comment mettre v2 devant le vrai trafic sans exposer le service à un modèle qui n'a jamais vu de production ? Vertex répond par le point de terminaison avec trafic partagé : deux versions cohabitent, on choisit la répartition, et l'on bascule progressivement selon les résultats.

Anatomie d'un point de terminaison

Un Endpoint Vertex est une adresse HTTPS qui accepte des requêtes de prédiction. Derrière cette adresse, il peut y avoir de 1 à 10 versions déployées, chacune avec sa part du trafic (les pourcentages doivent sommer à 100). Chaque version a ses propres réplicas et sa propre configuration machine, ce qui permet des expérimentations fines : v1 sur n1-standard-4, v2 sur n1-standard-8 si elle est plus coûteuse à évaluer.

Notre plateforme utilise un point de terminaison par cas d'usage, jamais par version. Le service front appelle toujours fraude-endpoint-eu. Ce qui change en interne — versions, pourcentages, réplicas — ne le concerne pas.

Créer et déployer

from google.cloud import aiplatform

endpoint = aiplatform.Endpoint.create(
display_name="fraude-endpoint-eu",
location="europe-west1",
labels={"equipe": "fraude", "env": "prod"},
)

# v1, deja en production, 100 % du trafic
modele_v1 = aiplatform.Model("projects/paiement-fraude-prod/locations/europe-west1/models/1234567890@1")

deploiement_v1 = endpoint.deploy(
model=modele_v1,
deployed_model_display_name="fraude-xgb-v1",
machine_type="n1-standard-4",
min_replica_count=2,
max_replica_count=8,
traffic_percentage=100,
service_account="vertex-fraude-runner@paiement-fraude-prod.iam.gserviceaccount.com",
)

Le déploiement prend cinq à dix minutes : Vertex provisionne les machines, tire l'image de service, charge le modèle en mémoire, teste la route /health. Une fois deployed_model_id renvoyé, l'endpoint accepte du trafic.

Ajouter la version challenger

Le vrai geste du module. On déploie v2 sur le même point de terminaison, avec 10 % du trafic — les 90 % restants restent sur v1 :

modele_v2 = aiplatform.Model("projects/paiement-fraude-prod/locations/europe-west1/models/1234567890@2")

endpoint.deploy(
model=modele_v2,
deployed_model_display_name="fraude-xgb-v2-challenger",
machine_type="n1-standard-4",
min_replica_count=1,
max_replica_count=4,
traffic_split={
deploiement_v1.id: 90,
"0": 10, # 0 est un placeholder pour la version qu'on vient de deployer
},
)

Vertex accepte l'ancienne convention où l'on passe la répartition à deploy(), mais un appel séparé à endpoint.update_traffic_split(...) reste plus lisible pour les revues d'exécution ultérieures. Après quelques minutes, la moitié des transactions du trafic entrant passera par v2, mais surtout 90 % sur v1 — le rapport 90/10 protège l'entreprise si v2 se révèle catastrophique.

Requête et forme des données

Le service appelle l'endpoint en JSON :

reponse = endpoint.predict(
instances=[{
"montant": 189.50,
"pays_carte": "FR",
"pays_marchand": "US",
"canal": "e-commerce",
"age_compte_jours": 42,
"nb_transactions_24h": 3,
# ... 36 autres variables
}]
)
print(reponse.predictions[0])

La forme du dictionnaire dépend du modèle. Pour un sklearn inscrit sans schéma, Vertex passe les valeurs dans l'ordre : c'est fragile. La bonne pratique est d'inscrire un predict_schemata à l'upload du modèle, ou de faire précéder le modèle d'un petit conteneur de prétraitement qui accepte un dictionnaire nommé et le convertit en vecteur ordonné.

Réplicas minimum et maximum

min_replica_count est le nombre minimal de machines toujours allumées. À 0, Vertex démarre à la première requête — mais cela signifie 30 à 60 secondes de latence pour cette première requête (cold start), rédhibitoire pour un service en ligne. Pour la production, jamais moins de 2 : cela garantit la tolérance à une panne d'instance et évite la latence de démarrage. En développement, min=0 économise sur les nuits.

max_replica_count est le plafond de l'autoscaler. Vertex ajoute des réplicas quand l'utilisation CPU d'un réplica dépasse 60 %, et en enlève quand elle descend. Le plafond protège la facture face à un pic anormal — et permet à l'équipe SRE de dormir.

Le rapport à choisir : pour un trafic aux variations naturelles, max = 4 × min couvre les heures de pointe. Pour un trafic qui triple en une seconde (soldes, promotions), il faut anticiper — l'autoscaler ne réagit pas assez vite pour un pic aussi brutal, et pré-scaler à min=8 la veille est plus sûr.

Mesurer la latence

La console affiche pour chaque déploiement les percentiles de latence (p50, p95, p99) sur les dernières 24 h. Trois seuils à surveiller :

PercentileNotre cible fraudeSens
p50< 30 msRessenti moyen d'une transaction
p95< 80 msCe que voit une transaction sur vingt
p99< 200 msLe pire acceptable, une sur cent

Le p99 est celui qui casse la promesse : à 3 000 transactions par seconde, une sur cent lente représente 30 par seconde qui excèdent 200 ms — visible dans les traces distribuées, à l'origine de tickets clients.

Journalisation des requêtes

Par défaut, Vertex ne journalise ni les requêtes ni les prédictions. Activation à la déploiement :

endpoint.deploy(
model=modele_v2,
enable_container_logging=True,
enable_access_logging=True,
# journalisation echantillonnee des requetes et predictions
explanation_metadata=None,
request_response_logging_config={
"enabled": True,
"sampling_rate": 0.01, # 1 % des requetes
"bigquery_destination": {
"output_uri": "bq://paiement-fraude-prod.vertex_logs.predictions_fraude",
},
},
)

Un pour cent des requêtes est écrit dans BigQuery, avec l'entrée, la sortie, la version déployée, l'horodatage. C'est la matière première de la surveillance de dérive (cours 20) et de la comparaison quantitative entre v1 et v2 : au bout de deux semaines, on compare les scores et les taux d'alerte de chaque version sur des transactions comparables. Sans ce log, l'expérimentation 90/10 ne prouve rien.

Basculer le trafic

Après validation, on inverse :

endpoint.update_traffic_split({
deploiement_v1.id: 0,
deploiement_v2.id: 100,
})

On garde v1 déployée quelques jours à 0 % : la remise à 100 % sur v1 en cas d'incident sur v2 prend alors une seconde, sans réprovisionner de machines. Retour arrière trivial — c'est là que la promesse du registre du module 6 se concrétise.

Le trafic partagé n'est pas de l'A/B test

La répartition 90/10 partage les requêtes, pas les utilisateurs. Un client peut voir sa première transaction évaluée par v1 et la suivante par v2, cinq secondes plus tard. Pour un vrai test A/B (métrique par cohorte), il faut acheminer soi-même selon un hash de l'identifiant client, en amont de Vertex. Vertex fournit une exposition contrôlée du modèle, pas un moteur d'expérimentation.

En résumé

  • Un Endpoint est une adresse HTTPS derrière laquelle vivent jusqu'à 10 versions, avec des pourcentages de trafic sommant à 100.
  • min_replica_count ≥ 2 en production : évite le cold start et tolère la panne d'un réplica.
  • max_replica_count protège la facture ; pour un pic soudain, pré-scaler la veille.
  • Le trafic partagé 90/10 expose challenger sans risquer la production, avec retour arrière à la seconde.
  • request_response_logging_config est indispensable pour comparer v1 et v2 sur du trafic réel.

Module suivant : nous traitons les transactions non temps réel — celles qui n'ont pas besoin d'une réponse en 30 ms — avec la prédiction par lots.