Le Collector OpenTelemetry n’est pas un composant unique mais une architecture à deux niveaux distincts : l’agent, déployé au plus près de chaque application, et le gateway, un niveau centralisé qui voit l’ensemble du trafic avant de décider quoi en faire. Confondre les deux rôles, ou n’en déployer qu’un par réflexe, limite ce que l’observabilité peut réellement faire.

L’agent : un Collector par nœud, au plus près de la source

Déployé en DaemonSet (un pod par nœud), l’agent reçoit les traces et métriques directement des applications qui tournent sur ce même nœud, avant tout traitement centralisé. Son rôle reste local et limité : recevoir, appliquer un premier filtrage léger, enrichir avec des métadonnées (nom du nœud, du pod) disponibles localement, puis transmettre au niveau suivant.

# L'agent DaemonSet ne voit que le trafic
# des applications qui tournent sur son propre nœud
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: otel-agent
spec:
  template:
    spec:
      containers:
        - name: otel-collector
          image: otel/opentelemetry-collector

Le gateway : un niveau qui voit tout, avant que rien ne soit décidé

Le gateway, déployé en Deployment (quelques replicas, pas un par nœud), reçoit le trafic agrégé de tous les agents. Cette centralisation change ce qui devient possible : une décision qui a besoin de voir l’ensemble d’une trace, potentiellement répartie sur plusieurs nœuds et plusieurs services, ne peut se prendre qu’à ce niveau, jamais au niveau d’un agent qui ne voit qu’une fraction locale du trafic.

# Le gateway agrège le trafic de tous les agents,
# seul niveau qui voit une trace dans son ensemble
apiVersion: apps/v1
kind: Deployment
metadata:
  name: otel-gateway
spec:
  replicas: 3

Pourquoi le tail-sampling exige spécifiquement le gateway

Le tail-based sampling décide de garder ou non une trace après l’avoir vue complète (garder systématiquement les traces en erreur ou lentes, échantillonner le reste), une décision qui suppose de disposer de tous les spans d’une trace au même endroit avant de trancher. Une trace qui traverse trois services répartis sur trois nœuds différents produit des spans captés par trois agents distincts : aucun agent, isolé sur son nœud, ne peut appliquer un tail-sampling correct, puisqu’aucun ne voit la trace dans son intégralité. Seul le gateway, qui reçoit l’ensemble agrégé, dispose de l’information nécessaire.

# Le tail-sampling ne peut s'appliquer qu'au niveau
# du gateway, jamais d'un agent qui ne voit qu'une fraction
processors:
  tail_sampling:
    policies:
      - name: keep-errors
        type: status_code
        status_code: {status_codes: [ERROR]}

Le coût de cette architecture à deux niveaux

Le gateway doit bufferiser les spans d’une trace en cours jusqu’à sa complétion avant de décider, ce qui consomme de la mémoire proportionnelle au volume de traces simultanées et à leur durée de vie. Sur un système à fort trafic, ce buffer devient un dimensionnement à part entière, distinct du dimensionnement des agents (qui ne font, eux, que relayer sans attendre). Sauter le niveau gateway et faire du tail-sampling directement dans les agents, une tentation d’économie d’infrastructure, produit un sampling incorrect par construction : chaque agent ne juge que sa fraction locale, sans jamais voir l’ensemble.

À retenir

L’architecture Collector d’OpenTelemetry sépare deux rôles distincts : l’agent (DaemonSet, un par nœud, collecte locale) et le gateway (Deployment, quelques replicas, vue agrégée de tout le trafic). Le tail-sampling, qui décide après avoir vu une trace complète, ne peut s’appliquer correctement qu’au niveau du gateway, jamais au niveau d’un agent qui ne voit qu’une fraction locale, un détail d’architecture qui détermine si l’échantillonnage intelligent fonctionne réellement ou seulement en apparence. Ce choix d’architecture s’inscrit dans le socle d’une fiabilité et observabilité qui tient réellement à l’échelle, pas seulement sur un système à trafic modeste.