Skip to content

Sincronizzazione temporale in un ambiente eterogeneo

Dopo aver esaminato vari repository e siti Web, abbiamo finalmente trovato la soluzione che ti mostreremo ora.

Soluzione:

[EDIT] Un'importante riscrittura con riferimenti, dato che ho appena annotato la vecchia risposta a memoria.

Risposta breve: no. Non è possibile ottenere una precisione vicina al millisecondo da un sistema operativo comune su una piattaforma x86/x64 oggi.

DISCLAIMERQuesta è una risposta da profano, poiché sono un normale amministratore di sistema con una visione ordinaria dei computer. Un livello professionale di conoscenza del timekeeping si trova probabilmente tra alcuni sviluppatori del kernel e architetti hardware.

Risposta lunga:

Bisogna iniziare da qualche parte. Lo farò dall'alto verso il basso, partendo dalle applicazioni e scendendo verso gli oscillatori.

Il primo problema non è avere il timekeeping su un computer, ma riuscire a far sì che l'ambiente nel suo complesso sia d'accordo su qualsiasi timekeeping si abbia. Quale cronometraggio? Si scopre che ci sono un paio di modi per tenere il tempo in un computer di oggi. Quello che vediamo più spesso è l'ora di sistema (visualizzata in uno degli angoli della schermata). Iniziamo facendo finta che sia così semplice e complichiamo le cose un paio di paragrafi più avanti.

Vogliamo che l'ora del sistema sia corretta e che sia uniforme su tutti i nostri computer. Abbiamo bisogno di un modo per comunicarlo da una fonte affidabile a un livello così granulare da soddisfare i nostri requisiti, qualunque essi siano.

Trasformiamo il nostro requisito in un livello di tolleranza di 1ms, ovvero il nostro tempo può deviare di 1ms all'interno del nostro ambiente o non raggiungere un obiettivo critico. Passiamo alla concretezza e vediamo cosa può fare Microsoft per noi.

Escludendo gli obsoleti come NT, Windows nativo esegue il suo timekeeping basandosi su ntp semplificato (computer uniti al dominio a partire da XP/2003) o sntp semplificato (computer non uniti al dominio a partire da Win2k) - grazie a @Ryan per aver messo a fuoco questo dettaglio. Microsoft ha fissato due obiettivi quando ha realizzato l'implementazione del timekeeping, nessuno dei quali include il livello di accuratezza da noi desiderato:

"Non garantiamo e non supportiamo la precisione del servizio W32Time tra i nodi di una rete. Il servizio W32Time non è una soluzione NTP completa che soddisfa le esigenze delle applicazioni sensibili al tempo. Il servizio W32Time è progettato principalmente per svolgere le seguenti funzioni:

  • Far funzionare il protocollo di autenticazione Kerberos versione 5.
  • Fornire un tempo di sincronizzazione libero per i computer client.

Il servizio W32Time non è in grado di mantenere in modo affidabile un tempo di sincronizzazione compreso tra uno e due secondi. Tali tolleranze non rientrano nelle specifiche di progettazione del servizio W32Time".

OK. Supponendo che lo stack di servizi venga eseguito su più di un computer e che il livello di tolleranza del tempo si avvicini a 1 ms per la correlazione degli eventi, questa è una delusione. Se lo stack di servizi comprende due computer, non è possibile utilizzare il timekeeping nativo di Windows. Ma già che ci siamo, sottolineiamo un paio di punti chiave sul timekeeping nativo di Windows e includiamo una documentazione approfondita:

Se avete un AD, osservate che l'ora in un determinato dominio sarà sincronizzata dal ruolo PDC Emulator, qualunque sia il DC che lo possiede. L'introduzione dell'ora corretta nel dominio deve quindi avvenire tramite il controller di dominio che esegue il ruolo PDC Emulator. Se si tratta di una foresta multidominio, ciò si traduce nell'emulatore PDC del dominio principale della foresta. Da qui l'orario viene distribuito principalmente agli emulatori PDC dei sottodomini e a ciascun membro del dominio in modo distribuito a ventaglio (con alcune avvertenze). Questo processo è documentato qui. Informazioni ancora più approfondite qui

OK. Cosa possiamo fare?

Per cominciare, abbiamo bisogno di un modo più preciso per sincronizzare l'ora in tutto l'ambiente. Supponendo di non poter utilizzare ntpd per Linux o ntpd per Windows, si potrebbe dare un'occhiata a un client shareware chiamato Tardis, ma probabilmente ce ne sono molti altri da provare.

Abbiamo usato Tardis su un server Win2k3 che girava come emulatore PDC e che aveva un orologio CMOS con un'oscillazione molto ampia; per inspiegabili ragioni storiche non avevamo altra scelta che sincronizzare l'intera rete da esso. Ora è stato sostituito con grande gioia da un ntpd Linux dedicato che porta l'ora dagli orologi atomici esterni, ma Tardis ci ha salvato mirabilmente in quel momento. Non so però se possa aiutarvi a raggiungere una precisione superiore a quella nativa di Windows.

Ma supponiamo da questo punto in poi che abbiamo capito come implementare una perfetta sincronizzazione temporale di rete sostitutiva. Grazie alla sua intrinseca astuzia, ha una capacità di tolleranza inferiore al millisecondo. L'abbiamo messo in atto in modo da far rispettare il modo in cui il nostro AD si aspetta che il tempo si diffonda attraverso la rete.

Questo significa che possiamo ottenere una diagnostica accurata dei sistemi operativi e dei microservizi a una granularità che si avvicina al singolo millisecondo?

Vediamo come i sistemi operativi sull'architettura x86/x64 programmano il tempo del processore.

Utilizzano gli interrupt, che sono bestie multiformi e ricche di sostanza archeologica. Tuttavia, il sistema operativo non è il solo a voler interrompere. Anche l'hardware desidera interrompere, e ha i mezzi per farlo! (E i sistemi operativi stanno al gioco.

Qui le cose si complicano e le risolverò semplificando eccessivamente. Domande? Mi nascondo, mi riparo e vi indico un trattato assolutamente eccellente sull'argomento. (Se siete a caccia di millisecondi su una piattaforma Windows, dovreste davvero leggerlo). Secondo quanto riferito, è in lavorazione una versione aggiornata per Win8.1/Win2012r2, ma non è ancora emersa una data di rilascio.

OK, interruzioni. Ogni volta che deve accadere qualcosa in un sistema operativo, un interrupt attiva l'azione che segue. L'azione è un gruppo di istruzioni prelevate dal kernel, che possono essere eseguite in molti modi diversi. Il punto cruciale è che, nonostante l'interrupt avvenga in un momento che può essere determinato con maggiore o minore precisione a seconda dell'architettura hardware e della gestione degli interrupt del kernel, il momento esatto in cui avvengono le parti successive dell'esecuzione generalmente non può essere determinato. Uno specifico insieme di istruzioni può essere eseguito subito dopo l'interrupt o in ritardo, può essere eseguito in una sequenza prevedibile o meno, può essere vittima di hardware difettoso o di driver mal scritti che influenzano latenze difficili da riconoscere. La maggior parte delle volte semplicemente non si sa. Il timestamp a livello di millisecondi che appare nella successiva tabella è molto preciso, ma è accurato per quanto riguarda il momento in cui si è verificato l'evento?

Fermiamoci brevemente sull'interrupt di cronometraggio. Un interrupt ha un livello di priorità: il livello più basso è quello in cui le applicazioni utente (come un servizio standard) ottengono il loro tempo di processore. Gli altri livelli (più alti) sono riservati all'hardware e al lavoro del kernel. Se arriva un'interruzione a un livello superiore a quello più basso, il sistema farà finta che tutte le interruzioni a priorità più bassa in coda non esistano (finché non saranno state gestite quelle a priorità più alta). In questo modo, le applicazioni e i servizi ordinari in esecuzione saranno gli ultimi della fila per il tempo del processore. Al contrario, la priorità più alta è data all'interrupt dell'orologio. L'aggiornamento del tempo verrà quasi sempre effettuato in un sistema. Questa è una semplificazione eccessiva quasi criminale di come funziona il tutto, ma serve allo scopo di questa risposta.

L'aggiornamento del tempo consiste in realtà in due operazioni:

  • Aggiornare l'ora del sistema / Ovvero l'orologio a muro / Ovvero quello che dico quando qualcuno mi chiede che ora è / Ovvero la cosa che ntp fa andare un po' avanti e indietro rispetto ai sistemi vicini.

  • Aggiornamento del conteggio dei tick, usato ad esempio per misurare la durata dell'esecuzione del codice.

Ma sia che si tratti dell'ora del muro o del conteggio dei tick, da dove prende l'ora il sistema? Dipende molto dall'architettura hardware. Da qualche parte nell'hardware uno o più oscillatori fanno il ticchettio, e questo ticchettio viene portato attraverso uno dei diversi percorsi possibili in un'interfaccia per il contatto con il kernel, che aggiorna con maggiore o minore precisione e accuratezza il suo wall time e il conteggio dei tick.

Esistono diversi modelli di progettazione per il posizionamento degli oscillatori in un sistema multicore; la differenza principale sembra essere il posizionamento sincrono o asincrono. Questi modelli, insieme alle rispettive sfide per un timekeeping accurato, sono descritti qui a titolo di esempio.

In breve, il timekeeping sincrono ha un orologio di riferimento per multicore, il cui segnale viene distribuito a tutti i core. Il timekeeping asincrono ha un oscillatore per core. Vale la pena notare che i più recenti processori multicore di Intel (Haswell) utilizzano una forma di progettazione sincrona che si avvale di un bus seriale chiamato "QuickPath Interconnect" con "Forwarded Clocking", cfr. scheda tecnica. Il Forwarded Clocking è descritto in termini tali da consentire a un profano (io) di ottenere una rapida comprensione superficiale.

OK, quindi, tolto di mezzo tutto questo nerderismo (che è servito a dimostrare che il cronometraggio è un compito pratico complesso con una storia molto viva), diamo un'occhiata più da vicino alla gestione degli interrupt.

I sistemi operativi gestiscono gli interrupt utilizzando una delle due strategie distinte: ticking o tickless. I vostri sistemi utilizzano l'una o l'altra, ma cosa significano questi termini?

Kernel con ticchettio inviare interrupt a intervalli fissi. Il sistema operativo non può misurare il tempo con una risoluzione più fine dell'intervallo di tick. Anche in questo caso, l'elaborazione effettiva coinvolta nell'esecuzione di una o più azioni può contenere un ritardo superiore all'intervallo di tick. Si pensi, ad esempio, ai sistemi distribuiti (come i microservizi), dove i ritardi inerenti alle chiamate interservizio potrebbero consumare una quantità di tempo relativamente elevata. Tuttavia, ogni serie di istruzioni sarà associata a uno o più interrupt misurati dal sistema operativo con una risoluzione non superiore al tempo di tick del kernel. Il tempo di ticchettio ha un valore di base ma, almeno in Windows, può essere diminuito su richiesta da una singola applicazione. Si tratta di un'azione associata non solo a benefici, ma anche a costi, e che comporta un bel po' di dettagli.

I cosiddetti kernel tickless (che hanno un nome poco descrittivo) sono un'invenzione relativamente nuova. Un kernel tickless imposta il tempo di tick a intervalli variabili (il più a lungo possibile nel futuro). Il motivo è che il sistema operativo consente dinamicamente ai core del processore di entrare in vari livelli di sospensione il più a lungo possibile, con il semplice scopo di risparmiare energia. I "vari livelli" comprendono l'elaborazione delle istruzioni a piena velocità, l'elaborazione a velocità ridotta (cioè a velocità ridotta del processore) o l'assenza di elaborazione. I diversi core possono operare a velocità diverse e il kernel tickless cerca di lasciare i processori il più possibile inattivi, anche mettendo in coda le istruzioni per farle partire in gruppi di interruzioni. In breve, i diversi core in un sistema multiprocessore possono andare alla deriva nel tempo l'uno rispetto all'altro. Questo, ovviamente, è un problema che non può essere risolto con le nuove architetture di processori a risparmio energetico e con i kernel senza ticchettio che consentono un risparmio energetico efficiente. A confronto con un kernel ticchettante (intervallo di ticchettatura statico) che risveglia continuamente tutti i core del processore, indipendentemente dal fatto che ricevano o meno lavoro effettivo, e in cui il cronometraggio comporta un certo grado di imprecisione, ma in misura relativamente affidabile rispetto ai kernel ticchettanti.

Il tempo di tick standard di Windows - cioè la risoluzione del sistema - è di 15,6 ms fino a Windows 8/2012, dove il comportamento predefinito è tickless (ma è reversibile al kernel ticking). Il tempo di ticchettio predefinito di Linux credo dipenda dalla compilazione del kernel, ma questa nicchia è ben al di fuori della mia esperienza (e anche di questa), quindi si consiglia di ricontrollare se si dipende da essa. I kernel Linux credo siano compilati senza ticchettio a partire dalla versione 2.6.21 e possono essere compilati con vari flag che ottimizzano il comportamento senza ticchettio (e di cui ricordo solo alcune varianti di no_hz).

Questo per quanto riguarda i sistemi bare metal. Nei sistemi virtuali la situazione è ancora peggiore, in quanto la contesa tra VM e hypervisor in diversi modi rende estremamente difficile un accurato timekeeping. Qui c'è una panoramica per VMware e qui ce n'è una per RHEL KVM. Lo stesso vale per i sistemi distribuiti. I sistemi cloud sono ancora più difficili, poiché non ci avviciniamo nemmeno lontanamente agli hypervisor e all'hardware reali.

Per concludere, ottenere un tempo accurato da un sistema è un problema a più livelli. Partendo dal basso verso l'alto, da un punto di vista di alto livello, dobbiamo risolvere i seguenti problemi: La sincronizzazione del tempo interno tra l'hardware e il kernel, l'elaborazione degli interrupt e i ritardi nell'esecuzione delle istruzioni di cui vogliamo conoscere il tempo, se in un ambiente virtuale le imprecisioni sono dovute all'incapsulamento di un secondo livello di OS, la sincronizzazione del tempo tra sistemi distribuiti.

Pertanto, a questo punto della storia dell'informatica, non otterremo una precisione al milisecondo da un'architettura x86/x64, almeno non utilizzando uno dei sistemi operativi più comuni.

Ma quanto ci si può avvicinare? Non lo so e dovrebbe variare molto tra i diversi sistemi. Riuscire a capire l'imprecisione dei propri sistemi specifici è un compito arduo. Basta vedere come Intel suggerisce di fare il benchmarking del codice per capire che i sistemi ordinari, come quelli che mi capita di amministrare, sono molto fuori controllo da questo punto di vista.

Non penso nemmeno di riuscire a raggiungere "Tutte le funzionalità di ottimizzazione energetica, la tecnologia Intel Hyper-Threading, il frequency scaling e la modalità turbo sono state disattivate". nei sistemi critici, tanto meno di armeggiare con wrapper di codice in C e di eseguire test a lungo termine per ottenere risposte successive. Cerco solo di tenerli in vita e di imparare il più possibile su di loro senza disturbarli troppo. Grazie timestamp, so che non posso fidarmi completamente di te, ma so che non sei fuori di molti secondi. Quando la precisione al millisecondo diventa importante, una sola misura non è sufficiente, ma è necessario un numero maggiore di misure per verificare il modello. Cos'altro possiamo fare?

Infine, è interessante vedere come gli esperti di sistemi operativi in tempo reale pensano alla latenza di interruzione. C'è anche un'alternativa molto interessante alla sincronizzazione del tempo, in cui vengono rese pubbliche molte statistiche, metodologie e whitepaper interessanti. Se a questo si aggiungono i futuri sviluppi dell'architettura hardware e del kernel, tra qualche anno la questione della precisione del timekeeping potrebbe non essere più un problema. C'è da sperare.

Puoi aggiungere valore ai nostri contenuti fornendo la tua esperienza nelle annotazioni.



Utilizzate il nostro motore di ricerca

Ricerca
Generic filters

Lascia un commento

Il tuo indirizzo email non sarà pubblicato.