Site Reliability Engineering
Chapitre 12 / 16 · 26 min de lecture

Tâches planifiées, pipelines et intégrité des données

Fiabiliser le cron distribué, concevoir des pipelines de données robustes, et garantir l'intégrité des données par la défense en profondeur.

Trois piliers du traitement de données par lots se rejoignent dans ce chapitre : l'ordonnancement périodique (le cron), les pipelines de transformation à grande échelle, et la garantie ultime que ces traitements préservent — l'intégrité des données. Tous trois partagent une même difficulté de fond : à l'échelle d'un centre de données, le plus humble des outils Unix devient un système distribué à part entière, sujet aux pannes partielles, aux conditions de course (race conditions) et aux choix douloureux entre exécuter une fois de trop ou pas assez. Là où le chapitre précédent traitait des fondations distribuées, celui-ci montre comment Google bâtit, sur ces fondations, des services qui manipulent les données sans jamais les perdre.

Le cron : un domaine de défaillance qui tient sur une machine

cron est l'utilitaire Unix qui lance des tâches à des instants ou intervalles définis par l'utilisateur, via le format crontab (« tous les jours à midi », « toutes les heures à l'heure pile »). Sur une seule machine, il prend la forme d'un démon, crond, qui charge la liste des tâches planifiées et les déclenche à l'heure dite. Du point de vue de la fiabilité, trois propriétés méritent l'attention.

D'abord, le domaine de défaillance (failure domain) de cron se réduit à une seule machine : si elle ne tourne pas, ni l'ordonnanceur ni les tâches qu'il lance ne tournent. Dès qu'on passe à un cas distribué — un ordonnanceur qui lance des tâches sur une machine ouvrière distincte, par exemple en SSH —, on crée deux domaines de défaillance distincts. Ensuite, le seul état à persister au travers des redémarrages de crond est la configuration crontab elle-même : les lancements sont de type « tire et oublie » (fire-and-forget), et crond ne cherche pas à les suivre. (L'exception notable est anacron, qui tente de rattraper les tâches qui auraient dû s'exécuter pendant que la machine était éteinte, en s'appuyant sur un fichier d'horodatage du dernier lancement.)

Idempotence et le compromis fondamental

La nature des tâches cron dicte leurs exigences de fiabilité. Certaines sont idempotentes : un ramasse-miettes (garbage collection) peut sans danger être relancé plusieurs fois. D'autres ne le sont pas : l'envoi d'une lettre d'information (newsletter) à une vaste liste de diffusion ne doit surtout pas partir deux fois. De même, l'échec d'un lancement est tolérable pour un ramasse-miettes qui tourne toutes les cinq minutes, mais inacceptable pour une paie (payroll) mensuelle.

Cette variété rend impossible une réponse unique aux modes de défaillance. La doctrine de Google est claire : on privilégie le saut d'un lancement plutôt que le risque d'un double lancement, autant que l'infrastructure le permet. La raison est asymétrique : se remettre d'un lancement manqué est plus aisé que de défaire un double lancement, lequel peut être difficile voire impossible (comment « dé-envoyer » une newsletter ?). On préfère donc « échouer fermé » (fail closed) pour éviter de créer systématiquement un état corrompu. Les propriétaires de tâches peuvent — et doivent — surveiller leurs tâches afin de réagir correctement à un saut.

À retenir

Face au doute entre rejouer ou non une action, préférez sauter le lancement plutôt que le dédoubler. La récupération après un saut est presque toujours plus simple que la réparation d'une action exécutée deux fois. Cette préférence du « fail closed » est le principe directeur de tout cron distribué.

Construire un cron distribué chez Google

Héberger le service cron sur une seule machine serait catastrophique : dans un centre de données de 1 000 machines, perdre 1/1000ᵉ du parc suffirait à anéantir tout l'ordonnancement. La parade consiste à découpler les processus des machines : on décrit les besoins du service et le centre de données où il doit tourner, et l'ordonnanceur du centre de données (lui-même fiable, c'est Borg) décide sur quelle(s) machine(s) le déployer et gère les morts de machines. Lancer une tâche revient alors à envoyer une ou plusieurs RPC à cet ordonnanceur.

Ce découplage a un coût. La détection d'une machine morte passe par des délais d'expiration (timeouts) de tests de santé ; le redéploiement réclame le temps d'installer le logiciel et de démarrer le nouveau processus. Comme déplacer un processus peut détruire l'état local et que le délai de redéploiement peut dépasser le plus petit intervalle d'ordonnancement (une minute), on prévoit des « remplaçants à chaud » (hot spares) prêts à reprendre la main pour raccourcir cette fenêtre. Le découplage expose aussi au lancement partiellement échoué : démarrer une tâche peut nécessiter plusieurs RPC, dont certaines réussissent quand d'autres échouent (par exemple parce que le processus émetteur est mort en plein vol).

Paxos, le leader et le follower

Pour suivre l'état des tâches, deux options se présentent : le stocker dans un stockage distribué externe, ou le conserver au sein du service cron lui-même. Google a choisi la seconde, pour deux raisons. Les systèmes de fichiers distribués (GFS, HDFS) sont taillés pour de très gros fichiers : les petites écritures y sont coûteuses et lentes, or l'état d'une tâche cron est minuscule. Surtout, un service de base dont la panne a un impact large doit avoir très peu de dépendances et continuer à fonctionner même si une partie du centre de données disparaît.

Le service déploie donc plusieurs répliques et s'appuie sur l'algorithme de consensus distribué Paxos (dans sa variante Fast Paxos) pour garantir un état cohérent. Tant qu'une majorité (un quorum) de membres est disponible, le système traite les changements d'état malgré la perte de sous-ensembles bornés. Une seule réplique leader modifie l'état partagé et lance les tâches ; les autres sont des followers.

                  Groupe Paxos (3 répliques)

        ┌─────────────┐     Paxos      ┌─────────────┐
        │   LEADER    │◄──────────────►│  FOLLOWER   │
        │  (lance les │   (notifie     │ (suit l'état│
        │   tâches)   │    quorum)     │  du monde)  │
        └──────┬──────┘                └─────────────┘
               │ ▲                     ┌─────────────┐
   RPC mutuel. │ │ état précalculé     │  FOLLOWER   │
   exclusif    │ │ des noms            └─────────────┘
               ▼ │
        ┌────────────────────┐
        │ Ordonnanceur (Borg)│   mort du leader → réélection < 1 min
        └────────────────────┘

Le leader maintient en interne la liste des tâches ordonnée par heure de lancement. À l'heure dite, il annonce — de façon synchrone, via Paxos — qu'il s'apprête à lancer la tâche, identifiée non seulement par son nom mais aussi par son heure de lancement (sans quoi les tâches très fréquentes deviendraient ambiguës). Le lancement réel ne procède qu'après confirmation que le quorum a bien reçu la notification. La fin du lancement est de même annoncée synchroniquement — peu importe qu'il ait réussi ou échoué pour des raisons externes : on consigne le fait que cron a tenté le lancement à l'heure prévue. Détail capital : dès qu'un leader perd son rang, il doit cesser immédiatement d'interagir avec l'ordonnanceur, car détenir le leadership doit garantir l'exclusion mutuelle d'accès à Borg ; sans quoi l'ancien et le nouveau leader pourraient agir de façon contradictoire.

Le follower suit en permanence l'état du monde tel que le leader le diffuse via Paxos, prêt à prendre la relève instantanément. La réélection doit converger en moins d'une minute pour ne pas manquer un lancement. Une fois élu, le nouveau leader doit conclure tous les lancements ouverts (les pannes partielles).

Résoudre les pannes partielles

Chaque lancement comporte deux points de synchronisation : « je suis sur le point de lancer » et « j'ai terminé le lancement ». Si le leader meurt entre les deux, comment le successeur sait-il si la RPC a réellement été envoyée ? L'une de ces deux conditions doit être satisfaite :

  • toutes les opérations sur les systèmes externes sont idempotentes (on peut les rejouer sans danger) ;
  • on peut consulter l'état de toutes les opérations externes pour déterminer sans ambiguïté si elles ont abouti.

La solution élégante consiste à précalculer les noms des tâches du centre de données à l'avance — sans rien muter chez l'ordonnanceur — puis à diffuser ces noms à toutes les répliques. Si le leader meurt en plein lancement, le successeur consulte l'état des noms précalculés et relance simplement ceux qui manquent. Comme pour l'état interne, les noms construits sur l'ordonnanceur incluent l'heure de lancement planifiée, ce qui évite, lors d'un basculement (failover) anormalement lent, qu'un successeur ne reprenne par erreur une tâche déjà terminée.

Stocker l'état : journaux locaux, instantanés sauvegardés

Paxos est essentiellement un journal continu de changements d'état, ajouté synchroniquement. Ce journal doit être compacté (sans quoi il croît à l'infini) et stocké quelque part. La compaction se fait par instantané (snapshot) : mille entrées « incrémente le compteur de 1 » se résument en un seul « positionne le compteur à 1 000 ».

Google combine les deux options de stockage. Les journaux Paxos résident sur le disque local de chaque réplique (trois copies en fonctionnement nominal) ; les instantanés y sont aussi, mais comme ils sont critiques, ils sont en outre sauvegardés sur un système de fichiers distribué. Les journaux, eux, ne le sont pas : perdre les quelques changements d'état les plus récents est un risque accepté, alors que les sauvegarder coûterait cher en petites écritures fréquentes. Perdre les instantanés revient à repartir de zéro ; perdre les journaux ne renvoie l'état qu'au dernier instantané. Enfin, une réplique fraîchement démarrée peut récupérer instantané et journaux d'une réplique déjà active par le réseau, rendant son redéploiement sur une autre machine quasi indolore.

Le troupeau qui charge

À grande échelle surgit un problème de systèmes distribués bien connu : le « troupeau qui charge » (thundering herd). Quand chacun configure sa « tâche quotidienne » à minuit (0 0 * * *) et que trente équipes lancent ainsi un MapReduce de milliers d'ouvriers dans le même centre de données, les pics d'usage sont brutaux. Google a étendu le format crontab avec le point d'interrogation : toute valeur est acceptable, et le système choisit en hachant la configuration de la tâche sur la plage horaire (par exemple 0..23 pour l'heure), répartissant ainsi les lancements plus uniformément. La charge reste néanmoins sporadique, notamment pour les tâches liées à des événements externes à heure fixe.

Pipelines de traitement de données

Le motif classique du traitement de données — un programme lit des données, les transforme, en écrit de nouvelles, le tout ordonnancé par un cron — s'appelle un pipeline de données (data pipeline). Ses racines plongent jusqu'aux co-routines, aux tubes Unix et aux pipelines ETL, mais c'est l'essor du big data qui l'a remis en lumière. Quand la transformation est trop lourde pour un seul programme, on chaîne plusieurs programmes en pipeline multiphase, chacun constituant une phase discrète. Le nombre de programmes chaînés mesure la profondeur (depth) du pipeline.

La fragilité du pipeline périodique

Les pipelines périodiques sont stables tant que les ouvriers suffisent au volume et que la demande reste dans la capacité de calcul, et tant que le nombre de tâches chaînées et leur débit relatif demeurent uniformes. Mais l'expérience collective des SRE est sans appel : le modèle périodique est fragile. Soigneusement réglé au départ, il se dégrade sous l'effet de la croissance organique — tâches qui dépassent leur échéance d'exécution, épuisement des ressources, blocs de traitement coincés.

La cause première est la répartition inégale du travail. La grande percée du big data fut l'application massive d'algorithmes « scandaleusement parallèles » (embarrassingly parallel) découpant la charge en blocs (chunks). Mais ces blocs réclament parfois des ressources très inégales sans qu'on sache pourquoi : si l'on partitionne par client, le bloc d'un gros client peut écraser les autres, et comme le client est l'unité indivisible, le temps d'exécution total est plafonné par celui du plus gros bloc. C'est le problème du « bloc qui pend » (hanging chunk). Pire, la réaction « par défaut » — tuer la tâche et la relancer — empire les choses : faute de points de reprise (checkpointing), tout le travail repart de zéro, gaspillant temps, cycles CPU et effort humain.

Attention

La pire chose pour une infrastructure de cluster et pour les SRE qui en répondent est une tâche de pipeline boguée à 10 000 ouvriers. Une logique de réessai (retry) naïve ou absente transforme un échec ponctuel en avalanche, et les ingénieurs peu expérimentés aggravent le mal en ajoutant des ouvriers quand la tâche ne finit pas à temps.

Lots, latence et le « moiré »

Au-delà d'une certaine fréquence, les pipelines périodiques heurtent un plancher de latence. Comme ils tournent en tâches par lots (batch) de basse priorité, Borg les place dans les interstices laissés par les services web, au risque de délais de démarrage indéfinis et de préemptions (preemptions) quand la charge du cluster est élevée. Si l'on raccourcit l'intervalle d'exécution sous le délai moyen de planification, on n'augmente plus le progrès : les exécutions s'empilent, ou la tâche presque terminée se fait tuer par la suivante — on stoppe tout progrès au nom de plus d'exécutions. Pour une tâche de ~20 minutes, descendre sous ~40 minutes d'intervalle provoque des exécutions qui se chevauchent.

S'ajoute le « motif de charge en moiré » (moiré load pattern) : quand deux pipelines ou plus s'exécutent simultanément et que leurs séquences se recouvrent par moments, ils consomment au même instant une ressource partagée commune. Invisible sur chaque pipeline pris isolément, le pic d'agrégat est ce qui réveille l'astreinte (on-call).

Pipeline A  ▁▁██▁▁▁▁██▁▁▁▁██▁▁
Pipeline B  ▁██▁▁▁██▁▁▁██▁▁▁██

Agrégat     ▁████▁▁██▁▁████▁██     ← pics de recouvrement
                  ↑           ↑      = douleur pour l'astreinte

Google Workflow : le modèle leader/ouvrier

Lorsqu'un pipeline « one-shot » est submergé par la demande de résultats continuellement à jour, refactoriser vers un pipeline continu s'impose — au pire moment, toujours. Anticipant ce besoin, Google a développé en 2003 un système nommé Workflow qui rend le traitement continu disponible à grande échelle. Il combine le motif distribué leader/ouvriers (leader-follower) et le motif de prévalence du système (system prevalence), pour des pipelines transactionnels très volumineux avec une sémantique « exactement une fois » (exactly-once).

On peut voir Workflow comme l'équivalent distribué du motif modèle-vue-contrôleur (MVC). Le modèle est un serveur, le « Task Master », qui maintient tous les états des tâches en mémoire pour un accès rapide tout en journalisant synchroniquement les mutations sur disque persistant. La vue, ce sont les ouvriers qui mettent à jour l'état de façon transactionnelle ; complètement sans état (stateless), ils sont jetables à tout instant. Le mieux est de ne stocker dans le Task Master que des pointeurs vers le travail, les données réelles vivant dans un système de fichiers commun. Un contrôleur optionnel gère le redimensionnement, les instantanés, le rollback ou l'interdiction globale pour la continuité d'activité. On accroît la profondeur en subdivisant le traitement en groupes de tâches (task groups) correspondant chacun à une phase.

Les garanties d'exactitude de Workflow

La justesse repose sur un édifice de garanties. Le Task Master détient une collection de pointeurs vers des données uniquement nommées, et chaque unité de travail porte un bail (lease) unique : un ouvrier ne peut valider (commit) que le travail dont il détient un bail valide. Comme chaque fichier de sortie a un nom unique, même un ouvrier orphelin peut continuer à écrire — mais il échouera au commit, car un autre détient le bail, et il ne pourra détruire le travail valide. Workflow versionne en outre toutes les tâches : toute mise à jour ou changement de bail engendre une tâche nouvelle, immuable, avec un nouvel identifiant. La configuration du pipeline étant elle-même stockée comme des tâches, un commit exige de référencer l'identifiant de la configuration utilisée ; si la configuration change en vol, les ouvriers concernés ne pourront plus valider — tout travail postérieur à un changement de configuration reste cohérent avec la nouvelle configuration, au prix du travail jeté par les malchanceux. Enfin, un jeton de serveur (server token), identifiant unique de ce Task Master précis, est inscrit dans les métadonnées de chaque tâche et vérifié par client et serveur à chaque opération, déjouant une mauvaise configuration subtile (par exemple un répartiteur de charge placé devant plusieurs Task Masters indépendants).

Les quatre garanties d'exactitude de Workflow
─────────────────────────────────────────────
1. Configuration  → les tâches de config créent des barrières
                    sur lesquelles prédiquer le travail
2. Bail (lease)   → tout commit exige un bail valide détenu
3. Noms uniques   → chaque fichier de sortie est nommé de façon unique
4. Jeton serveur  → client et serveur valident le Task Master à chaque op.

Note

Pourquoi ne pas se contenter d'une base de données comme Spanner à la place du Task Master ? Parce que chaque tâche Workflow est unique et immuable : ces deux propriétés préviennent quantité de problèmes subtils de distribution du travail. Avec une base directe, le bail faisant partie de la tâche, chaque changement de bail réclamerait une transaction longue couvrant chaque lecture — possible, mais terriblement inefficace.

Pour la continuité d'activité (business continuity) face aux coupures de fibre, intempéries ou pannes de réseau électrique en cascade qui peuvent neutraliser des centres de données entiers, Workflow stocke ses journaux sur Spanner (système de fichiers global, cohérent, à faible débit), élit l'écrivain via le service de verrous distribués Chubby, et exploite deux Workflows locaux ou plus dans des clusters distincts plus une notion de tâches de référence dans un Workflow global. Un binaire « étape 1 » insère des tâches de référence et met à jour une tâche de battement de cœur (heartbeat) ; faute de mise à jour dans le délai imparti, le Workflow distant saisit le travail en cours et le pipeline poursuit, imperturbable.

Astuce

La règle d'or des pipelines : si un problème de traitement est continu, ou destinée à le devenir par croissance organique, n'utilisez pas de pipeline périodique. Préférez une technologie aux propriétés de Workflow — traitement continu, garanties fortes, montée en charge sur infrastructure de cluster distribuée.

Intégrité des données : ce que vous lisez est ce que vous avez écrit

Qu'est-ce que l'intégrité des données (data integrity) ? Quand l'utilisateur passe avant tout, c'est ce que l'utilisateur pense qu'elle est. On la définirait volontiers comme l'exactitude et l'accessibilité des données ; mais c'est insuffisant. Si un bogue d'interface affiche une boîte Gmail vide trop longtemps, l'utilisateur croira avoir tout perdu — même si aucune donnée ne l'a été — et la confiance s'érode. Combien de temps, « trop longtemps » ? L'incident Gmail de 2011 l'a montré : quatre jours, c'est trop ; Google retient 24 heures comme bon seuil de départ pour Google Apps. Pour l'utilisateur, perte, corruption et indisponibilité prolongée sont indiscernables.

Ce qui paraît contre-intuitif, c'est l'exigence. Un SLO de disponibilité de 99,99 % laisse une heure d'arrêt par an. Mais un SLO de « 99,99 % de bons octets » sur un artefact de 2 Go autoriserait 200 Ko corrompus — de quoi rendre un exécutable inexploitable ou une base illisible. Le secret d'une intégrité supérieure n'est donc pas l'absence de panne, mais la détection proactive couplée à une réparation rapide : un artefact corrompu détecté et réparé en une demi-heure reste disponible à 99,99 % sur l'année, et son intégrité demeure ~100 % pendant sa durée de vie accessible.

Piège courant

L'intégrité des données est le moyen ; la disponibilité des données est le but. Le cas d'un fournisseur de courriel resté dix jours hors service, qui annonça d'abord la perte définitive puis, plusieurs jours après, que rien n'était perdu, l'illustre : les données existaient, mais elles furent inaccessibles trop longtemps. La morale : du point de vue de l'utilisateur, l'intégrité sans disponibilité régulière et attendue équivaut à n'avoir aucune donnée.

Sauvegardes contre archives

Les entreprises « protègent » traditionnellement leurs données en investissant dans des sauvegardes (backups). Mais le vrai objet de cet effort est la récupération (recovery) — ce qui distingue une vraie sauvegarde d'une archive. La différence essentielle : une sauvegarde se recharge dans une application, une archive non.

CritèreSauvegarde (backup)Archive
FinalitéReprise après sinistre (disaster recovery)Audit, découverte légale, conformité
RechargementSe recharge dans l'applicationNe se recharge pas
Délai de récupérationDans les exigences de disponibilité du serviceLent toléré (une semaine, un mois)
FréquenceQuotidienne, horaire, voire continue (streaming)Mensuelle ou plus rare
RétentionSelon la perte de données récentes tolérableLongue (années)

À retenir

Comme on l'observe parfois : personne ne veut vraiment faire des sauvegardes ; ce que tout le monde veut, ce sont des restaurations. La sauvegarde est un impôt qu'on paie en continu pour le service municipal de la disponibilité des données. Au lieu d'insister sur l'impôt, attirez l'attention sur le service qu'il finance. Chez Google, on ne fait pas « pratiquer » la sauvegarde aux équipes : elles définissent des SLO de disponibilité des données pour divers modes de défaillance, puis prouvent qu'elles savent les atteindre.

Les 24 combinaisons de défaillance

Un plan de récupération efficace doit couvrir toute combinaison concevable de trois facteurs. La cause première (root cause) peut être une action utilisateur, une erreur d'opérateur, un bogue applicatif, un défaut d'infrastructure, du matériel fautif ou une catastrophe de site. La portée (scope) peut être large (de nombreuses entités) ou étroite (un petit sous-ensemble d'utilisateurs). Le rythme (rate) peut être un « big bang » (un million de lignes remplacées par dix en une minute) ou rampant (dix lignes supprimées par minute pendant des semaines).

   Cause première  ×  Portée  ×  Rythme   =  24 modes
   ─────────────      ──────     ──────
   action utilisateur  large      big bang
   erreur opérateur    étroite    rampant
   bogue applicatif
   défaut infra
   matériel fautif
   catastrophe de site

Une étude de 19 récupérations chez Google a montré que les pertes visibles les plus fréquentes provenaient de suppressions ou de pertes d'intégrité référentielle dues à des bogues logiciels, les plus redoutables étant les corruptions ou suppressions de bas grade (low-grade) découvertes des semaines ou des mois après l'introduction du bogue. La parade idéale, la récupération à un instant donné (point-in-time recovery, baptisée « time-travel » en interne), reste une chimère couvrant à la fois bases ACID et BASE sous des contraintes strictes. Beaucoup adoptent alors une stratégie de sauvegarde par paliers (tiered).

Attention

Une réponse classique mais fausse à « avez-vous une sauvegarde ? » est « mieux qu'une sauvegarde : la réplication ! ». Réplication et redondance ne sont pas récupérabilité. Les bases qui synchronisent automatiquement leurs répliques propagent une ligne corrompue ou une suppression erronée à toutes les copies, sans doute avant qu'on isole le problème. La clé est la diversité : protéger contre une panne à la couche X exige de stocker sur des composants divers à cette couche (isolation des supports — un bogue de pilote de disque n'atteint pas les bandes magnétiques).

La défense en profondeur

Puisqu'aucune balle d'argent ne couvre les 24 combinaisons, il faut une défense en profondeur (defense in depth) : des couches successives, chacune protégeant de scénarios de perte progressivement moins courants.

            Voyage d'un objet, de la suppression à la destruction

  vivant ──► [1] suppression douce ──► [2] sauvegardes ──► destruction
              (soft / lazy delete)       (paliers)
                  ↑                          ↑                ↑
            corbeille,                 récupération     [3] détection précoce
            undelete                   par restauration  (validation régulière)

         ─── par-dessus tout : réplication (utile, jamais suffisante) ───

Première couche — la suppression douce (soft delete). En environnement à haute vélocité, les bogues applicatifs causent l'essentiel des pertes ; pouvoir « dé-supprimer » durant un temps limité devient la première ligne de défense. La donnée supprimée est immédiatement marquée comme telle — inaccessible à tous sauf au code d'administration. Une corbeille (à la Gmail, 30 jours) défend contre l'erreur d'utilisateur ; la suppression douce défend surtout contre l'erreur de développeur. Pour les offres de cloud, une couche supplémentaire de suppression paresseuse (lazy delete), pilotée par le système de stockage, conserve quelques semaines la donnée déjà rendue inaccessible. Les délais usuels (15, 30, 45 ou 60 jours) reflètent que la plupart des piratages de compte et problèmes d'intégrité sont détectés sous 60 jours. Les cas les plus dévastateurs viennent de développeurs peu familiers du code travaillant sur des pipelines de suppression par lots : il faut concevoir les interfaces pour qu'on ne puisse pas contourner la suppression douce — « la meilleure armure est inutile si on ne l'enfile pas ».

Deuxième couche — les sauvegardes et leurs méthodes de récupération. Principe fondamental, encore : les sauvegardes n'ont pas d'importance, c'est la récupération qui compte. Ce sont les scénarios de récupération qui doivent dicter les méthodes, la fréquence (complète ou incrémentale), le lieu de stockage et la durée de rétention — jamais l'inverse. Plus on peut perdre peu de données récentes, plus la sauvegarde incrémentale doit être sérieuse (pour une vieille version de Gmail, Google a employé une sauvegarde en flux quasi temps réel). Plus la récupération doit être rapide, plus les sauvegardes doivent être locales. D'où une stratégie par paliers : instantanés (snapshots) coûteux mais rapides à restaurer, conservés peu de temps près des données vives ; sauvegardes sur stockage distribué local au site pour quelques jours ; puis bandes en quasi-ligne (nearline) et hors-site pour la protection au niveau du site. Google trace souvent la ligne entre 30 et 90 jours de sauvegardes selon la tolérance à la perte et l'investissement en détection précoce.

Par-dessus tout — la réplication. Idéalement, toute instance de stockage, y compris celles des sauvegardes, serait répliquée. Mais à mesure que le volume croît, c'est irréaliste ; on décale alors les sauvegardes successives sur des sites distincts, défaillant indépendamment, en écrivant avec une méthode de redondance (RAID, codes d'effacement de Reed-Solomon, réplication façon GFS) — et l'on choisit un schéma populaire, en usage continu, et non un schéma rare dont les seuls « tests » seraient nos propres tentatives de récupération.

Note

1 To n'est pas « juste » une plus grosse sauvegarde que 1 Po. Itérer une validation basique sur 700 Po à 300 Mo/s prendrait huit décennies. La technique consiste à établir des « points de confiance » (trust points) — portions devenues immuables, vérifiées une fois figées — puis à n'effectuer que des sauvegardes incrémentales, et à distribuer la charge sur N tâches parallèles traitant chacune 1/N des données. C'est ce qui ramène la restauration à un délai pertinent.

Troisième couche : la détection précoce

Une donnée « mauvaise » ne reste pas inerte : elle se propage. Plus tôt on connaît une perte, plus la récupération est aisée et complète. En environnement à haute vélocité (intégrité référentielle entre dépôts, changements de schéma, migrations sans coupure, points d'intégration mouvants), la qualité se dégrade silencieusement sans effort conscient. Le débutant délègue volontiers l'intégrité à l'algorithme cohérent sous l'API (Paxos, Bigtable) ; or, les algorithmes infaillibles en théorie ont des implémentations truffées de raccourcis, d'optimisations et de bogues. D'où la maxime : faites confiance au stockage, mais vérifiez (trust but verify).

La parade est la validation de données hors-bande (out-of-band validation) : un système de contre-vérifications, le plus souvent des MapReduce ou des tâches Hadoop, au sein et entre les dépôts. Détourner quelques développeurs vers une telle validation ralentit la vélocité à court terme, mais — comme les tests unitaires — accélère l'ensemble à long terme, parce que les ingénieurs savent que les bogues de corruption seront détectés. Gmail détecte ainsi sous 24 heures les incohérences introduites en production, ce qui a donné à ses développeurs le courage de modifier le stockage de production plus d'une fois par semaine. Toute la subtilité est de ne valider que les invariants dont la violation dévaste les utilisateurs : trop strict, la validation casse à la moindre évolution légitime et finit abandonnée ; trop laxiste, la corruption passe. Google Drive vérifie périodiquement que le contenu des fichiers correspond aux listings des dossiers — et corrige automatiquement les écarts, transformant une urgence « les fichiers disparaissent ! » de 2013 en un tranquille « on corrige la cause lundi ». À grande échelle, une validation hors-bande complète exige gestion des tâches, supervision/alertes/tableaux de bord, limitation de débit, outils de diagnostic, runbooks de production et API de validation — autant de raisons de confier le cadre à une équipe d'infrastructure centrale, les équipes produit n'y greffant que la logique métier.

Savoir que la récupération fonctionne

Quand une ampoule grille-t-elle ? Pas forcément quand on actionne l'interrupteur : souvent elle avait déjà lâché, et on le découvre dans le noir, l'orteil cogné. De même, vos dépendances de récupération peuvent être dans un état latent défaillant que vous ignorez jusqu'à la tentative de restauration. L'espoir n'est pas une stratégie : les composants qu'on n'exerce pas en continu lâchent au pire moment.

Piège courant

La seule preuve qui permette de dormir est un test de bout en bout, complet et automatisé, exécuté en continu. La seule leçon à retenir de tout ceci : vous ne savez que vous pouvez restaurer votre état récent que si vous le faites réellement. Vérifiez que vos sauvegardes sont valides et complètes (pas vides), que les ressources machine suffisent, que la récupération finit dans un temps mural raisonnable, qu'elle est observable, et qu'elle ne dépend pas de ressources hors de votre contrôle (un coffre de bandes hors-site indisponible 24/7).

Deux récupérations réelles

Gmail, février 2011 — restauration depuis GTape. Un dimanche soir, le bipeur (pager) du système de sauvegarde se déclenche : malgré redondances et contrôles internes, Gmail a perdu une quantité significative de données utilisateur. Ce fut la première utilisation à grande échelle de GTape, le système de sauvegarde hors-ligne mondial — la dernière ligne de défense, sur bande magnétique. Grâce à de nombreuses simulations préalables, l'équipe put estimer la durée, restaurer tous les comptes en quelques heures autour de l'estimation, et récupérer plus de 99 % des données avant l'échéance prévue. La réaction publique mêla surprise et amusement : de la bande, vraiment, alors que Google dispose de tant de disques et d'un réseau rapide ? Précisément : la défense en profondeur impose des couches multiples contre la rupture de tout mécanisme unique — ici, une défaillance dépassant ce que les moyens internes pouvaient récupérer. Le succès tint à la coordination de nombreuses équipes, fruit de répétitions générales régulières.

Google Music, mars 2012 — détection d'une suppression galopante. Un utilisateur signale des morceaux sautés. L'enquête révèle qu'une référence audio a été supprimée par un pipeline de suppression protégeant la vie privée, refactorisé pour gagner en efficacité. Un MapReduce de diagnostic estime ~600 000 références audio supprimées à tort, touchant 21 000 utilisateurs — et l'ampleur réelle pouvait être pire. La cause profonde : une condition de course entre deux phases du pipeline, censées tourner à trois heures d'écart, qui se rapprochaient à mesure que le volume croissait ; les optimisations puis le refactoring avaient fait grimper la probabilité de suppression non déterministe de mauvaises données. Les bandes étaient stockées hors-site ; il fallut rappeler par camion plus de 5 000 bandes, découper la restauration en 5 475 tâches (impossible à la main), recourir à des bandes de redondance pour 17 bandes défectueuses, et composer avec 1 862 bandes omises par le prestataire. Atout décisif : l'exercice annuel de reprise après sinistre DiRT venait d'avoir lieu, et l'équipe disposait d'un outil testé à cette occasion. En sept jours (dont cinq de récupération effective), 1,5 Po de données audio furent rétablis ; les 161 000 pistes supprimées avant toute sauvegarde furent, pour les achats en boutique, réinstaurées depuis les copies originales, et pour les téléversements personnels, re-demandées aux clients.

Astuce

Les principes généraux du SRE s'appliquent en plein à l'intégrité : « esprit du débutant » (ne jamais croire qu'on comprend assez un système complexe pour exclure une panne), « faites confiance mais vérifiez », « l'espoir n'est pas une stratégie », défense en profondeur, et réexaminez sans cesse — « le fait que vos données étaient sûres hier ne vous aidera pas demain ». L'objectif final n'est pas le moyen (la sauvegarde) mais le but : la disponibilité de données correctes, prouvée comme en développement piloté par les tests.

À retenir

  • À l'échelle du centre de données, cron devient un système distribué : on découple les processus des machines (via Borg), on conserve un état cohérent par Paxos avec un leader unique et des followers, et l'on suit chaque lancement de façon synchrone — identifié par son nom et son heure planifiée.
  • Face au doute, préférez sauter un lancement plutôt que le dédoubler (« fail closed ») ; gérez les pannes partielles par l'idempotence ou par des noms précalculés consultables après un basculement.
  • Les pipelines périodiques sont fragiles : répartition inégale du travail, « bloc qui pend » sans points de reprise, troupeau qui charge (atténué par le ? du crontab) et motif en moiré des ressources partagées sont leurs maux caractéristiques.
  • Google Workflow (modèle leader/ouvriers + prévalence du système) apporte le traitement continu à grande échelle avec une sémantique exactement une fois, garantie par quatre mécanismes : configuration-barrière, bail, noms de fichiers uniques et jeton de serveur.
  • L'intégrité des données est le moyen, la disponibilité des données correctes est le but : la perte, la corruption et l'indisponibilité prolongée sont indiscernables pour l'utilisateur, et l'on raisonne en SLO de disponibilité des données sur les modes de défaillance.
  • La défense en profondeur empile suppression douce/paresseuse, sauvegardes par paliers et détection précoce (validation hors-bande) — la réplication par-dessus aidant parfois, mais ne suffisant jamais ; on couvre ainsi les 24 combinaisons de cause × portée × rythme.
  • Personne ne veut de sauvegardes, tout le monde veut des restaurations : on ne sait qu'on peut récupérer son état récent qu'en le testant réellement, de bout en bout et en continu — comme l'ont prouvé les récupérations de Gmail depuis GTape et de Google Music depuis 5 000 bandes.