Aller au contenu principal

Simuler un décalage d'horloge dans Kubernetes sans affecter les autres conteneurs du nœud

· 10 minutes de lecture
Cwen Yin
Maintainer of Chaos Mesh
Traduction Bêta Non Officielle

Cette page a été traduite par PageTurner AI (bêta). Non approuvée officiellement par le projet. Vous avez trouvé une erreur ? Signaler un problème →

Synchronisation horaire dans les systèmes distribués
Synchronisation horaire dans les systèmes distribués

Chaos Mesh, plateforme open source de chaos engineering cloud-native facile à utiliser pour Kubernetes (K8s), propose une nouvelle fonctionnalité : TimeChaos, qui simule le phénomène de décalage d'horloge. Habituellement, lorsqu'on modifie les horloges d'un conteneur, on souhaite un rayon d'impact minimal sans affecter les autres conteneurs du nœud. En réalité, implémenter cela s'avère plus complexe qu'il n'y paraît. Comment Chaos Mesh résout-il ce problème ?

Dans cet article, je décrirai comment nous avons exploré différentes approches du décalage d'horloge et comment TimeChaos dans Chaos Mesh permet à l'heure de fluctuer librement dans les conteneurs.

Simuler un décalage d'horloge sans affecter les autres conteneurs du nœud

Le décalage d'horloge désigne l'écart temporel entre les horloges des nœuds d'un réseau. Il peut provoquer des problèmes de fiabilité dans les systèmes distribués et constitue une préoccupation pour les concepteurs et développeurs de systèmes distribués complexes. Par exemple, dans une base de données SQL distribuée, maintenir une horloge locale synchronisée entre les nœuds est essentiel pour obtenir un instantané global cohérent et garantir les propriétés ACID des transactions.

Il existe aujourd'hui des solutions reconnues pour synchroniser les horloges, mais sans tests appropriés, vous ne pouvez jamais être certain de la robustesse de votre implémentation.

Comment alors tester la cohérence des instantanés globaux dans un système distribué ? La réponse est évidente : en simulant un décalage d'horloge pour vérifier si les systèmes distribués maintiennent un instantané global cohérent dans des conditions horaires anormales. Certains outils de test permettent de simuler ce décalage dans les conteneurs, mais ils impactent les nœuds physiques.

TimeChaos est un outil qui simule un décalage d'horloge dans les conteneurs pour tester son impact sur votre application sans affecter l'ensemble du nœud. Ainsi, nous pouvons identifier précisément les conséquences potentielles du décalage et prendre les mesures adaptées.

Différentes approches explorées pour simuler le décalage d'horloge

En examinant les solutions existantes, nous savons qu'elles ne conviennent pas à Chaos Mesh fonctionnant sous Kubernetes. Deux méthodes courantes – modifier directement l'horloge du nœud et utiliser le framework Jepsen – changent l'heure pour tous les processus du nœud. Ces solutions sont inacceptables pour nous. Dans un conteneur Kubernetes, injecter une erreur de décalage affectant l'ensemble du nœud perturberait les autres conteneurs. Une approche aussi brutale est inadmissible.

Comment résoudre ce problème ? La première idée qui nous vient à l'esprit est d'explorer des solutions au niveau du noyau via le filtre de paquets Berkeley (BPF).

LD_PRELOAD

LD_PRELOAD est une variable d'environnement Linux permettant de définir quelle bibliothèque dynamique est chargée avant l'exécution du programme.

Cette variable présente deux avantages :

  • Nous pouvons appeler nos propres fonctions sans connaître le code source.

  • Nous pouvons injecter du code dans d'autres programmes à des fins spécifiques.

Pour les langages où les applications appellent la fonction temporelle de glibc, comme Rust et C, l'utilisation de LD_PRELOAD suffit pour simuler le décalage horaire. Mais la situation est plus délicate avec Golang. Les langages comme Golang accèdent directement au virtual Dynamic Shared Object (vDSO), un mécanisme d'accélération des appels système. Pour obtenir l'adresse de la fonction temporelle, on ne peut pas simplement utiliser LD_PRELOAD pour intercepter l'interface glibc. Par conséquent, LD_PRELOAD n'est pas notre solution.

Utiliser BPF pour modifier la valeur de retour de l'appel système clock_gettime

Nous avons également essayé de filtrer la tâche par son numéro d'identification de processus (PID) avec BPF. Cette méthode permettait de simuler le décalage horaire sur un processus spécifique et de modifier la valeur de retour de l'appel système clock_gettime.

L'idée semblait prometteuse, mais nous avons aussi rencontré un problème : dans la plupart des cas, vDSO accélère clock_gettime, mais clock_gettime n'effectue pas d'appel système. Cette solution n'a pas fonctionné non plus. Oups.

Heureusement, nous avons déterminé qu'avec un noyau système en version 4.18 ou ultérieure utilisant l'horloge HPET, clock_gettime() récupère l'heure via des appels système normaux plutôt que par vDSO. Nous avons implémenté une version de décalage horaire avec cette approche, qui fonctionne correctement pour Rust et C. Pour Golang, bien que le programme obtienne l'heure correctement, les opérations sleep pendant l'injection du décalage restent souvent bloquées, même après l'annulation de l'injection. Nous avons donc dû abandonner cette approche.

TimeChaos, notre solution finale

Comme vu précédemment, les programmes récupèrent généralement l'heure système via clock_gettime. Dans notre cas, clock_gettime utilise vDSO pour accélérer le processus, rendant impossible l'interception des appels système clock_gettime via LD_PRELOAD.

La solution ? Agir directement sur vDSO. Si nous pouvons rediriger l'adresse de retour de clock_gettime dans vDSO vers une adresse personnalisée, le problème est résolu.

Plus facile à dire qu'à faire. Pour y parvenir, nous devons résoudre ces problématiques :

  • Identifier l'adresse en mode utilisateur utilisée par vDSO

  • Déterminer l'adresse en mode noyau de vDSO pour modifier sa fonction clock_gettime

  • Savoir comment modifier les données vDSO

Première étape : inspecter vDSO via /proc/pid/maps.

$ cat /proc/pid/maps
...
7ffe53143000-7ffe53145000 r-xp 00000000 00:00 0 [vdso]

La dernière ligne contient les informations vDSO. Ses privilèges r-xp (lecture et exécution, sans écriture) empêchent toute modification en mode utilisateur. Nous contournons cette restriction avec ptrace.

Ensuite, nous exportons vDSO via gdb dump memory et examinons son contenu avec objdump :

(gdb) dump memory vdso.so 0x00007ffe53143000 0x00007ffe53145000
$ objdump -T vdso.so
vdso.so: file format elf64-x86-64
DYNAMIC SYMBOL TABLE:
ffffffffff700600 w DF .text 0000000000000545 LINUX_2.6 clock_gettime

vDSO se comporte comme un fichier .so, formatable au format ELF. Ces informations permettent d'esquisser le workflow de TimeChaos :

Workflow de TimeChaos
Workflow de TimeChaos

Ce diagramme illustre le processus de TimeChaos, l'implémentation du décalage horaire dans Chaos Mesh.

  1. Utiliser ptrace pour attacher le processus PID cible et l'interrompre.

  2. Utiliser ptrace pour créer une nouvelle mappage dans l'espace d'adressage virtuel du processus appelant et employer process_vm_writev pour écrire la fonction fake_clock_gettime que nous avons définie dans l'espace mémoire.

  3. Utiliser process_vm_writev pour écrire les paramètres spécifiés dans fake_clock_gettime. Ces paramètres représentent le décalage temporel que nous souhaitons injecter, par exemple deux heures en arrière ou deux jours en avant.

  4. Utiliser ptrace pour modifier la fonction clock_gettime dans vDSO et la rediriger vers la fonction fake_clock_gettime.

  5. Utiliser ptrace pour détacher le processus PID.

Si vous souhaitez consulter les détails techniques, référez-vous au dépôt GitHub de Chaos Mesh.

Simulation d'un décalage d'horloge sur une base de données SQL distribuée

Les résultats parlent d'eux-mêmes. Nous allons tester TimeChaos sur TiDB, une base de données SQL distribuée open source de type NewSQL qui prend en charge les charges de travail Hybrid Transactional/Analytical Processing (HTAP), pour vérifier l'efficacité des tests de chaos.

TiDB utilise un service centralisé Timestamp Oracle (TSO) pour obtenir un numéro de version globalement cohérent et garantir une progression monotone des versions de transactions. Le service TSO est géré par le composant Placement Driver (PD). Nous sélectionnons donc un nœud PD aléatoire et y injectons régulièrement TimeChaos, chaque injection provoquant un décalage d'horloge de 10 millisecondes en arrière. Observons comment TiDB relève ce défi.

Pour optimiser le test, nous utilisons bank comme charge de travail, simulant des transferts financiers dans un système bancaire. Cet outil est couramment employé pour valider la correction des transactions des bases de données.

Voici notre configuration de test :

apiVersion: chaos-mesh.org/v1alpha1
kind: TimeChaos
metadata:
name: time-skew-example
namespace: tidb-demo
spec:
mode: one
selector:
labelSelectors:
"app.kubernetes.io/component": "pd"
timeOffset:
sec: -600
clockIds:
- CLOCK_REALTIME
duration: "10s"
scheduler:
cron: "@every 1m"

Durant ce test, Chaos Mesh injecte TimeChaos dans un Pod PD choisi toutes les 1 milliseconde pendant 10 secondes. Pendant cette période, l'heure obtenue par PD présente un décalage de 600 secondes par rapport à l'heure réelle. Pour plus de détails, consultez le Wiki Chaos Mesh.

Créons une expérience TimeChaos via la commande kubectl apply :

kubectl apply -f pd-time.yaml

Nous pouvons maintenant récupérer les logs PD avec la commande suivante :

kubectl logs -n tidb-demo tidb-app-pd-0 | grep "system time jump backward"

Voici un extrait des logs :

[2020/03/24 09:06:23.164 +00:00] [ERROR] [systime_mon.go:32] ["system time jump backward"] [last=1585041383060109693]
[2020/03/24 09:16:32.260 +00:00] [ERROR] [systime_mon.go:32] ["system time jump backward"] [last=1585041992160476622]
[2020/03/24 09:20:32.059 +00:00] [ERROR] [systime_mon.go:32] ["system time jump backward"] [last=1585042231960027622]
[2020/03/24 09:23:32.059 +00:00] [ERROR] [systime_mon.go:32] ["system time jump backward"] [last=1585042411960079655]
[2020/03/24 09:25:32.059 +00:00] [ERROR] [systime_mon.go:32] ["system time jump backward"] [last=1585042531963640321]
[2020/03/24 09:28:32.060 +00:00] [ERROR] [systime_mon.go:32] ["system time jump backward"] [last=1585042711960148191]
[2020/03/24 09:33:32.063 +00:00] [ERROR] [systime_mon.go:32] ["system time jump backward"] [last=1585043011960517655]
[2020/03/24 09:34:32.060 +00:00] [ERROR] [systime_mon.go:32] ["system time jump backward"] [last=1585043071959942937]
[2020/03/24 09:35:32.059 +00:00] [ERROR] [systime_mon.go:32] ["system time jump backward"] [last=1585043131978582964]
[2020/03/24 09:36:32.059 +00:00] [ERROR] [systime_mon.go:32] ["system time jump backward"] [last=1585043191960687755]
[2020/03/24 09:38:32.060 +00:00] [ERROR] [systime_mon.go:32] ["system time jump backward"] [last=1585043311959970737]
[2020/03/24 09:41:32.060 +00:00] [ERROR] [systime_mon.go:32] ["system time jump backward"] [last=1585043491959970502]
[2020/03/24 09:45:32.061 +00:00] [ERROR] [systime_mon.go:32] ["system time jump backward"] [last=1585043731961304629]
...

D'après ces logs, nous observons que PD détecte périodiquement un recul de l'heure système. Cela signifie :

  • TimeChaos simule avec succès le décalage d'horloge.

  • PD parvient à gérer cette situation de décalage temporel.

Ces résultats sont encourageants. Mais TimeChaos affecte-t-il d'autres services que PD ? Vérifions dans le Chaos Dashboard :

Tableau de bord Chaos
Tableau de bord Chaos

Le moniteur montre clairement que TimeChaos a été injecté toutes les 1 milliseconde pendant 10 secondes. Par ailleurs, TiDB n'a subi aucun impact : le programme bank s'est exécuté normalement sans dégradation des performances.

Essayez Chaos Mesh

En tant que plateforme d'ingénierie du chaos cloud-native, Chaos Mesh propose des méthodes complètes d'injection de fautes pour systèmes complexes sur Kubernetes, couvrant les fautes au niveau des Pods, du réseau, du système de fichiers et même du noyau.

Vous souhaitez acquérir une expérience pratique en ingénierie du chaos ? Bienvenue sur Chaos Mesh. Ce tutoriel de 10 minutes vous aidera à démarrer rapidement avec l'ingénierie du chaos et à exécuter votre première expérience de chaos avec Chaos Mesh.