This post is also available in english.
En utilisant Hyper-V Server, vous allez peut-être constater que l’horloge dérive beaucoup du temps “réel”, en particulier lorsque les machines virtuelles “invitées” utilisent fortement les CPUs. Comme l’OS de l’hôte est également virtualisé, cela implique que sa charge fait aussi dériver l’horloge système.
Comment atténuer la dérive de l’horloge
- Désactiver la synchronisation du temps dans la section “Integration Services”. (Attention, ce paramètre est défini par snapshot)
- Importer le fichier de registre suivant :
Windows Registry Editor Version 5.00 [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\W32Time\Config]
"MaxAllowedPhaseOffset"=dword:00000001
"SpecialPollInterval"=dword:00000005
"SpecialInterval"=dword:00000001
Note: Si vous utilisez notepad, assurez vous de sauver le fichier en utilisant un encodage Unicode.
- Si l’OS “invité” ne fait pas partie d’un domaine, exécutez la ligne suivante pour définir une source de temps :
w32tm /config /manualpeerlist:"time.windows.com 1.ca.pool.ntp.org 2.ca.pool.ntp.org" /syncfromflags:MANUAL /update
Note: Les FQDN des hôtes sont séparés par des espaces.
- Executer la commande suivante pour forcer une synchronisation du temps :
w32tm /resync
- Vérifier que l’horloge ne dérive plus avec la commande suivante :
w32tm /monitor /computer:time.windows.com
Un peu d’histoire...
Le système sur lequel je travaille en ce moment se sert énormément du temps, et l’utilise pour prendre les instants de différentes étapes du process. Si pour une raison quelconque l’horloge système devient instable, cela implique que les données générées ne sont plus fiables. Cela peut générer de temps à autres des données corrompues, et ce n’est pas bon pour le business...
J’étais en train d’investiguer une séquence d’événements stockés dans une base de données dans un ordre qui ne pouvait pas s’être produit, parce que le code ne peut pas les générer de cette manière.
Après beaucoup de recherche pour trouver des erreurs dans le code, je suis tombé sur quelque chose d’assez étrange dans les logs de mes applications. Considérant que chacune des lignes est générée par la même thread, et que le temps d’une ligne doit être ultérieur à la ligne précédente :
2009-10-13T17:15:26.541T [INFO][][7] ...
2009-10-13T17:15:26.556T [INFO][][7] ...
2009-10-13T17:15:24.203T [INFO][][7] ...
2009-10-13T17:15:24.219T [INFO][][7] ...
2009-10-13T17:15:24.234T [INFO][][7] ...
Comme ces lignes ont été générées par la même thread, cela veut dire que l’heure système a été radicalement changée entre la deuxième et la troisième ligne. Du point de vue le l’application, le temps est revenu en arrière d’environ deux secondes et que durant ces deux secondes la base de donnée contenait des données générées dans le futur. Ce n’est pas très bon...
L’investigation
En regardant le code source de Log4net, j’ai pu confirmer que le temps est récupéré en utilisant un appel à System.DateTime.Now, ce qui de fait exclut une erreur de code.
J’ai ensuite regardé l’état du service de temps de windows, et en exécutant la commande suivante :
w32tm /stripchart /computer:time.windows.com
J’ai remarqué que la différence de temps entre mon système et le NTP distant était très grande, quelque chose comme 10 secondes. Mais le plus dérangeant n’est pas la différence de temps, mais l’évolution de cette différence de temps.
Dépendant de la charge CPU de la machine virtuelle, la différence de temps devenait très grande au point d’attendre une seconde de retard en moins d’une minute. La machine “invitée” et l’hôte présentaient ce comportement. Comme Hyper-V Integration Services synchronise par défaut l’horloge de toutes les machines virtuelles avec celle de la machine hôte, cela implique de la charge d’une seule des machine influence l’horloge de toutes les autres. La machine hôte peut elle même influencer la cadence globale de l’horloge, puisqu’elle est elle-même virtualisée.
Essai d’explication du phénomène
En essayant de faire une explication éclairée, la source du temps utilisée par windows est le TSC du processeur (par l’utilisation de l’opcode RDTSC), qui est virtualisé. La préemption du CPU par les autres machines virtuelles semble avoir un impact négatif sur le compteur utilisé comme référence par windows.
Plus le CPU est préempté, plus le compteur dérive.
Corriger la dérive
Par défaut, le Service de Temps a un procédé “d’ajustement de phase” qui ralentis ou accélère la cadence l’horloge système pour qu’elle se rapproche de celle d’une source de temps fiable. Le compteur TSC sur le processeur physique est cadencé par le Quartz système (Si cela est toujours le cas). La dérive “normale” de ce genre de composant n’est généralement pas très important, et peut être lié à des facteurs externes tels que la température ambiante. Le service de temps peut gérer sans problème ce genre de dérive lente.
Mais la configuration par défaut semble ne pas être appropriée pour une source de temps qui dérive très rapidement et de manière imprévisible. Il faut donc augmenter la fréquence de l’opération d’ajustement de phase.
Modifier cela est relativement simple, le service de temps doit corriger plus fréquemment la cadence de l’horloge, afin de compenser la charge des machines virtuelles qui ralentissent la cadence de l’horloge.
Les paramètres par défaut dans Hyper-V Server R2 sont ceux d’une machine membre d’un domaine, et qui sont définies ici. La période de récupération du temps depuis une source fiable est beaucoup trop longue, 3600 secondes, considérant la vitesse de dérive de l’horloge.
Quelques paramètres doivent donc être ajustés dans la base de registre pour permettre à l’horloge de rester synchronisée :
- Assigner la valeur 0x1 à SpecialInterval pour permettre l’utilisation de SpecialPollInterval.
- Assigner 10 à SpecialPollInterval pour forcer la lecture de la source NTP toutes les 10 secondes.
- Assigner 1 à MaxAllowedPhaseOffset to 1, pour définir la dérive maximale à une seconde, après quoi l’horloge sera assignée directement si la modification de la cadence de l’horloge ne fonctionne pas.
L’utilisation de ces paramètres ne permet pas d’avoir une horloge parfaitement stable, mais elle va au moins être corrigée rapidement.
Il semblerait qu’un paramètre caché du boot.ini pour Windows 2003, /USEPMTIMER, qui force windows à utiliser le timer ACPI et éviter ce genre de dérive. Je n’ai pas pu confirmer que ce paramètre a quelque sorte d’effet. Je n’ai pas non plus trouvé de méthode pour confirmer quel timer est utilisé par windows.