Upload
others
View
3
Download
0
Embed Size (px)
Citation preview
1
Università degli Studi di Roma “Tor Vergata”
Facoltà di Scienze MM.FF.NN
Corso di Laurea in Informatica
Laurea triennale
Trattamento dei dati all’interno del progetto !CHAOS
Sistema di controllo basato su alta astrazione ed adattabilità
di
Claudio Bisegni
Relatore:
prof. Vigliano Loredana
Correlatore:
prof. Luciano Catani
a.a. 2011/2012
2
Indice
Introduzione .......................................................................................................... 4
Obiettivo !CHAOS ................................................................................................. 5
1.2 Caratteristiche generali ..................................................................................... 6
Scenari e Requisiti ............................................................................................... 8
2.1 Requisiti e Problematiche ................................................................................. 9 2.1.1 Centralizzazione ........................................................................................................ 10 2.1.2 Descrizione della strumentazione ..................................................................... 11 2.1.3 Monitoraggio dello stato degli apparati .......................................................... 13 2.1.4 Logiche di controllo. ................................................................................................ 14 2.1.5 Archiviazione dei dati acquisiti .......................................................................... 15 2.1.6 Controllo remoto della strumentazione ......................................................... 17 2.1.7 Gestione degli eventi (allarmi, soglie, etc.) .................................................... 18 2.1.8 Acquisizione dati su evento .................................................................................. 19 2.1.9 Gestione dei Metadati e del LogBook ............................................................... 21
2.2 Requisito di schema libero ............................................................................. 22
INGEGNERIA DEL SOFTWARE ....................................................................... 24
3.1 Architettura software del sistema ............................................................... 24 3.1.1 Livello Comune .......................................................................................................... 27 3.1.2 Instruments Drivers ................................................................................................ 35
3.2 Tecnologie ............................................................................................................ 40 3.2.1 Serializzazione ........................................................................................................... 40 3.2.2 Sistema RPC ................................................................................................................ 42 3.2.3 Sistema di cache dei dati in tempo reale ........................................................ 42
3.3 Soluzioni a problematiche architetturali .................................................. 43 3.4 Architettura Implementativa ........................................................................ 46 3.4.1 Architettura del sotto sistema RPC (Common Layer) .............................. 48 3.4.2 Architettura del sotto sistema degli Eventi (Common Layer) .............. 49 3.4.3 Architettura del direct I/O per la gestione dei dati (Common Layer) 50 3.4.4 Architettura MessageChannels (Common Layer) ...................................... 51 3.4.5 Architettura EventChannels (Common Layer) ............................................ 53 3.4.5 Architettura del Control Unit Toolkit ............................................................... 54 3.4.6 Architettura dell’UIToolkit ................................................................................... 57
3
3.4.7 Architettura dell’Execution Unit Toolkit ........................................................ 61
Gestione dei Dati live in !CHAOS .................................................................. 65
4.1 Architettura ......................................................................................................... 65 4.2 Implementazione .............................................................................................. 66 4.3 Performance ........................................................................................................ 70
Gestione dei Dati STORICI in !CHAOS ......................................................... 73
5.1 Architettura ......................................................................................................... 75 5.2 Implementazione .............................................................................................. 79 5.2.1 ChaosQL ........................................................................................................................ 79 5.2.2 Riposte sincrone ed asincrone alle query di ricerca ................................. 82 5.2.3 Gestione degli indici ................................................................................................ 84 5.2.4 Gestione dell’ageing sui dati. ............................................................................... 87 5.2.4 Gestione dell’archiviazione dei pacchetti nel filesystem ......................... 88
Gestione dei Dati live e Storici IN UN UNICO SERVIZIO ........................ 90
6.1 Architettura proposta ...................................................................................... 90 6.2 Problematiche .................................................................................................... 91
OBIETTIVI raggiunti e futuro Prossimo .................................................... 92
Conclusioni .......................................................................................................... 94
Bibliografia ......................................................................................................... 97
4
INTRODUZIONE L'Istituto Nazionale di Fisica Nucleare è tra gli enti dedicati alla ricerca nel
campo della fisica delle particelle atomiche e sub-atomiche quello che può
vantare una tradizione nella realizzazione di acceleratori di particelle tra le più
solide e riconosciute a livello internazionale. Acceleratori come Ada, il primo
collisore di particelle al mondo, e Adone entrambi costruiti ai Laboratori di
Frascati (LNF), sono stati dei punti di riferimento nel panorama mondiale e il
loro successo ha dato vita ad una scuola di fisici ed ingegneri specializzati in
questo settore ancora in grado di competere ai massimi livelli.
Negli anni si è arrivati alla realizzazione di DAFNE 1 che date le sue
caratteristiche in dimensione e numero di apparati coinvolti, ha reso
necessario lo sviluppo di diverse soluzioni innovative tra cui un sistema di
controllo moderno e più completo rispetto a quelli usati in esperimenti
precedenti. A tale scopo fu ideato e realizzato il primo sistema di controllo
basato su personal computer, a tutt'oggi, ancora in funzione. Dall'esperienza
acquisita negli anni e con il prospettarsi di nuovi progetti all'orizzonte ai LNF
si è sentita la necessità di fare un successivo passo in avanti e la
predisposizione alla ricerca ha portato ad investigare soluzioni e tecnologie
non tipiche di questo settore applicativo ma con un grande potenziale
innovativo.
1 Double Anular ring for Nice Experiments
5
OBIETTIVO !CHAOS Considerato il contesto precedente il progetto !CHAOS (Control system
based on a Highly Abstracted and Open Structures) si prefigge di definire un
nuovo paradigma per i sistemi di controllo2 degli acceleratori di particelle e
grandi apparati sperimentali. Oltre ad una nuova topologia nell’acquisizione
dati e nell’acquisizione dei dati su trigger3 hardware, il nuovo modello
proposto pone al centro di tutto la semplicità di utilizzo, la scalabilità e
l’estrema adattabilità della strumentazione alle varie esigenze di utilizzo unite
ad una costante semplicità di implementazione e gestione. Le principali
caratteristiche possono essere riassunte dai seguenti punti:
• Definizione di una nuova topologia che permetta di integrare SdiC,
DAQ, e triggered DAQ;
• Completa astrazione sul dataset4 della strumentazione da controllare;
• Gestione del flusso di enorme mole di dati, disponibili in tempo reale
e in uno storico;
• Totale indipendenza del sistema dal dataset della strumentazione;
• Completa astrazione architetturale sull’implementazione
dell’archiviazione dei dati in tempo reale e dei dati storici.
Un sistema di controllo ha il compito di permettere il monitoraggio dei valori
dei canali, in ingresso e in uscita, e il controllo remoto dei rilevatori e attuatori
che permettono il corretto funzionamento del sistema globale.
Nei grandi apparati questa esigenza diventa essenziale perché la grande
quantità di strumentazione e le dimensioni degli apparati rendono difficile e a
volte impossibile la gestione manuale di ogni aspetto della macchina.
Ne è un esempio L’LHC5 del CERN, acceleratore nucleare di quasi 30 KM di
raggio, che insieme i suoi rilevatori (ALICE6, ATLAS7, CMS8, LHCb9) è
2 SdiC, sistema di controllo 3 Triggered DAQ, triggered data acquisition 4 Insieme che definisce la struttura dei dati e i canali di I/O di uno strumento 5 Large Hadron Collider 6 A Large Ion Collider Experiment 7 A Torrodoidal LHC ApparatuS
6
composto da vari sottosistemi, ognuno dei quali può a sua volta dividersi in
altri sottosistemi ancora più piccoli.
E' evidente che un sistema di queste dimensioni abbia bisogno di un sistema
in grado di tenere sotto controllo ogni sua parte, in molti casi ricorrendo a
degli automatismi.
La corretta organizzazione dell'iterazione di ogni sottosistema con gli
algoritmi di controllo e monitoraggio dei valori dei vari canali di I/O, fa si che
l’intero sistema possa funzionare correttamente con un minimo di intervento
umano.
In particolare le grandi dimensioni e complessità delle macchine moderne, e
di conseguenza dei loro sistemi di controllo, hanno portato a concentrare
l'attenzione, sin dall'inizio della fase di analisi, su tre aspetti importanti:
• semplicità di integrazione e di adattamento alle esigenze
• elevata astrazione per permettere differenti implementazioni di
coesistere.
• alta scalabilità per la gestione di grandi quantitativi di dati.
La semplicità, permette di poter velocizzare l'applicazione del sistema di
controllo concentrandosi sulle necessità dell’applicazione e non sul controllo
stesso, diminuendo la quantità di errori.
Una buona astrazione permette di poter usare il sistema senza rinunciare alle
proprie necessità con piena flessibilità nella descrizione dei canali di I/O e
piena flessibilità su come implementare o modificare i livelli di archiviazione
dati e di creazione dei moduli software.
Un’alta scalabilità permette di poter adeguare il sistema e di far fronte ad
adeguamenti futuri in ordine di quantità di dati nell'unità di tempo (larghezza
di banda).
1.2 Caratteristiche generali Per ottenere l’obiettivo descritto precedentemente, !CHAOS è stato progettato
come framework software. Sono stati identificati gli stakeholder all'interno di
8 Compact Muon Solenoid 9 Large Hadron Collider beauty
7
enti di ricerca, università e società dell'industria in grado di garantire un'ampia
copertura in fase di analisi. Il disegno delle sue caratteristiche, dei protocolli e
dei livelli software è basato su una completa astrazione dei servizi, dei
componenti hw e sw e degli apparati da controllare, allo scopo di ottenere un
framework ampiamente adattabile, configurabile, modulare e nello stesso
tempo, semplice da usare ed applicare. Queste caratteristiche gli conferiscono
un ridotto tempo di apprendimento nel suo utilizzo, sia per quanto riguarda lo
sviluppo di algoritmi di controllo che dei driver per l'interfacciamento dello
strumento hardware.
Un ulteriore punto a favore del suo disegno è quello di permettere la
parallelizzazione dello sviluppo del framework con quello della sua
applicazione. Il rilascio di nuove versioni e l'introduzione di nuove
funzionalità non necessiteranno di lunghi periodi di apprendimento, in quanto
l'astrazione, che ne ha guidato la progettazione sin dalle prime fasi di analisi,
interpone un muro virtuale tra framework e applicazione invalicabile da
entrambe le direzioni.
In futuro potranno quindi essere implementati in !CHAOS nuovi layer che
rimarranno compatibili con le installazioni e applicazioni sviluppate su
versioni precedenti.
Tutto questo ha favorito la decisione di passare dallo studio di fattibilità alla
realizzazione concreta di !CHAOS; per questo l'INFN ha dato vita ad un
progetto pluriennale nell’ambito delle sue iniziative di ricerca tecnologica ed
interdisciplinare per poter meglio supportare l’attività di ricerca e la fase
applicativa.
8
SCENARI E REQUISITI Il compito di un sistema di controllo è di permettere, tipicamente da remoto, il
monitoraggio (dei valori di un insieme di canali di input) ed il controllo (dei
valori di un insieme di canali di output) di un sistema complesso, costituito da
uno o più apparati ognuno dei quali può essere a sua volta composto da uno o
più strumenti nonché da altri sottosistemi. Questa definizione permette, in
modo approssimativo, una prima identificazione dei requisiti minimi per un
sistema di controllo:
• Gestione della comunicazione, e loro tracciabilità, tra i vari elementi del
sistema [rilevatori ed attuatori];
• Monitoraggio dei valori dei canali di I/O di ogni strumento;
• Controllo remoto di uno strumento;
• Storicizzazione della variazione dei valori dei canali I/O;
• Adattabilità al cambio tecnologico;
• Possibilità di definire di algoritmi che possano regolamentare, leggendo
i valori di alcuni strumenti, il comportamento di altri.
I precedenti punti definiscono in modo generale, ma comunque completo, le
proprietà e meccanismi necessari; non esplicitamente dichiarato c'è il più
complesso dei requisiti: quello della scalabilità. Un sistema controllo si può
definire scalabile quando all'aumentare delle informazioni da gestire, degli
algoritmi da eseguire o del numero dei componenti o dei sottosistemi da
controllare, la sua struttura e le modalità di funzionamento rimangono
inalterate e solo la configurazione deve essere modificata (facilmente) per far
fronte alle nuove necessità.
Tale flessibilità è rappresentata per esempio dalla possibilità d'inserimento,
nel flusso di controllo e di monitoraggio, di nuovi sottosistemi senza però
compromettere il funzionamento del sistema globale; Dall'altra parte il
numero di risorse del sistema di controllo (Storage, database per le
interrogazioni) deve poter essere adeguato per rispondere alle nuove richieste
del sottosistema: questa proprietà prende il nome di HotInsert.
È evidente che la scalabilità è una proprietà che deve far fronte a varie
esigenze. L'aumento delle risorse di archiviazione e di ricerca dei suoi dati
9
acquisiti dal sistema di controllo potrebbe rendersi necessario per far fronte
non solo all'inserimento di nuovi sottosistemi ma anche all'inserimento di
nuovi algoritmi di controllo.
Un possibile scenario che possa evidenziare questa esigenza è il seguente.
Consideriamo l'acceleratore DAFNE dei Laboratori Nazionali di Frascati
dell’INFN come sistema complesso; esso è costituito principalmente da tre
sottosistemi:
• Acceleratore lineare (LINAC) di elettroni (e-) e positroni (e+);
• Doppio anello di accumulazione dove avvengono le collisioni e+e- e
dove sono collocati i rilevatori;
• Beam Test Facility (BTF).
Ognuno dei tre sistemi è controllato dallo stesso sistema centralizzato. Si
prenda in considerazione la necessità che qualcosa nella BFT debba essere
modificato o aggiornato, sia dal punto di vista di strumentazione che di
algoritmi di controllo. In questo caso l’applicazione delle modifiche deve
poter essere riconosciuta dal controllo e gestita, mentre il resto dei due
sottosistemi prosegue il proprio lavoro. È evidente che un sistema
centralizzato deve poter soddisfare questa necessità, in caso contrario
avremmo dovuto realizzare due differenti sistemi di controllo, uno per il
LINAC e per la zona di collisione e uno per la BTF.
2.1 Requisiti e Problematiche Lo studio di ogni requisito, condotto con l'affiancamento dell'esperienza dei
vari stakeholder intervistati, è stato condotto tenendo conto della sua
integrazione nella operatività di un sistema di controllo. Per ognuno di essi si
è cercato di individuarne le problematiche spesso celate dietro il contesto in
cui si pone. Molte problematiche non sono legate ai requisiti ma bensì
intrinseche del progetto stesso, mentre altre sono dovute alla scelta di creare
un sistema altamente adattabile basato sull'astrazione. Nei seguenti paragrafi
saranno analizzati e studiati in maniera approfondita i vari requisiti sopra
esposti. Divisi per aree ne saranno studiate le problematiche e verranno
introdotte nuove idee che andranno a completare l'insieme delle funzionalità
dell'architettura da realizzare.
10
2.1.1 Centralizzazione Un sistema di grande dimensioni è composto da molti sottosistemi, ognuno
dei quali può essere molto complesso. I gruppi di lavoro che realizzano i vari
sottosistemi, per ovvie ragioni, difficilmente saranno gli stessi. Il gruppo che
lavoro al funzionamento di un acceleratore, sarà differente da quello che
lavorerà su di un rilevatore. Le differenti esigenze dei gruppi potrebbero
portare a differenti scelte sull'uso di sistemi di controllo, di archiviazione dati
o di differenti database.
Un altro problema è legato alla gestione dei fermi di uno o più sottosistemi.
Come detto in precedenza questi dovrebbero poter essere spenti, sostituiti o
aggiornati, mentre il resto dei sistemi continua a funzionare. La
centralizzazione e l'unificazione di tutti i controlli sotto un unico sistema può
essere realizzata a condizione di risolvere i seguenti problemi:
• Gestione centralizzata e globale delle regole d’implementazione dando
comunque la massima libertà nella specializzazione dei vari
sottosistemi;
• Uso contemporaneo di differenti implementazioni di archiviazione e di
ricerca su dati acquisiti;
• Scalabilità di ogni parte del sistema in caso di aumento dell'uso di
risorse;
Il primo punto pone risalto il concetto di “gestione” centralizzata. Sarà
necessario quindi un gestore di metadati o metadata server (MDS); un
servizio grazie al quale si potranno richiedere informazioni relative alle
funzionalità e alla descrizione delle composizioni dei dataset di ogni
strumento collegato al sistema di controllo. Si potrebbero ad esempio poter
gestire informazioni sulla localizzazione fisica degli strumenti, le
informazioni riguardanti il modello, produttore, numero di serie, etc.
Inoltre una delle funzioni importanti di cui un sistema di controllo necessita,
realizzabile all’interno dell’MDS, è quella del Log Book; un archivio di
eventi, che vanno dalla registrazione dei difetti di qualche strumento a note
scaturite da osservazioni da annotare durante il funzionamento della
strumentazione. Avendo già catalogato tutte le informazioni ad essa relative,
11
l’utilità di poter collegare logicamente un evento a uno strumento renderà
possibile la realizzazioni di funzioni statistiche o di ricerca utili al debugging
dei problemi come anche alla gestione dei report sulle operazioni effettuate.
Tutte queste informazioni potranno poi essere correlate con tutte le altre
rappresentate dai dati acquisiti dagli strumenti, permettendo così una visuale
completa di tutto l’insieme, rendendo di fatto, l’architettura ben definita sia
dal punto di vista funzionale che dal punto di vista informativo.
La scalabilità invece permette di progettare il sistema in modo di avere ogni
modulo software e hardware sviluppato e configurato in modo di non essere
“unico”. La possibilità di averne un numero qualsiasi di istanze, rende tutto il
sistema più robusto ai possibili guasti dell’hardware su cui gira.
2.1.2 Descrizione della strumentazione Lo studio e l'analisi di un sistema con le caratteristiche sin qui descritte deve
necessariamente partire da un concetto di astrazione, per permettere quindi
un'assoluta generalità in termini di strumentazione hardware da controllare.
Ogni strumento hardware ha le sue caratteristiche in termini di funzioni e di
canali di I/O. Ogni canale corrisponde a dei dati che vengono accettati oppure
erogati dall’hardware. Deve essere data piena libertà e flessibilità sulla
descrizione di queste caratteristiche. In pratica il sistema di controllo deve
poter essere configurato (o auto-configurato) in modo del tutto indipendente
dagli strumenti.
In pratica, quello che si vuole ottenere, è che il modulo software che coordina
lo strumento si possa in qualche modo annunciare verso i metadata servers e
dichiarare le proprie caratteristiche raggruppabili nei seguenti punti:
• Il dataset cioè insieme dei canali di I/O per ognuno dei quali sono
descritte tutte le informazioni che lo caratterizzano (tipo di dato,
descrizione del canale, valori massimi e minimi sia in output che
input, valore di default, etc.);
• I comandi custom sono funzioni invocabili tramite sistema RPC10, per
la gestione di operazioni personalizzate della strumentazione. In 10 Remote Procedure Call, sistema per l’esecuzione remota di una funzione o servizio.
12
questo caso sono descritti i parametri della funzione nello stesso modo
dei canali di I/O;
• Informazioni generali utili per la descrizione semantica dello
strumento, canale, etc.
Ogni canale rappresenta il modo in cui uno strumento comunica con il mondo
esterno accettando dati in ingresso o fornendo lo stato delle sue misure in
uscita.
Un canale può accettare o generare valori di tipi differenti:
• Tipi standard, identificati da caratteri, interi 32/64 bit, double;
• Tipi strutturati, costituiti da gruppi di tipi standard o da altre strutture;
• Tipi binari che differentemente dai primi due tipi, necessitano di
ulteriori informazioni che ne descrivano il contenuto. Si potrebbero
rappresentare ad esempio un array d’interi, una matrice
multidimensionale oppure un’immagine. A tal fine sono state
individuate le seguenti caratteristiche:
• Tipo, realizzato con I primi due punti dell’elenco precedente;
• Numero di dimensioni, nel caso si vogliano descrivere forme
d’onda, matrici, immagini, etc.;
La possibilità di poter creare strutture complesse e personalizzate per
descrivere le caratteristiche di uno strumento, realizza il concetto di astrazione
dell’hardware in CHAOS. Questo concetto verrà ripreso e maggiormente
descritto nel paragrafo successivo. Per meglio organizzare i dataset si è
convenuto, in fase di analisi, di associare a ognuno di essi una classificazione.
L’appartenenza di uno o più strumenti, di uno o più produttori, alla stessa
classe di dataset denota solo comportamenti simili. Ad esempio, creando una
classe per gli alimentatori che contiene caratteristiche standard comuni, sarà
possibile associarla a differente marca usata senza dover crearne una per ogni
nuovo modello. Ovviamente caratteristiche aggiuntive dovranno essere
specificate per i singoli alimentatori che le supportino. Questo ovviamente è
possibile se tale classe è associata ad alimentatori, seppure con
implementazioni differenti, che hanno in comunque l’insieme di
caratteristiche in ingresso e in uscita descritte dalla classe.
13
Questo rafforza ancora di più il concetto di astrazione in CHAOS. Così
facendo si potranno creare algoritmi di calcolo o di controllo che lavorano su
classi di strumenti.
Per realizzare tale astrazione e per collegare lo strumento al sistema di
controllo, il framework da progettare deve simulare lo sviluppo di un driver
che, in modo semplice, permetta di realizzazione tutto ciò sin qui descritto.
2.1.3 Monitoraggio dello stato degli apparati Uno dei requisiti fondamentali di un sistema di controllo è ovviamente quello
del monitoraggio dello stato di uno strumento; questo consiste nel
visualizzarne, nel tempo, l’andamento del valore di uno o più canali di uscita
e d’ingresso. Questa operazione, in un sistema di controllo, avviene sia dai
programmi di interfaccia utente di monitoraggio che dai programmi di
controllo; quest’ultimi saranno studiati in dettaglio nel paragrafo successivo.
L’operazione di monitoraggio, serve per avere la visualizzazione costante, a
bassa velocità di aggiornamento di come sono i valori dei canali della
strumentazione. Per esempio si può tenere d’occhio tutti i sensori di
temperatura di un certo settore di un acceleratore per verificare che non ci
siano alterazioni sensibili. Questi controlli sono fatti sia da algoritmi che, in
caso di necessità gestiscono gli allarmi di sicurezza, ma sono anche usati dalle
persone in sala di controllo per vedere cosa asta succedendo.
Per lo sviluppo del software che deve realizzare questa parte importante e
necessaria del sistema di controllo, si deve tener conto principalmente di due
problematiche:
• La necessità di garantire l’uso di servizi che permettano la
memorizzazione e l’accesso ai dati garantendo il failover e il load-
balancing;
• Rendere accessibile la lettura dei canali di I/O a più client possibili
senza incrementare gli accessi diretti allo strumento.
Nel primo punto il problema è il carico delle troppe richieste su un unico
strumento, nel secondo è rappresentato dalla necessità di poter scalare tale
14
infrastruttura secondo le necessità e, a sistema avviato, di poter resistere a
crash di un certo numero di server. La fase di monitoring rappresenta quindi
una funzione essenziale in un sistema di controllo. Per questa attività non è
necessario avere ogni dato emesso dagli strumenti ma un valore campionato a
certi intervalli di tempo che vanno dalla decina di campionamenti al secondo
in su. Pensando ad un sistema grande e complesso, la necessità di monitorare
ogni sottosistema e strumento rende bene l’idea di quanto complessa possa
essere la realizzazione del software che realizzerà questo requisito.
L'architettura deve permettere di astrarre la realizzazione di questo servizio in
modo da poter dare la possibilità di adottare differenti tecnologie e di poterle
adottare contemporaneamente. Questa esigenza permetterà di avere differenti
realizzazioni del servizio di monitoraggio rispondente a differenti
caratteristiche, così facendo si potrebbero usare tecnologie specifiche e
costose solamente dove servissero e lasciare tecnologiche più economiche a
gestire il resto. La differenziazione nelle tecnologie potrebbe essere usata per
condividere i dati di strumentazione con differente velocità nella variazione
dei valori dei canali di output, come ad esempio per supportare differenti
livelli di affidabilità secondo l’importanza di uno strumento rispetto a un
altro. Questo aiuterà a regolare i costi dell'hardware da usare poiché si
potranno scegliere differenti soluzioni contemporaneamente. Il tutto
ovviamente deve rimanere trasparente al funzionamento del sistema.
2.1.4 Logiche di controllo. In questo paragrafo si andrà in dettaglio nello studio delle problematiche da
affrontare per includere nel sistema di controllo la gestione dell’esecuzione di
procedure automatiche; questi algoritmi hanno principalmente lo scopo di
regolare automaticamente il funzionamento di alcuni strumenti prendendo in
considerazione dei dati acquisiti da altri. Come si è visto l’operazione di
monitoraggio dei valori dei canali di I/O può accettare di perdere pacchetti in
quanto deve poter permettere la verifica in linea di massima dell’andamento
del funzionamento di ogni strumento o sottosistema.
Nel caso del controllo automatico invece la perdita di letture dei canali di I/O
di alcuni strumenti potrebbe non essere accettabile. Tali algoritmi potrebbero
15
avere la necessità di lavorare su tutti i dati acquisiti dallo strumento, e anche
se con un certo ritardo nella ricezione, avrebbero necessità di avere la
sicurezza di non perdere alcun dato. Questi requisiti si vanno ad aggiungere a
quelli del monitoraggio. Anche qui ovviamente l’intero sistema deve resistere
al carico di molte richieste e al malfunzionamento dei server che realizzano
l’infrastruttura di condivisione dei valori dei canali di I/O degli strumenti.
2.1.5 Archiviazione dei dati acquisiti In un sistema di controllo la possibilità di tenere traccia dell’andamento nel
tempo di tutta la strumentazione, rappresenta uno strumento necessario non
solo in caso di guasti o eventi significativi da studiare, ma anche per il solo
scopo di archiviare il comportamento di ogni strumento; permettendo di
risalire allo stato di tutta la strumentazione in un determinato periodo o di
eseguire ricerche su eventi legati a valori rilevanti di canali di I/O. Per lo
studio di questa parte si è partiti dall'identificazione dei requisiti che sono
generalizzabili ad ogni singolo strumento; Uno dei principali è il tempo di
acquisizione dei dati dello storico, che rappresenta la granularità con cui si
vuole che i dati siano storicizzati. All’interno di un sistema complesso come
un acceleratore di particelle, ci sono strumenti che lavorano a differenti
velocità di acquisizione dei dati; si va dagli HZ fino ai GigaHZ . Con la
tecnologia attuale sarebbe impossibile acquisire e mantenere per un tempo
indeterminato dati acquisiti ad alte frequenze di un sistema contenente
centinaia di strumenti. Anche nel caso di dataset di piccole dimensioni ad alte
frequenze di campionamento si avrebbero comunque dimensioni
considerevoli anche per il singolo strumento. Sono stati quindi evidenziati
nuovi requisiti che migliorano e ottimizzano la persistenza:
• tempo di validità per ogni classe di strumentazione o per uno specifico
strumento;
• rimozione graduale dei dati più vecchi per granularità nel tempo ed
importanza.
Mentre il primo punto permette di definire l’intervallo passato il quale i dati
possono essere rimossi, Il secondo permette di definire la granularità (numero
di dataset nell'unità di tempo) dei dati storicizzati per intervalli temporali; in
16
questo modo si avrebbe un maggior dettaglio per dati recenti perdendone
invece su quelli sempre più vecchi. Insieme alla granularità ovviamente sono
necessarie regole per determinare l'importanza di un dataset, questo affinché
rimanga memorizzato, pur rientrando in quelli che andrebbero cancellati per
la regola di granularità.
Sempre con l'ottica di realizzare un framework usabile su vasta scala e da più
gruppi di lavoro si sono identificati dei requisiti che vanno a regolare la
realizzazione pratica della storicizzazione. L'uso di un database al posto di un
altro non è del tutto definibile a priori. Per alcune necessità un database
NOSQL potrebbe essere più scalabile e utile in termine di funzione rispetto a
un database SQL. In altre situazioni potrebbe essere vero il contrario.
Essendoci inoltre, in tutto il framework da realizzare, un filo conduttore unico
identificato nell'astrazione dei dati, un tradizionale database SQL sarebbe
inappropriato basato, infatti, su schemi determinati che identificano i dati.
Tutte queste considerazioni fanno si che i requisiti per la realizzazione
dell'infrastruttura di storicizzazione in CHAOS si debba basare sui seguenti
punti:
• Personalizzazione del metodo di memorizzazione del dato da
storicizzare;
• Personalizzazione del modo in cui implementare indici sui dati;
• Personalizzazione del sistema di ricerca su indice.
Il framework base da realizzare dovrà basarsi su questi tre requisiti
realizzando un astrazione in cui sarà possibile personalizzare, a seconda dei
caso, uno o più punti rispetto alle proprie esigenze. Data l'alta adattabilità ed
astrazione è necessario realizzare un semplice simulatore di un linguaggio di
interrogazione, in modo da uniformare e standardizzare le operazioni
sull'infrastruttura e sui dati di storico; in grado di descrivere sinteticamente i
seguenti comandi:
• Inserimento di un dataset nello storico;
• Ricerca dei dataset mediante l'uso regole e costrutti sui valori dei
canali di I/O;
• Creazione d’indici su logiche personalizzabili.
17
• Definizione delle regole per calcolare e definire la granularità dei
tempi di validità dei dati storicizzati (punti descritti nella pagina
precedente)
2.1.6 Controllo remoto della strumentazione Il controllo remoto del cambio di stato e dell'attivazione di funzioni di un
strumento, sono una parte fondamentale parallelamente alla funzione di
monitoraggio dei suoi canali. Un sistema di controllo che mira alla
centralizzazione deve poter disporre fondamentalmente di tre requisiti base
nella gestione del controllo remoto, e sono:
• Sicurezza che il comando sia stato recapitato e tracciamento di tale
evento;
• Certezza del risultato del comando o tracciamento dell'errore;
• Possibilità di vincolare l'uso di uno o più strumenti ad una o più
postazioni o utenti.
I primi due sono necessari per la risoluzioni di errori e per debugging
dell'intero sistema, l'ultimo per dare la possibilità ad operatori o ad algoritmi
di controllo di non avere interruzioni o modifiche nel flusso di molteplici
comandi che determinano comportamenti automatizzati dell'hardware. La
possibilità di vincolo deve poter essere specificata per i singoli canali di input
e funzioni dell'hardware, in questo modo nel caso un hardware assolva a
molteplici funzioni, in caso di automatismi di alcune di esse, sarà comunque
possibile controllare manualmente le altre.
Seguendo il filo conduttore dell’alta adattabilità, il sistema di controllo deve
permettere la personalizzazione di tre aspetti fondamentali del sistema RPC:
• Implementazione della serializzazione dei dati;
• Implementazione del protocollo di comunicazione:
• Implementazione della regola di esecuzioni dei comandi.
Il terzo esprime un requisito non immediato ma importantissimo. Dare la
possibilità di definire il modo in cui, alla ricezione di un comando, questo
deve essere eseguito e con quale priorità. All’esecuzione di un comando
server applicare delle regole che devono permettere di specificare se
18
l’esecuzione di un comando è subordinata ad altri. Per esempio una
strumentazione che riceve il set di due attributi in istanti differenti potrebbe
permettere l’esecuzione in parallelo o sequenziale. Questo evidenzia la
necessità di un sistema di macchine a stati finiti (FSM) altamente
configurabile.
2.1.7 Gestione degli eventi (allarmi, soglie, etc.) Introduciamo gli eventi mostrando due esempi. Questi mostrano l'esigenza
che si ha, durante il normale funzionamento di un sistema di controllo, di
avere un sistema ad eventi.
Esempio 1: un algoritmo che deve generare un allarme(valorizzando
opportunamente alcune valori otturando un interruttore hardware) in caso di
superamento di un certa soglia di temperatura di uno tra centinaia di
strumenti; in questo caso andrebbe eseguito un polling sui dati di tutti gli
strumenti.
Esempio 2: dopo l’invio di un comando ad uno strumento, la verifica
dell’effettiva impostazione di un valore di input andrebbe eseguita
controllando con la tecnica del polling11 se questo è stato effettivamente
completato.
Questi due esempi sono sufficienti a rendere l’idea di quanto, nel caso di un
gran numero di strumentazione, poco efficiente (in questa situazione) sia la
tecnica del polling. A volte anche pericolosa perché su grandi numeri, il
ricontrollo dello stesso strumento potrebbe avvenire dopo un certo tempo che,
a seconda delle misure in gioco, potrebbe essere troppo lungo; questo
problema si evidenzia in caso di valori che hanno una certa velocità nel
cambiare. L’idea di “evento” tende quindi a trovare una soluzione a questi
problemi e quindi a diminuire i ritardi nel rilevare valori significativi o
cambiamenti di stato della strumentazione. La generazione di un evento è
realizzabile tramite l'invio di pacchetti che portano informazioni come:
• Tipologia dell'evento;
• Livello di priorità; 11 Verifica ciclica dello stato dei valori.
19
• Identificativo dell'emettitore;
• Dato contestuale all'evento.
Questi sono generati direttamente dalla strumentazione (ovvero dal driver). Le
varie tipologie di eventi sono raggruppabili in 4 differenti macro categorie:
• Instrument Notification, rappresentano tutte quelle notifiche per
eventi riguardanti le strumentazioni controllate: heartbeat, strumento
non disponibile, etc.
• Command Notification, notifiche riguardanti informazioni sui
comandi: comando eseguito, canale di input impostato, etc.
• Alert Notification, notifiche riguardanti eventi di una certa severità:
superamenti di soglie dei canali I/O, eccezioni, etc.
• Altro.
In generale ogni nodo del sistema deve poter emettere o registrarsi per la
ricezione di notifiche di eventi. Una volta ricevute, le priorità di trasmissione
ai successivi livelli software del framework deve essere fatta direttamente da
un layer di re-indirizzamento dell'evento. Ogni pacchetto porta una sua
specifica priorità la quale permette di poter creare una gerarchia di severità
anche tra pacchetti dello stesso tipo. Stessi eventi potrebbero essere generati
da strumenti ognuno dei quali rappresenta una certa criticità e va quindi
gestito più celermente rispetto allo strumento meno critico. Infine ogni
pacchetto può trasportare dei dati che dovranno essere contestuali alla sua
tipologia; in genere non dovranno essere trasportati grandi quantitativi di
informazione, gli eventi dovrebbero avere il solo scopo d'informare un nodo
di un qualcosa a cui porre attenzione. Per completare il quadro informativo
dell'evento andranno usati i dati del monitor o dello storico.
2.1.8 Acquisizione dati su evento Per acquisizione dei dati, nell'ambito degli esperimenti di fisica o ingenerale
quando si parla di dati emessi da eventi particolarmente veloci, si intende
l'acquisizione dei dati su evento o Triggered DAQ. Nel campo dell'elettronica
digitale esistono gli interrupt, che quando si attivano, il codice correntemente
in esecuzione viene sospeso e viene passato il controllo ad una determinata
20
procedura che esegue un determinato lavoro in risposta all'evento che ha
generato l'interrupt stesso; per esempio un dispositivo di I/O genera un
interrupt per avvertire il sistema operativo che ci sono dei dati da leggere, e
questa operazione deve essere fatta il più velocemente possibile. Per triggered
DAQ viene inteso quindi un sistema che provvede al campionamento di
determinate misure solo dopo aver ricevuto un interrupt o trigger generato da
un evento particolare o manuale. Questo si rende necessario perché non tutti i
dati sono "interessanti" dal punto dell'analisi, a volte si ha bisogno di studiare
misure solo nel momento in cui un evento accade. Campionature continue,
oltre che inutili, sarebbero inefficienti visto che in tempi brevi si
raggiungerebbero dimensioni rilevanti e si avrebbero molte difficoltà per
accedere e immagazzinare i dati associati. Aspetto molto importante è dovuto
al fatto che gli eventi potrebbero essere molto veloci e i dati da acquisire
andrebbero campionati da differenti apparecchiature. In questo caso l'avvio
del campionamento deve partire contemporaneamente in tutti i dispositivi, la
propagazione del segnale di trigger deve essere il più veloce possibile. È
evidente quindi che il triggered DAQ è una modalità di acquisizione dati
inevitabile in molte situazioni ed importate per lo studio di eventi veloci.
Solitamente il segnale di trigger viene generato da un rilevatore che riesce
velocemente a riconoscere l'evento interessante e a generare un segnale
trasmesso via cavo agli strumenti di campionamento. Il segnale arriva
contemporaneamente ad ognuno di essi avviando così l'acquisizione dei dati.
L'idea è quella integrare la gestione e il coordinamento del triggered DAQ
all'interno del sistema di controllo. Iniziamo con l'identificare le varie
tipologie di questa funzionalità:
• Trigger inviato manualmente;
• Trigger inviato su evento da studiare.
In entrambe le tipologie quello che occorre è riconoscere i dati acquisiti su un
determinato evento di trigger. Uno strumento di acquisizione dati potrebbe
avviare l'acquisizione su uno o più trigger, è necessario quindi che il dato
acquisito sia associato ovviamente ad un codice identificativo. Questo
affinchè sia possibile risalire al tipo di evento che lo ha generato.
21
2.1.9 Gestione dei Metadati e del LogBook Il metadata server e il LogBook, come descritto nel paragrafo di
centralizzazione, sono strumenti necessari per gestire la condivisione dei
metadati (degli strumenti e degli algoritmi di controllo) e l'annotazione di
eventi (importanti o di manutenzione). L'unificazione di entrambi gli
strumenti in un unico punto permette di avere una completa gestione
informativa dell'intero sistema da controllare; si saranno definiti in modo
relazionale i metadati con annotazioni del medesimo strumento, permettendo
una semplice e veloce panoramica globale sullo stato del singolo strumento.
I metadati di uno strumento comprendono una vasta gamma di informazioni:
• Dataset dei canali di I/O;
• Descrizione funzionale;
• Descrizione e configurazione del modello, produttore, distributore,
etc.;
• Stato dello strumento: offline/online;
• Ultimo failure o alert.
Per quanto riguarda il logbook i normali eventi memorizzati sono:
• Malfunzionamenti di un determinato device;
• Annotazioni su idee o anomalie riscontrate durante il funzionamento;
• Annotazioni automatiche di failure e alert;
• Gestione della correzione di malfunzionamenti;
• Etc.
L'importanza di avere collegato in modo relazionale le informazioni sopra
riportate rappresentano un notevole vantaggio; permette di integrare
direttamente nel sistema di controllo, un sistema di ticketing per la gestione di
fermi e malfunzionamenti di strumenti. Si potrebbe anche implementare un
avvio automatico di procedure di sostituzione di strumenti mal funzionanti,
come anche migliorare la gestione della scorta di ricambi.
Con le informazioni sopra elencate si potranno realizzare report statistici che
possano indicare quale strumentazione sia più soggetta ad usura, migliorando
quindi la scelta dell'approvvigionamento dei ricambi.
22
2.2 Requisito di schema libero L'intero studio dei requisiti è stato notevolmente influenzato dal concetto di
"libertà da strutture fisse". La richiesta di "schema libero" porta un notevole
aumento della complessità dell'architettura a fronte di un estremo guadagno in
termini di flessibilità ed adattabilità ad ogni esigenza. Per realizzare questo
concetto è necessario avere a disposizione un qualche sistema per descrivere
strutture di qualsiasi complessità e deve essere possibile poterlo fare in modo
dinamico.
Nel paradigma usato in !CHAOS una variabile è definita da un insieme di
triplette chiave/tipo/valore (semplicemente K/V). Una o più variabili sono
raggruppate in una struttura di base simile ad una struttura c; la differenza
sostanziale sta nel fatto che la definizione di quali e quante triplette
aggiungere alla struttura avviene dinamicamente, mediante uso di apposite
API12, e non deve essere creata staticamente. Questo permette, a runtime, di
creare strutture che si adattano alle esigenza allo stato attuale del software. Di
seguito un esempio di una struttura composta da tre variabili, in cui la terza è
a sua volta una struttura:
{ “Chiave_1”: (Double) : 56.005 “Chiave_2”: (Integer) : 125 “Chiave_3”: (Struct) : { “Chiave_3.1”: (Integer) :2000 “Chiave_3.1”: (Double) :58.3 } }
Questo modello descrittivo dei dati mette a disposizione una struttura
“variante”; nel framework sarà usata lì, dove la definizione dei dati non potrà
essere determinata a priori. La sua duttilità trova massima espressione
nell’uso della descrizione dei dataset degli strumenti, ognuno dei quali potrà
usarla per definire liberamente i canali di I/O anche alla presenza di strutture
complesse.
Di seguito è descritto come questa duttilità ha necessariamente complicato la
scelta del modo in cui gestire l’archiviazione dei dati. Nel caso del 12 Application Programming Interface
23
monitoraggio la natura dell’uso del dato ha permesso di semplificarne la
gestione, di contro la storicizzazione ha subito una notevole complicazione
proprio per la mancanza di uno schema predeterminato.
Dati di monitoraggio: come detto in precedenza il sistema deve rendere
disponibile sempre l’ultimo dato aggiornato dello strumento nel modo più
veloce possibile. Questo permette di semplificare al massimo la funzione di
ricerca, che si risolve semplicemente trovando un sistema per associare
all’identificativo dello strumento i suoi dati. Si tratta sostanzialmente di una
hashtable distribuita.
Dati di storico: il sistema agisce come contenitore di tutte le valorizzazioni
che il dataset di uno strumento ha subito nel tempo. Diversamente dal sistema
di monitoraggio deve quindi permettere la ricerca delle valorizzazioni del
dataset che rispecchino determinate logiche su valori assunti dai canali di I/O.
Per ogni strumento quindi dovrà gestire le seguenti operazioni:
• “capire” la struttura del dataset;
• Recepire e memorizzare su sistema di storage sicuro il pacchetto dati
inviato dallo strumento;
• Creare e aggiornare opportuni indici definiti sulla struttura del dataset
in grado, per ogni pacchetto, di memorizzarne informazioni utili alla
ricerca è la posizione nel sistema di memorizzazione.
Il concetto di schema libero è stato determinante sin dalle prime fasi di analisi
e di conseguenza è stata la prima cosa affrontata dal punto di vista
dell'ingegneria del software.
24
INGEGNERIA DEL SOFTWARE In questo capitolo sarà affrontato lo studio dell'ingegneria del software che ha
portato alla definizione finale dell'architettura disegnata per !CHAOS. Nei
successivi paragrafi s’illustrerà l’architettura generale del framework risultato
dell’integrazione dei requisiti esposti nel capitolo precedente; di come essi
hanno determinato la scelta architetturale dei vari livelli software. Si
mostreranno inoltre le scelte architetturali e le tecnologie scelte per risolvere i
punti critici del progetto illustrati nei singoli punti successivi.
3.1 Architettura software del sistema Nei capitoli precedenti sono stati discussi dettagliatamente tutti i requisiti,
problemi e necessità che un sistema di controllo deve necessariamente
soddisfare e risolvere. Lo studio architetturale si è focalizzato sulla
realizzazione di un framework per sistemi di controllo e non un prodotto
finale. La sfida è stata quella di trovare un confine entro il quale si potesse
risolvere e soddisfare i requisiti esposti, lasciando massima libertà
all’implementazione e adattabilità alle esigenze date dall'applicazione reale
(scelta degli strumenti da usare, dei sistemi di storage, tempi di archiviazione
etc.). Questo affinché gli sviluppatori siano liberi di pesare a come usare
!CHAOS per realizzare il proprio sistema di controllo, focalizzandosi sul solo
sviluppo dei driver per gli strumenti, sull’interfaccia grafica per gli utenti e
sugli algoritmi di controllo. La scalabilità deve essere una caratteristica
intrinseca del progetto e quindi gestita direttamente dal framework,
garantendo in questo modo un’alta flessibilità sia per la quantità di strumenti
da supportare e sia per la quantità di dati che si dovranno gestire.
25
Figura 3.1: visione generale dell’architettura.
La figura 1 mostra le macro-aree che compongono l’architettura di !CHAOS,
il confine indicato dalla linea tratteggiata evidenzia la separazione tra il
framework che si realizzerà e il codice che l’utente dovrà implementare. È
evidente come, l’intero framework lasci piena possibilità di definire le
implementazioni, concentrandosi sul coordinamento dei vari elementi.
I nodi rappresentati sono (partendo dall’alto in senso orario):
• Le Logiche di Controllo sono algoritmi che leggono dati di alcune
strumentazioni, applicano delle logiche e ne controllano altri;
• Le Interfacce utente sono applicazioni di monitoraggio e di controllo
manuale;
• Servizi Cloud per il Metadata Server (MC13) è il sistema informativo e
gestore dei metadati di tutto il sistema hardware da controllare;
13 MetadatasServer Cloud, servizio di scalabilità per la gestione dei metadati
26
• Servizi Cloud di storage e caching dei dati (DC14) è il gestore per il
caching dei dati live e di tutti i dati che dopo l’acquisizione non
devono essere persi;
• Driver per la strumentazione è software per l’interfacciamento della
strumentazione al sistema di controllo.
Ognuno di questi nodi è interconnesso mediante il layer di comunicazione.
Per network non s’intende necessariamente il protocollo ethernet ma bensì
qualsiasi sistema che permetta di inviare e ricevere informazioni tra hardware.
Tutto quello che segue comunque, prende come riferimento il protocollo
TCP/IP e UDP. L’architettura permette di poter integrare differenti domini del
DC (figura 2). Per domini si intende differenti implementazioni del caching e
dello storico dei dati. Uno o più domini potranno coesistere in un unico setup
di !CHAOS. Questo renderà possibile l’uso di soluzioni economiche e
relativamente performanti dove possibile, permettendo cosi un abbattimento
dei costi dell’intero sistema. La gestione dell’associazione dei vari strumenti
ad uno o all’altro dominio rientrerà nel compito del metadata server (MDS).
Figura 3.2: Differenti domini del data cloud.
L’architettura mostrata evidenzia che tutti i nodi richiedono un insieme di
funzioni comuni ad ognuno di essi come; gestione dei messaggi RPC
(comunicazione nodo-nodo, nodo-MDS o MDS-MDS) e interazione con il DC,
serializzazione dei dati. Basta questo per capire della necessità di strutturare
l’architettura del software partendo da un livello di base.
14 DataCloud, servizio di astrazione e scalabilità per la gestione dei dati.
27
3.1.1 Livello Comune Il livello comune rappresenta la base da cui tutti gli altri livelli, che
specializzeranno i vari nodi, dovranno dipendere. L’insieme completo oltre
alla comunicazione RPC e all’interazione col DC, va trovato seguendo i
requisiti studiati nel secondo capitolo; si arriva quindi ad avere i seguenti
sottosistemi:
• Serializzazione;
• Messaggi RPC;
• Messaggi per eseguire Query al DC;
• Eventi.
3.1.1.1 Serializzazione
La serializzazione e una delle parti più importanti in ogni software distribuito,
nei sistemi di controllo poi necessità di ulteriore qualità; deve essere
soprattutto veloce sia nella codifica che nella decodifica. A questo si
aggiunge, dai requisiti, la possibilità di gestire i dati con il paradigma
chiave/valore. Seguendo la logica dell’astrazione e dell’alta adattabilità a
sviluppi futuri, la serializzazione si basa su una semplice architettura
composta da una classe che permette di eseguire le associazioni chiave/valore
codificandole per mezzo di un apposito driver.
Figure 3.3 Architettura di serializzazione.
Questo permetterà di poter modificare il protocollo di codifica e decodifica
serializzazione secondo le necessità15.
15 In una installazione del framework può essere usato un solo protocollo alla volta.
28
3.1.1.2 Sistema RPC
Questo sottosistema implementa completamente la gestione di messaggi RPC
tra nodi di !CHAOS. Questi sono divisi in due categorie, semplici (messaggi)
o richieste. Sostanzialmente la differenza tra messaggio e richiesta sta nel
fatto che il nodo emettitore rimane in attesa della risposta. In questo caso il
nodo ricettore, terminata l’elaborazione, invia una risposta con l’esito
dell’esecuzione. La figura seguente ne schematizza il flusso:
Figure 3.3 Invio di messaggi e risposte.
La reale destinazione di un messaggio (richiesta) o di una risposta è un’azione
pubblicata dal nodo, il quale sostanzialmente rappresenta un gruppo di azioni.
La sua identificazione e data dalla concatenazione di due indirizzi e un aliasi:
1. Indirizzamento definito dal tipo di network usato (nel caso del TCP/IP
corrisponde a Indirizzo IP:porta);
2. Indirizzamento interno al framework;
3. Alias dell’azione.
Esempio indirizzamento messaggio; ip:porta:3b95d9b5:alias_azione.
L’invio di un messaggio è un’operazione sincrona che termina con la
ricezione del risultato di sottomissione del pacchetto inviato (come mostrato
in figura 3.3). Questa è una caratteristica essenziale in un sistema di controllo,
in quanto per ragioni di sicurezza, si deve avere sempre la verifica che un
messaggio è stato consegnato alla destinazione. Il tempo di esecuzione non è
determinabile a priori, dipende sostanzialmente dal tipo di operazione
richiesta dal messaggio; per questo motivo quindi sarebbe inaccettabile che
una richiesta attendesse in modo sincrono la sua risposta.
29
Introduciamo ora la struttura del pacchetto trasmesso da sistema RPC. Un
normale messaggio e una richiesta sono sostanzialmente simili; la richiesta
porta con se informazioni utili per poter spedire, al termine dell’operazione, il
risultato dell’operazione al nodo che ne attende la risposta16. I pacchetti sono
strutturati usando il paradigma del chiave/valore. Un normale messaggio è
definito nel modo seguente:
“NODE_DEST”: “3b95d9b5”
“ACT_ALIAS_DST”: “alias”
“ACT_MSG”: message Figura 3.4 Struttura di un messaggio
Il pacchetto è inviato all’indirizzo, con la logica del network di trasmissione,
dove è raggiungibile il nodo di destinazione. Una volta decodificato, le
informazioni contenute nella sua struttura sono utilizzate per trasmetterne il
contenuto alla destinazione (nodo/azione). La struttura complessiva del
messaggio è la seguente (figura 3.4):
• Indirizzo del Nodo per istanza del framework;
• Alias dell’azione;
• Messaggio17.
“ANSW_ID”: 1..2^32
“ANSW_NODE”: “3b95d9b5”
“ANSW_ACT” “alias”
“ANSW_IP”: ip:port Figura 3.5 Struttura aggiuntiva per la richiesta
16 Non necessariamente il nodo destinatario della risposta deve corrispondere al nodo che ha
generato la richiesta. 17 Il messaggio è codificato secondo il paradigma chiave/valore.
30
Il pacchetto per la richiesta è simile al messaggio necessitando però di
ulteriori informazioni che saranno utilizzate per l’inoltro della risposta. Di
seguito la sua struttura (figura 3.5):
• Id della risposta;
• Indirizzo del network di trasmissione;
• Indirizzo del Nodo di destinazione, per istanza del framework;
• Alias dell’azione per la ricezione del messaggio di risposta.
Gli indirizzi del network e del framework si riferiscono al nodo che attende la
risposta. La gestione dell’associazione richiesta/risposta è possibile grazie
all’uso di un identificato. Questo deve essere sempre presente nel messaggio
di risposta solo cosi, alla sua ricezione, il nodo richiedente potrà riassociare il
risultato alla richiesta precedentemente sottomessa. Questa modalità permette
inoltre l’invio di più richieste contemporaneamente; difatti le risposte possono
arrivare anche in tempi differenti e il nodo ricevente, grazie appunto all’id
presente nel pacchetto di risposta, sarà sempre in grado di associare ognuna di
esse alle richieste in attesa.
3.1.1.3 Messaggi per eseguire Query al DC
Il DC è una parte molto importante del framework. Esso astrae la cloud per la
gestione dei dati. I dati gestiti dal framework sono di due tipi:
• Dati live
• Dati di storico
L’architettura della Cloud sarà discussa egli ultimi capitoli dettagliata mente,
per ora possiamo pensare a un contenitore di dati accessibile tramite dei
server. L’idea è quella di creare un semplice protocollo che permetta di poter
interrogare ed inserire dati nel DC. Per rimanere conformi alla logica astratta
ed estendibile de framework si è pensato di usare il paradigma chiave/valore,
utilizzando quindi il layer di serializzazione standard senza crearne di nuovi.
In pratica, questo “linguaggio” non è altro che un insieme di elementi
chiave/valore che definisce semanticamente delle operazioni sui dati. Questo
permette inoltre di non precludere l’estensione di tale linguaggio a chi poi ne
realizzerà il sistema di controllo o per funzioni di sistema future. Le
caratteristiche di questo semplice linguaggio devono essere le seguenti:
31
• Inserimento del dato, sia nel live che nello storico
• Interrogazione sui dati storici
• Creazione degli indici
• Impostazione delle regole di ageing18 sui dati
La sua trattazione dettagliata sarà discussa nel capitolo della gestione dei dati.
3.1.1.4 Eventi
Il sistema di eventi di CHAOS rappresenta a tutte gli effetti anche un sistema
di “notifiche”. Il sistema di network che collega i nodi deve permettere la
modalità di invio e ricezione dei pacchetti sia multicast che broadcast; questo
permette l’invio di un singolo pacchetto ad uno o più destinatari. Molti sono
gli usi che in un sistema di controllo possono essere assolti da un sistema di
notifiche, tra i più importati si evidenziano:
• Sincronizzazione di processi asincroni nei nodi;
• Operazioni di check dei vari nodi;
• Notifiche per informare i nodi per l’offline di un altro nodo;
• Etc.
L’idea è di creare un piccolo protocollo binario leggero e veloce in modo da
poter essere il più performante possibile, alfine di poter scambiare
informazioni di uso generale tra i nodi che desiderano riceverle. In
quest’ottica sono stati tradotti i requisiti studiati nel paragrafo 2.1.7, nella
seguente struttura di dati:
Figura 3.6 Pacchetto dati di un evento
18 Regolamentazione della memorizzazione dei dati nel passere del tempo
32
Il protocollo usa il formato little-endian per la scrittura delle parole a multi
byte. Al posto del TCP/IP usato per i messaggi, gli eventi sono implementati
in UDP per permettere il broadcast e multicast. Per ottenere la maggior
performance possibile, non viene implementato nessun protocollo che
gestisca la deframmentazione dei pacchetti, sarà necessario quindi che la rete
che connette i nodi, sia configurata in modo da non causarne la
deframmentazione al di sotto di 1052 byte (header ip + header udp +
pacchetto eventi).
0 Header IP 20 Porta sorgente Porta destinazione 24 Lunghezza Checksum (optional)
28+
Figura 3.6 Descrizione pacchetto UDP degli eventi
La figura 3.6 mostra il pacchetto UDP completo comprendente, nel campo
dati, il sotto pacchetto di eventi di CHAOS.
Il pacchetto degli eventi è quindi compost da 4 campi:
• Header
• Type
• Priority
• Event data
L’header permette di determinate il tipo di contenuto e la lunghezza totale del
pacchetto, più un campo di 8 bit riservato per usi futuri. La descrizione del
tipo potrebbe sembrare superflua, mentre se si pensa alla possibilità che
sviluppi futuri del framework potrebbero integrare altri tipi di pacchetti
broadcast/multicast, la sua utilità è evidente.
Header Pacchetto Eventi 0-32 (bit) ‘CE’ Versione(3bit) Lunghezza(13bit)
Tabella 3.7 Descrizione header.
33
L’header è composto da tre campi:
• Identificativo ‘CE’, sta per “Chaos Event”, serve inoltre a determinare
che la serializzazione sia in little-endian;
• Il numero di versione, formato da tre bit;
• La dimensione dell’intero pacchetto (compreso l’header stesso) con
l’uso dei rimanenti 13 bit.
La dimensione totale del pacchetto è di 8192 bit (1024*8), con 13 bit si
rappresentano i numeri da 0 a 8191. In considerazione del fatto che i campi da
spedire (per costruzione) obbligatori sono Header, Type e Priority, lo 0 non ha
senso di essere considerato, il framework quindi con 13 bit mapperà l’intera
lunghezza del pacchetto di eventi.
Tipo E Priorità 32-40 (bit) tipo (2bit) priorità (6bit)
Tabella 3.8 Descrizione pacchetto degli eventi.
Il tipo, riprendendo l’analisi fatta nel paragrafo 2.1.7, deve rappresentare uno
di queste tipologie di notifiche, che possono essere descritte da due bit:
• Alert Notification (AN-00);
• Instrument Notification (IN-01);
• Command Notification (CN-10).
Associato a ogni tipologia d’evento c’è una priorità intrinseca del tipo stesso.
La priorità diminuisce19 con l’aumentare del valore del tipo; esempio gli
eventi sono a più alta priorità rispetto agli altri. Il framework gestisce la
priorità all’arrivo del pacchetto inoltrandolo prima rispetto a pacchetti di
tipologie a priorità più bassa.
Il campo Priorità, definisce la priorità rispetto a pacchetti di eguale tipologia.
Per esempio l’allarme di uno strumento può avere maggiore priorità rispetto
ad un altro strumento. La sua dimensione è di 6 bit, permettendo quindi di
definire 64 livelli di priorità all’interno della stessa tipologia. E’ opportuno
che questo valore sia configurato a livello di strumentazione o nodo dal
metadata server.
Infine il campo Evet Data porta l’informazione contestuale all’evento. La sua 19 Il tipo per i bit 00 ha priorità maggiore rispetto al tipo 01 e cosi via.
34
dimensione massima deve essere tale che non si superino in totale i 1019 byte,
ossia la dimensione massima dell’evento 1024 byte – i 5 byte dell’header più
le informazioni di tipo e priorità.
Per ognuna delle quattro tipologie di eventi la struttura del dato è la medesima
ed è raffigurata nella figura 3.9
Dato per evento tipo Alert 40-8192
(bit) informazioni (5+[0-255])
tipo_valore (1 byte)
valore (718 Min – 1013 max)
byte Figura 3.9 Struttura del dato generale.
Come si vede, la parte dei dati è divisa ulteriormente in 3 parti:
• Informazioni (figura 3.10) che servono a descrivere il tipo di sotto
codice dell’evento e la sua priorità e l’identificazione di chi ha
emesso l’evento;
• Il campo “Tipo Valore” della dimensione di un byte rappresenta il
tipo di valore contenuto nei successivi 1014 byte e è cosi definito:
Int8, Int32, Int64, Double, CString, Binary;
• Il campo valore contiene, a seconda del tipo la valorizzazione del
messaggio portato dall’evento.
Informazioni del dato codice (2 byte)
priorità (2 byte)
dim. identificativo (1 byte)
identificativo (255 byte max)
Figura 3.10 Struttura dei campi di informazione del dato.
La figura 3.10 mostra come e’ diviso il campo delle informazioni di un
evento. Esso contiene il codice che definisce il sottotipo di evento. Ad
esempio per gli alert ci saranno censiti sottocodici che meglio descriveranno
che tipo di alert si è verificato. Ad esempio saranno censiti i superamenti di
soglia dei canali in output di uno strumento oppure altre tipologie . La priorità
permette di personalizzare ulteriormente la priorità all’interno dei tipi. Infine
il campo ‘dim. identificativo’ descrive la dimensione dell’identificativo di chi
ha emesso l’evento. Questa puo’ variare da 0 a 255, ciò pone un tetto limite
agli identificativi usabili dagli strumenti.
Di seguito vengono meglio dettagliate le varie categorie di eventi.
35
Le notifiche di tipo AN portano informazioni di allerta. Sono generate in tutte
quelle situazioni in cui ci sono dei superamenti soglie di valori o sono
generati da algoritmi di controllo che devono, secondo le situazioni, inviare
codici che identificano le allerte e i valori per determinarne la quantità.
Definire codici e valori a priorità, data l’alta astrazione, non è possibile ogni
sistema di controllo potrà definire le sue.
Le notifiche di tipo “IN” portano invece informazioni riguardanti gli
strumenti. Esse sono generate dai driver che adattano la strumentazione al
framework (discusse nel capitolo successivo). Alcuni sotto codici sono stati
definiti a priori perché usate dal framework e sono; Offline, Online, Heartbeat
e di SetAttribute
L’evento di codice Offline, è inviato da un qualsiasi nodo quando scopre che
uno strumento non risponde, il campo dell’identificativo è la chiave univoca
dello strumento che è in offline. Il codice di Online invece è inviato dallo
strumento stesso, al momento ritorna che attivo. L’Heartbeat, come il
precedente è inviato ad intervalli regolari direttamente dallo strumento.
L’evento di SetAttribute, è inviato al termine dell’impostazione di un attributo
successivamente all’arrivo di un comando RPC che dispone l’impostazione.
Le notifiche di tipo CN (Command Notification) dovranno essere censite e
serviranno a descrivere informazioni riguardanti il coordinamento tra i vari
nodi del framework.
L’ultimo spazio a disposizione, quello a più bassa priorità, serve per poter
creare eventi totalmente personalizzati in cui la struttura (sempre di
dimensione massima di 1024 byte) è stabilita dagli implementatori.
3.1.2 Instruments Drivers Prima di procedere nella descrizione dei driver degli strumenti sono
necessarie fare alcune premesse. Lo scopo di CHAOS è di controllare e
monitorare strumentazione hardware. E’ evidente quindi che in situazioni
complesse si avranno sicuramente molti strumenti appartenenti alla stessa
classe; Per esempio ci possono essere differenti alimentatori della stessa
marca in molteplici zone. I driver quindi si riferiscono alla “classe” dello
36
strumento e non alla singola installazione; allo stesso tempo però devono
permettere anche di identificare quale dei tanti strumenti essi controllano.
Figura 3.12 Rappresentazione stilizzata di più strumenti della stesa classe.
La figura 3.9 mostra il concetto sopra esposto. Di seguito sarà introdotto il
dataset e come esso è definito all’interno di CHAOS, esso è da intendersi
come la descrizione della classe di strumenti e non del singolo. Per
identificare lo strumento singolo viene introdotto il concetto di
“DEVICE_ID” chiave univoca che sta proprio a rappresentare il singolo
strumento in una determinata posizione nell’installazione.
Come anticipato la struttura del dataset è il modo con il quale in CHAOS è
stata risolta l’astrazione e l’adattabilità di uno strumento al framework. Sin
dall’inizio, il punto centrale di tutto il progetto è stato quello di non vincolarsi
a nessuna struttura predefinita per descriverne i canali di I/O. Il dataset quindi
rappresenta un insieme di attributi, che descrivono i canali di I/O e le
caratteristiche funzionali e operative (tipo frequenza di acquisizione dati,
operazioni da invocare etc.) di uno strumento. Ogni attributo descrive un
singolo canale (reale o virtuale) di I/O, le cui proprietà sono:
• Nome;
• Descrizione;
• Tipo (int32, int64, double, etc.);
• Cardinalità(singolo / array);
• Direzione(Input, Output, Bidirezionale);
• Range di valori ammissibili (massimo, minimo o puntuale);
• Ulteriori definibili dal programmatore.
37
L’idea è quindi quella di permettere allo strumento di comunicare esso stesso,
mediante il driver, le caratteristiche di I/O a tutti gli altri nodi. A tale scopo è
usato anche in questo caso il paradigma chiave/valore. L’associazione di una
determinata chiave alle proprietà di un attributo e all’insieme degli attributi di
uno strumento, permette di descriverne perfettamente la struttura. Un attributo
può a sua volta essere di tipo strutturato, permettendo cosi definizioni
complesse sulla struttura dei canali di I/O.
"device_id" : "SIMULATED_DEVICE_ID" , "dataset" :
[ { "name" : "intValue_1",
"description" :"descrizione valore 1", "direction" : 1, "type" : 0,
“cardinality”: 1}, …
{ "name" : "intValue_2", "description" :"descrizione valore 2", "direction" : 1 "type" : 0,
"cardinality": 1}
]
Schema 3.1 Struttura chiave/valore della descrizione del Dataset.
Lo schema 3.1 mostra l’idea che sta alla base della descrizione del dataset,
nell’esempio la struttura ha solo due livelli, ma riesce a far comprendere ogni
strumento avrà piena liberta di espressione nel descrivere i propri canali. Di
seguito la descrizione delle chiavi:
• device_id, specifica quale dei tanti strumenti di una classe viene
gestito dall’istanza del driver. Lo sviluppatore deve quindi trovare un
modo per poter identificare quale strumento si trova a controllare e
codificarlo nel dataset;
• dataset, è una sequenza di oggetti ognuno dei quali descrivono un
attributo del dataset;
• name, definisce il nome del canale di I/O, va paragonato come il
nome di una variabile.
38
• description, fornisce la descrizione dell’attributo, in un formato
comprensibile;
• direction, indica la direzione rispetto allo strumento di tale attributo.
Possono aversi tre differenti casi:
o Output, definisce un canale di ouptut dallo strumento verso il
sistema, in questa modalità sono censiti i canali da monitorare
o su cui si deve eseguire un campionamento per controllarne
altri;
o Input, definisce un canale in ingresso verso lo strumento,
questi sono usati per impostare dei valori dello strumento. In
un alimentatore, i canali di tipo input sono quelli per impostare
ad esempio il voltaggio di lavoro.
o Bidirectional, sono canali che hanno sia il comportamento di
Input che il comportamento di Output.
• type, definisce il tipo di un canale elencato dai seguenti tipi:
TYPE_INT32(0),TYPE_INT64(1),TYPE_DOUBLE(3),TYPE_STR
ING(4),TYPE_BYTEARRAY(5),TYPE_STRUCT(6). Mentre i
primi sono esplicativi, l’ultimo rappresenta un tipo formato da una
struttura definita dai tipi precedenti. Il tipo TYPE_BYTEARRAY è
discusso separatamente più avanti;
• cardinality, rappresenta quanti elementi dello stesso tipo sono
presenti. È usato per creare array di elementi, nel caso il suo valore si
a maggiore di uno.
A questo punto è evidente come il dataset sia una semplice e leggibile
struttura che ci permette di capire le caratteristiche dello strumento. A tutta
questa leggibilità manca però la descrizione completa del tipo binario. Esso,
data la sua natura, rappresenta solo un insieme di byte, serve quindi un modo
per poter capire cosa è definito al suo interno. Nella figura successiva è
mostrata la descrizione estesa di un tipo binario:
"device_id" : "SIMULATED_DEVICE_ID" , "subtype": [{"id":1,
"dataset":[ { "type" : 0,
39
"cardinality " : 1}] "dataset" :
[…. { "name" : "binaryValue_1", "description " :"descrizione attributo binario 1", "direction" : 1 " type" : 5,
"cardinality": 1, "subtype":1}, ….]
Schema 3.2 Struttura per la definizione completa di un attributo di tipo binario del dataset.
Lo schema 3.2 mostra le chiavi che devono essere aggiunte per la descrizione
completa del tipo binario. Innanzi tutto va definito un sottotipo con la chiave
“subtype”, il cui contenuto è un vettore di sottotipi. Ogni sottotipo è descritto
da due chiavi una per l’id che lo identifica e l’altra per definire la sua
struttura. Nello schema è definito un sottotipo di id uguale ad “1”, composto
da un solo elemento di tipo int32. La cardinalità in questa situazione esprime
quanti elementi di tipo int32 è composta ogni singola struttura. Le chiavi
"type" e "cardinality" sono le stesse usate nel dataset. Definito il sottotipo si
può quindi descrivere il tipo binario aggiungendo la chiave "subtype":1 come
nello schema d’esempio. In questo contesto la cardinalità ci dice quanti
elementi del sottotipo ci sono nel byte array. Se si volesse creare un tipo
binario di due elementi in cui ogni elemento fosse formato da due int32 e da
un double la descrizione del sottotipo sarebbe la seguente:
"subtype": [{"id":1,
"dataset":[ { "type" : 0, "cardinality " : 2}, { "type" : 3, "cardinality " : 1},] Schema 3.3 estratto dello schema per la descrizione del sottotipo con due int32 e un double
Grazie al paradigma chiave/valore la struttura sin qui descritta permette di
aggiungere nuove chiavi, quest’ulteriore opportunità verrà descritta più
avanti.
40
3.2 Tecnologie In questo paragrafo saranno discusse le tecnologie studiate per realizzare le
parti critiche in precedenza discusse. La serializzazione chiave/valore è alla
base di ogni altro livello software, data la sua importanza, è stata soggetta a
uno studio molto approfondito.
3.2.1 Serializzazione In !CHAOS il paradigma chiave/valore è largamente usato, nel sistema RPC e
in tutte quelle situazioni in cui necessita una struttura variabile. La
serializzazione quindi è stata quindi la prima parte che ha portato uno studio
approfondito delle tecnologie attuali. Si è convenuto astrarre ulteriormente il
concetto della serializzazione de dati in modo da non legare il framework a un
determinato formato. La serializzazione dei data è stata quindi inglobata in
una classe CPP che offre tutte le funzioni necessarie per leggere e scrivere
strutture dinamiche di dati (verrà illustrata nel paragrafo 3.4) Sono stati
studiati quindi i seguenti formati:
• Thrift [1];
• Avro [2];
• Protobuf [3];
• Bson [4];
• Msgpack [5].
I primi due software oltre alla serializzazione hanno un’implicita gestione dei
messaggi. Gli ultimi tre si occupano invece solo di codificare informazioni.
Tutti i formati garantiscono la compatibilità, con opportune librerie, in una
larga varietà di linguaggi. Per com’è stato progettato il sistema RPC di
!CHAOS (il quale permette di esportare dinamicamente metodi di classi CPP)
l’uso dei primi due formati, dopo un periodo di sperimentazione, è stato
scartato. Ciò è stato dovuto al fatto che in realtà il loro sistema di
serializzazione non è né flessibile né tantomeno dinamico. Ognuno dei due
formati prevede la scrittura di un file IDL20, in cui sono descritti sia i dati sia
20 interface definition language.
41
le funzioni RPC. È evidente quindi che questi due formati non sono utili
all’uso in !CHAOS. Di seguito tratteremo separatamente i formati rimanenti:
AVRO permette di creare dinamicamente un file IDL in memoria e di
trasmetterlo nella serializzazione in formato JSON-like, questo permette al
ricevente di deserializzare correttamente il dato mantenendo la struttura
originaria. La descrizione del formato non necessariamente deve essere
passata ogni volta e quindi può essere anche creata dinamicamente, condivisa
e poi usata per serializzare e deserializzare i dati. Questo fa di AVRO un
ottimo candidato per CHAOS.
BSON è l’acronimo di Binary JSON questo formato quindi è una codifica
binaria di un documento simile al formato JSON. E’ un formato che nasce
come documento chiave/valore, in cui il valore può essere a sua volta un altro
nuovo documento. Non richiede la creazione di un file IDL ma per contro
bisogna conoscere a priori come è organizzata la struttura codificata. A favore
invece offre una notevole velocità di serializzazione e deserializzazione.
Questo grazie al disegno del formato che insieme ai dati vengono
memorizzati anche le chiavi, il tipo e il valore dell’elemento. Non richiede di
una struttura di appoggio in quanto la scrittura e lettura durante l’uso delle
API viene fatta direttamente in memoria nel formato della serializzazione.
Msgpack è un formato molto compatto di serializzazione binaria e mira ad
ottimizzare lo spazio necessario per memorizzare dati. Per esempio due int32
secondo il loro valore avranno bisogno di differenti quantità di bit per essere
codificati. Non è strettamente un formato chiave/valore come BSON ma un
suo uso come chiave valore è sempre possibile.
Dopo molte valutazioni è stato scelto il Bson ma Avro e Msgpack sono i
principali candidati per successive evoluzioni. È proprio a questo scopo che,
l’astrazione per la gestione dei dati è stata introdotta in CHAOS. Altro fattore
che ha determinato la scelta di BSON è che la momento della scelta era
l’unico protocollo usato in software di produzione come MongoDB (10Gen
MongoDB).
Nei sistemi di controllo è comodo avere il pacchetto dei dati memorizzato
nella live cache e nel database di storico con dimensione omogenea al tipo di
42
dato. Ossia, se deve essere codificato un intero a quattro byte questo dovrebbe
occupare sempre quattro byte sia che il suo valore sia zero o sia molto
maggiore di zero. Ciò permette di poter predisporre ottimizzazioni future in
grado di aggiornare i dati trasmettendo il solo valore modificato e non tutto il
pacchetto. Con serializzazioni ottimizzate come Msgpack, questa cosa non è
possibile. La dimensione di codifica dipende sia dal tipo e sia del valore. La
modifica dei soli dati modificati comporterebbe quindi una corruzione
dell’intero pacchetto.
La necessità di mantenere l’uso del paradigma chiave/valore trasparente dal
tipo di serializzazione, renderà il framework sempre adattabile a nuovi sistemi
e logiche atte a migliorarne le performance.
3.2.2 Sistema RPC Il sistema di RPC, come si vedrà nei paragrafi successivi, è stato sviluppato
partendo da due classi astratte in CPP. Entrambi definiscono un’astrazione sia
per la parte client sia per quella server, le cui attuali implementazioni sono
state fatte usando il protocollo Msgpack-RPC [6]. Questo protocollo si basa
su un buon sistema di parallelismo consentendo l’invio simultaneo di più
richieste sulla stessa connessione. Tale caratteristica permette di avere un
notevole guadagno in termini di performance, per lo scambio di messaggi tra
nodi. Il lato negativo è lo strettamente legame alla serializzazione Msgpack.
Nell’attuale implementazione del sistema RPC di !CHAOS, la serializzazione
BSON è codificata direttamente nel tipo binario di Msgpack. Ovviamente ciò
porta un inutile doppio passaggio di serializzazioni. Tale soluzione risulta
comunque molto performante rispetto ad altre soluzione trovate, per il
momento quindi, vista l’alta adattabilità del framework, si è comunque
proceduto all’uso di Msgpack-RPC, rimandando in futuro migliori
ottimizzazioni.
3.2.3 Sistema di cache dei dati in tempo reale Per la gestione della distribuzione dei dati live, come mostrato nel successivo
paragrafo, il disegno architetturale prevede una centralizzazione del
campionamento dei canali di Output, Input e degli Allert della
43
strumentazione. Una topologia cosi definita necessita ovviamente di un
software che possa essere visto come una cache. Uno tra i migliori software,
idoneo a questo scopo, è Memcached [7] sviluppato originariamente per il sito
social Live Journal21 e in messo sotto Open Source da qualche tempo. Il suo
utilizzo e molto semplice: permette di impostare, data una chiave, un buffer di
desiderate dimensioni o di recuperare tale buffer data la chiave. Il paradigma
adottato e molto simile all’uso della memoria di un computer dove le chiavi
sono una similitudine del puntatore a memoria.
3.3 Soluzioni a problematiche architetturali La problematica maggiore in un sistema di controllo è di garantire un accesso
veloce ai valori dei vari canali della strumentazione e cercare di non avere
interruzioni di letture. Per ultimo ma non meno importante è il file-over e il
bilanciamento dei carichi tra i vari nodi. Ricapitolando
• Minimizzare il carico sul software di adattamento dello strumento al
framework;
• Consentire l’accesso ai dati a più client possibili.
• Fail-over e bilanciamento del carico per la lettura dei dati live e dello
storico.
Mentre i primi due punti sono trattati nei capitoli successivi, in quanto
dipendono dall’architettura, in questo paragrafo tratteremo il metodo usato per
risolvere il problema del file-over e del bilanciamento dei carichi verso i nodi
in !CHAOS. La soluzione trovata lavora a livello d’indirizzamento dei
messaggi e quindi sarà applicabile nell’invio e nelle letture del dato live e di
storico come nella comunicazione con il metadata server.
Ricordiamo i concetti di fail-over e bilanciamento del carico:
• Fail-over, è quella tecnica che permette, a seconda del contesto, di poter
resistere alla non accessibilità di uno o più server, usando quelli
ancora disponibili;
• Bilanciamento, è il modo in cui si ottimizza la distribuzione dei dati nei
server, in modo che nessun di essi sia più o meno usato degli altri. 21 http://www.livejournal.com/
44
La soluzione adottata in !CHAOS è simile al modo in cui lavorano i client di
Memcached. Il server non ha conoscenza di altri server e il fail-over con il
bilanciamento sono interamente gestiti dai client; ogni di essi deve avere la
lista completa dei server, e data una chiave (stringa) con un algoritmo ne
viene calcolata la destinazione (ip:porta del server). In questo modo tutti i
client (sia che leggano o scrivano) useranno lo stesso server per una
determinata chiave. Questa soluzione permette inoltre di scaricare i server
dagli oneri di duplicazione dei dati su di altri.
In CHAOS si è deciso di usare una soluzione simile ma opportunamente
ampliata per le nuove esigenze. Il bilanciamento è calcolato su differenti
parametri. Consideriamo di aver “N” server a disposizione ed “M” client; Per
ognuno dei client vengono presi in considerazione due parametri essenziali ai
fini del bilanciamento:
• Dimensione media del pacchetto dei dati;
• Frequenza media di aggiornamento dei dati.
Alla stessa maniera anche i server sono considerati con il solo unico
parametro che è la larghezza di banda che riescono ad gestire. Un algoritmo
poi, prende in input tutte queste informazioni e per ogni device genera una
lista di server, [Device(attributi), Server(attributi)] = [Device, (Lista Server)].
L’uso del server dipende dalla priorità che è posizionale alla lista stessa. Ogni
volta che si ha una modifica nella quantità di server e di client, l’algoritmo
viene rieseguito e le nuove liste vengono inviate di nuovo ai rispettivi layers
software che gestiscono i client. Dal punto di vista del client (lettura e
scrittura) si usa sempre il primo server attivo disponibile nella lista in ordine
di priorità (dal primo all’ultimo).
45
Figure 3.13 Rappresentazione del cambio di server dopo la disconnessione del server P1.
I client eseguono un cambio del server solo in due situazioni:
Fail-over del server corrente (figura 3.13); durante le operazioni il server
non è più raggiungibile, viene quindi selezionato il successivo server
disponibile;
Switching coordinato dal metadata server; dopo la riattivazione di un
server in precedenza fuori uso, o dopo l’aggiunta di nuovi server o client, il
metadata server può decidere di coordinare lo spostamento di un device su
server differente da quello in uso; questo, per bilanciare nuovamente i carichi.
Questa operazione è eseguita in tre fasi:
• Fase uno: il metadata server avverte i layers software del devie da
spostare e di tutti i client che leggono i suoi dati, di usare il nuovo
server indicato;
• Fase due: il metadata server attende che tutti i client rispondano con la
corretta ricezione del dato che ne indica la disponibilità al cambio;
• Fase tre: il metadata server invia a tutti il timestamp, dopo il quale il
nuovo server deve essere usato.
In caso di failover del server la procedura è più semplice, in quanto tutti i
client hanno la lista di server e il time-out della connessione viene usata come
trigger per lo spostamento al successivo elemento.
46
3.4 Architettura Implementativa In questo paragrafo sarà presentata l’architettura implementativa dell’intero
framework. Ne saranno descritti i principali layers e le scelte attuate per la
realizzazione di ognuno di essi. La progettazione è stata di tipo top-down. Si
sono dapprima suddivisi logicamente i layers e studiate le dipendenze. L’idea
è stata quella di dividere il framework in differenti librerie, ognuna delle quali
rappresenta uno specifico livello di software. La figura 3.14 schematizza le
dipendenze delle varie librerie. Ognuna di esse è realizzata in c++, questo ha
permesso di definire astrazioni, regole e semplificazioni in modo da fornire
all’utente implementatore, un modo semplice e sicuro per implementare
attuatori e controlli.
Figure 3.14 Suddivisione dei vari layers software e dipendenze.
Il Common Layer, riunisce tutti i sotto livelli software e quindi implementa
tutte le soluzioni sin qui descritte; serializzazione, comunicazioni network,
fail-over, bilanciamento e gli eventi. Sostanzialmente rappresenta un “kernel”
che da supporto ai successivi tre livelli.
Il CUToolkit Layer riunisce tutti livelli software che permettono di realizzare
il driver di adattamento dello strumento a !CHAOS. Dipende strettamente dal
livello Common.
L’UIToolkit Layer è una collezione di livelli classi che semplificano la
creazione di Interfacce utente. Il livello è stato pensato per risolvere le
problematiche comuni a tutti i programmi di visualizzazione di canali di I/O
della strumentazione quali; visualizzazione di grafici per i canali di I/O.
47
Correlazione tra vari strumenti ed analisi comparative tra differenti
strumentazione. Gestione degli allarmi, etc.
L’EUToolkit Layer è una collezione di livelli software che permette
l’implementazione di algoritmi di controllo, che lavora su classi di strumenti e
di canali di I/O. L’idea è quella di semplificare il più possibile il lavoro di chi
fa algoritmi di controllo, non legandolo al singolo strumento ma ad una classe
di strumenti.
Il common layer, come già detto, contiene tutti i livelli software che
permettono di astrarre, ai livelli superiori, l’implementazione dei sistemi di
comunicazione tra nodi e la serializzazione. In questo layer viene anche
definita la classe ChaosCommon, una classe template, che per disegno, sarà la
superclasse di tutte le classi principali degli altri layer.
Figure 3.15 Dipendenze delle principale classi dei toolkit.
Il common layer offre i soli sottosistemi sopra citati, i sotto layers invece
sono progettati per astrarre ulteriormente !CHAOS semplificando ai
programmatori l’implementazione di driver, UI e algoritmi di controllo.
Ognuno di essi contiene una classe che fa da “Manager” del layers stesso;
questa estende la classe ChaosCommon (che rappresenta un singleton) e
prende il nome del layer d’appartenenza. La figura 3.15 mostra le tre classi
manager the tre layers descritti sopra. Ogni manager implementa due metodi
principali:
48
• Init, ogni layer inizializza i sottosistemi di pertinenza, nel casi si
verifichino errori viene lanciata un’eccezione con una successiva
terminazione del processo;
• Deinit, ogni layer deinizializza e rilascia tutte le risorse usate dai
sottosistemi.
3.4.1 Architettura del sotto sistema RPC (Common Layer)
Figure 3.16 Architettura del sistema di RPC.
Il sotto sistema di RPC si basa sull’astrazione delle parti server e client, e su
due classi astratte che rappresentano il gestore dei messaggi RPC ricevuti
(MessageHanlder, MH) e inviati (MessageForwarder, MF). Questo permette
di poter di mascherare interamente l’implementazione. Il compito del
sottosistema è quello di inoltrare ad un altro nodo la serializzazione del
CDataWrapper e di ricevere i messaggi per inoltrarli subito all’MH. Le classi
astratte AbstractRPCServer (ARS) e AbstractRPCClient (ARC), estendono la
classe DriverManagmentInterface (DMI) che regola le operazioni
d’inizializzazione e deinizializzazione, allo stesso tempo rappresentano le basi
delle implementazioni. L’indirizzo di destinazione e gestito dalla classe
NetworkAddress (NA). Le implementazioni possono decidere di realizzare i
49
due driver in modalità multi o single thread. Le attuali implementazioni del
sistema RPC usano il protocolo MsgPackRPC, descritto nel paragrafo 3.2.2.
3.4.2 Architettura del sotto sistema degli Eventi (Common Layer)
Figure 3.17 Architettura del sotto sistema ad aventi.
Il sottosistema di eventi, come quello RPC, si basa sull’astrazione dei driver.
Anche in questo caso il gestore della ricezione (EventHandler, EH) e
dell’invio (EventForwarder, EF) degli eventi, aumentano la separazione tra
l’utilizzo e l’implementazione; le classi astratte AbstractEventClient (AEC) e
AbstractEventServer (AES) completano la progettazione, definendo delle basi
per le implementazioni. La descrizione dell’evento si basa su una classe base
che come unico metodo ha quello per ottenere la versione binaria dell’evento.
Le sue superclassi la specializzeranno per descrivere i quattro tipi di evento
decritti nel sotto paragrafo (3.1.1.4). Anche in questo sarà realizzata
un’implementazione usando il protocollo UDP in multicast ( un indirizzo per
ogni tipologia di evento).
50
3.4.3 Architettura del direct I/O per la gestione dei dati (Common
Layer)
Figure 3.17 Architettura del sotto sistema di IO.
Il direct I/O è una connessione TCP/IP dedicata all’inserimento
all’interrogazione dei dati della strumentazione (canali di I/O, allert, soglie,
etc.). Il driver interfaccia agli sviluppatori la Cloud per il live caching (LC) e
l’History storage engine (HSE) trattati nei successivi capitoli.
La gestione di questi dati è la cosa più importante all’interno di un sistema di
controllo, l’aggiunta di un nuovo layer software mira ad ottimizzare il più
possibile tale gestione (inserimento e query); infatti a differenza del sotto
sistema RPC i flussi di dati in ingresso ed uscita sono gestiti del tutto
differentemente. In !CHAOS sarà realizzata un’implementazione di tale
driver usando il Chaos Query Language (CHAOSQL). Ovviamente
l’astrazione del driver lavora sulla classe CDataWrapper che, come già detto,
astrae il paradigma chiave valore. Ogni altra implementazione (come e anche
il CHAOSQL) dovranno basarsi su questa logica.
51
3.4.4 Architettura MessageChannels (Common Layer)
Figure 3.18 Architettura dei canali dei messaggi.
L’architettura dei messaggi del sistema RPC presentata nel sotto paragrafo
3.1.1.2, è stata ulteriormente ampliata per semplificarne l’uso agli sviluppatori
( e all’interno del framework). La separazione dalle implementazioni dei
driver e l’indirizzamento verso un altro nodo sono stati astratti al massimo
mediante l’uso del broker e dei canali.
52
Il canale rappresenta l’interfaccia di comunicazione verso un nodo remoto; è
il livello di astrazione più alto per l’invio di messaggi e ricezione delle riposte
a richieste. La logica di incapsulamento del messaggio viene completamente
astratta. L’altro capo del canale è rappresentato dall’azione di un nodo
remoto.
Il MessageBroker è il nucleo principale dell’intero sistema Messaggi-RPC. Il
suo compito è la gestione dei seguenti aspetti:
• Inizializzazione e deinizializzazione del sistema RPC (client e server)
e del dispatcher;
• Allocazione e deallocazione dei canali (sia per il MetadataServer e sia
per la strumentazione);
• Registrazione e deregistrazione delle azioni.
Questo broker rappresenta un vero e proprio router, per lo smistamento dei
messaggi; la progettazione è fatta in modo da renderlo flessibile per
evoluzione future. Potranno essere apportati implementati nuovi scheduler e
differenti tipi di protocolli RPC, senza creare alle classi che usano i canali.
Implementazioni future dei saranno focalizzate alla sicurezza (cifratura del
contenuto dei messaggi) come anche alla ricezione di messaggi o richieste da
parte di canali remoti autorizzati. Quest’ultimo requisito servirà a disciplinare
i canali d’interfacce grafiche o di algoritmi di controllo, alla possibilità di
aprire canali verso uno o più strumenti. Ovviamente questa gestione dovrà
essere coordinata dal MetadataServer.
Il dispatcher è l’oggetto che prende in cura il messaggio ricevuto dal server
RPC e lo inoltra al destinatario. I destinatari sono delle classi c++ che
estendono “DeclareActions” e che dichiarano, alcuni metodi come azioni.
Queste poi dovranno registrarsi nel MessageBroker per esportare le azioni via
RPC. Alla definizione dell’azione la classe stessa dichiara l’indirizzo logico
con cui è pubblicata l’azione più l’alias con cui è esportata. L’indirizzo logico
è una stringa che, la quale funge da contenitore di azioni. Differenti classi
possono pubblicare azioni sotto lo stesso indirizzo logico. Il dispatcher è
definito da una classe astratta che implementa la maggior parte
dell’operazione, di registrazioni e deregistrazioni delle azioni. Le
53
implementazioni devono solo gestire come viene eseguito il processamento
delle chiamate. L’implementazione di default realizza il processamento
parallelo differenti indirizzi logici, per ogni indirizzo logico l’esecuzione delle
azioni è gestita da una coda FIFO.
3.4.5 Architettura EventChannels (Common Layer)
Figure 3.19 Architettura dei canali degli eventi.
L’architettura per la gestione degli eventi è molto simile a quella dei
messaggi. La differenza fondamentale sta nell’uso di un protocollo UDP
(multicast) e sull’assenza di richieste. La struttura si basa sui seguenti oggetti:
54
• La classe EventChannel rappresenta un canale dedicato per l’invio di
eventi. Per ogni tipologia esiste ne esiste sottoclasse specifica;
• EventHandler, identifica un oggetto capace di gestire eventi;
• EventFilter permette di descrivere un filtro su specifici eventi;
• AbstractEventDispatcher è la casse base che realizza la registrazione e
deregistrazione degli handler su determinati filtri. Le sottoclassi
specializzano lo smistamento degli eventi ricevuti seguendo le regole
dei filtri;
• Il client e server driver infine astraggono il protocollo di
comunicazione.
Il modo di trasmissione nell’implementazione di default è di assegnare un
indirizzo ip multicast ad ogni tipo di evento. In questo modo il filtro sui tipi
avverrà direttamente a livello di kernel. Il server ha due metodi per registrarsi
e deregistrarsi sulla ricezione di tipi di evento. L’implementazione di fatto
non dovrà far altro che registrarsi per ricevere i pacchetti UDP multicast
sull’ip associato e quel determinato tipo.
3.4.5 Architettura del Control Unit Toolkit Il CUToolkit è il livello software che ha lo scopo di facilitare la creazione di
driver per la strumentazione da collegare al sistema di controllo. Il disegno
del toolkit gira su una classe singleton principale, con funzioni di
coordinamento delle operazioni d’inizializzazione e deinizializzazione. Il
compito più importante è quello dell’esecuzione di Control Unit, moduli
software con il compito di interfacciare l’hardware al sistema di controllo.
Figure 3.20 Classe base di tutte le Control Unit.
55
L’uso del toolkit si focalizza su quattro fasi:
1. Inizializzazione, dove sono allocati i servizi RPC e degli eventi;
2. Aggiunta di Control Unit;
3. Avvio, fase in cui il CUToolkit diventa un vero e proprio server
attendendo comandi e schedulando l’esecuzione delle Control Unit
fino al suo spegnimento;
4. Deinizializzazione, fase in cui sono deallocate tutte le Control Unit in
esecuzione e le risorse.
Ogni modulo è una sottoclasse di AbstarctControlUnit (ACU, figura 3.20).
Questa è una classe astratta che definisce dei metodi obbligatori atti al
funzionamento dei moduli:
• defineActionAndDataset, permette di definire la struttura
dell’hardware che il modulo dovrà gestire;
• init, permette di avviare l’inizializzazione del device, nel caso
l’hardware da controllare avesse bisogno di procedure specifiche per
l’avvio al funzionamento;
• run, questo è il metodo che viene chiamato con frequenze regolabili
via RPC. L’uso di questo metodo è quello di monitorare lo stato dello
strumento e acquisire i valori correnti dei canali di output, per
inoltrarlo nell’infrastruttura di CHAOS;
• stop, questo metodo viene chiamato quando è stato richiesto lo stop
dell’acquisizione dei canali di Output;
• deinit, metodo chiamato quando è richiesta la deinizializzazione dello
strumento in quanto la sua funzione non è più richiesta;
• setDatasetAttribute, metodo chiamato quando si richieste
l’impostazione di uno o più attributi di Input.
La classe ACU, mette a disposizione dei metodi protetti, che dovranno essere
usati nelle implementazioni per definire il dataset degli strumenti descritto nel
sotto paragrafo 3.1.2. I dati campionati nel metodo “run”, tramite appositi
metodi, saranno preparati e spediti ai sistemi di live caching e di history a
seconda delle necessità. Le destinazioni dei dati non devono essere conosciute
a priori, ma sono una caratteristica dinamica del framework. Gli strumenti
56
potranno essere associati a differenti domini (con diverse implementazioni),
di live e history data.
Ogni pacchetto da inviare, per viene richeisto tramite un’apposita API della
ACU nel quale vengono valorizzate automaticamente le seguenti quattro
informazioni obbligatorie (con il paradigma chiave/valore):
• Stringa identificazione univoca del device;
• Timestamp di campionamento della CU;
• Timestamp hardware di campionamento(se presente);
• Codice di trigger.
La figura 3.19 mostra lo schema di massima della struttura del CUToolkit.
Il CommandManager si occupa di gestire l’uso del MessageBroker,
separandolo dalle Control Unit.
Il ControlManager ha il compito di regolare l’esecuzione delle fasi delle
Control Unit, e ricevendo comandi via RPC e coordinare il funzionamento dei
moduli.
Questa struttura permette di isolare al massimo i programmatori di moduli dal
resto di !CHAOS. In questo modo chi sviluppa codice per adattare gli
strumenti al sistema di controllo non deve assolutamente conoscere come gli
algoritmi di controllo lo useranno.
57
Figure 3.19 Architettura del Control Unit Toolkit.
3.4.6 Architettura dell’UIToolkit L’UIToolkit è il livello software studiato per facilitare lo sviluppo veloce di
applicativi quali interfacce utente per il controllo e il monitoring della
strumentazione; potrà ovviamente essere usato per creare algoritmi di
controllo sotto forma di applicazioni. La figura 3.20 ne mostra la struttura per
58
ora approssimativa. La classe fondamentale creata è il DeviceController, un
astrazione ad alto livello per la serializa, il DeviceMessageChannel, e il
DirectIO. In questo modo per creare applicazioni la conoscenza addentrata di
!CHAOS è del tutto opzionale.
Figura 3.20 Architettura dell’UIToolkit.
La classe DeviceController è sviluppata per essere inizializzata con la stringa
univoca d’identificazione della strumentazione DeviceID. Alla sua creazione
vengono istanziati i canali per inviare messaggi al metadata server(MDS) e al
device, e viene istanziato il driver per i dati22. L’inizializzazione della classe
avviene in tre fai:
• Creazione del canale per dialogare con il metadata server;
• Prelevamento delle informazioni dello strumento dal metadata server:
o Indirizzo del network e nodo della Control Unit che gestisce lo
strumento;
22 Usando un implementazione dell’AbstractIODriver
59
o Dataset dello strumento;
o Indirizzi dei server live e di storico che contengono i dati
campionati.
• Creazione del canale per lo scambio di messaggi con il device,
attraverso la Control Unit;
• Creazione del driver per recuperare i dati di live e storico dello
strumento.
Una volta istanziato il DeviceController astrae totalmente le risorse di
CHAOS permettendo allo sviluppatore di concentrarsi sulla propria
applicazione.
Questo è solo un primo passo per la realizzazione di un UIToolkit completo,
manca di fatto lo studio e l’analisi per implementare le seguenti features:
• Sistema di caching locale per poter condividere i dati dello strumento
tra differenti thread che ahnno la necessità di lavorare su dati dello
stresso strumento;
• Applicazione di algoritmi ai dati acquisiti;
• Creazione di speciali buffer, studiati ad hoc, per ottimizzare il fetch
dei dati live e di storico, e per ottimizzare l’applicazione di algoritmi
su di essi;
• Ottimizzazione del fetch dei dati live in caso di lettura da differenti
strumenti con differenti tempistiche. Sarà necessario un pool di thread
ognuno dei quali dovrà gestire un intervallo di tempo di acquisizione.
60
Figura 3.21 Schema approssimativo del multi threading caching.
La figura 3.21 mostra in linea di massima l’idea del caching per la
condivisione trai thread del processo della UIToolkit che accedono ai dati
live.
61
3.4.7 Architettura dell’Execution Unit Toolkit
Figura 3.22 Architettura dell’Execution Unit Toolkit
Le Execution Unit sono una parte fondamentale per il controllo automatico in
CHAOS, la struttura del EUToolkit che le gestisce è molto simile a quella del
CUToolkit (sotto capitolo 3.4.5). La differenza fondamentale sta nella
astrazione del lavoro quello del driver per la Control Unit e quello di un
algoritmo per la Execution Unit.
Il compito dell’execution unit, come già detto, è di semplificare la creazione
di algoritmi, e permettere la loro esecuzione in un cluster di server di EU. La
classe astratta AbstractExecutioUnit ha due metodi astratti:
• defineInputAndOutput, per la definizione dei parametri di input e
quelli di output;
• execute, metodo chiamato quando l’algoritmo deve svolgere i compiti.
Con le Execution Unit possono essere modellate due tipologie di algoritmi:
• Algoritmi di controllo, per il controllo di device;
62
• Algoritmi di calcolo.
In entrambe le tipologie, gli algoritmi possono usare i sia i DirectIO e sia i
MessageChannel in modo di leggere i dati live e storici degli strumenti e
controllarne altri mediante messaggi RPC. I parametri di input potrebbero
essere usati per configurare su quali device e attributi eseguire i controlli.
Quelli di Output invece sono da considerarsi utili negli algoritmi di calcolo.
Ogni tipologia di parametro è trasportata mediante messaggi RPC, in cui
ognuno è codificato col solito paradigma chiave/valore.
Questa struttura permette di creare una vera e propria coda di esecuzione di
algoritmi (sia di controllo che di calcolo), in cui i valori di Output di una EU
sono i parametri di input della successiva EU. La figura 3.23 mostra il
concetto.
Figura 3.23 Sequenza di EU per chiamate in cascata di algoritmi.
Ovviamente la sequenza di EU da chiamare deve essere predeterminata a
priori. Va studiato un sistema per usare il messaggio RPC in modo da
contenere gli indirizzi delle EU che completano la sequenza. Di Conseguenza
l’intero pacchetto potrebbe essere visto come un “programma” che viene
eseguito da diverse EU distribuite.
La figura 3.24 mostra come potrebbe essere strutturato il pacchetto inviato
alla pirma EU. Il metadata server potrebbe precalcolare, tra tutte le istanze che
si sono registrate delle EU in gioco, quali siano più libere (quelle con meno
istanze di algoritmi da eseguire) e inserire nel pacchetto le informazioni per
inoltravi via RPC i risultati delle EU. In coda invece ci sono i parametri di
input valorizzati per l’esecuzione della EU_1, che una volta terminata
procederà alla procedura di inoltro. Questa ha il compito di leggere
63
l’informazione sulla successiva EU (se presente) prelevare, se ci sono, i valori
dei parametri di output dopo l’esecuzione e inoltrarli tramite messaggio RPC.
Il messaggio di uscita ovviamente conterrà solo le successive EU. A questo
punto la EU_2 riceverà i parametri di output della EU_1 come sui input. Il
ciclo si ripete finche tutti i nodi non saranno esauriti.
Figura 3.24 Layer del pacchetto inviato alla prima EU.
Il trigger dell’invio del pacchetto può essere fatto o dal metadata server, per
l’esecuzione di algoritmi schedulati a tempo, da un’interfaccia utente di
monitoring e controllo. Da notare, che il costruttore del messaggio iniziale
può mettere le proprie informazioni al termine (al posto di un’EU) e quindi
ricevere lui stesso i valori di output dell’ultima esecuzione. Essendo i
messaggi asincroni questo non comporta nessun problema.
La figura 3.25 mostra la possibile architettura interna della parte di esecuzione
della EU. Ogni nuovo messaggio ricevuto viene messo in una coda d’attesa.
Una volta terminata l’elaborazione corrente viene prelevato un nuovo
messaggio dalla coda e processato seguendo le seguenti fasi:
• Estrapolazione dei parametri di input dal messaggio;
• Avvio del metodo “execute” con i parametri nel CDataWrapper;
• Terminata l’esecuzione del punto precedente, viene creato un nuovo
messaggio in cui viene copiato il restante contenuto di quello che ha
64
determinato l’esecuzione corrente e i correnti valori dei parametri di
output;
• Inoltro del nuovo messaggio alla EU successiva per mezzo di una
coda di uscita.
Le code d’ingresso servono nel caso si ricevano più messaggi mentre è in
corso un’esecuzione. Quella di uscita invece serve nel caso ci siano
problemi o lentezze nel dispatching dei messaggi RPC. La figura 3.25
schematizza l’idea che sta alla base del funzionamento precedentemente
esposto.
Figura 3.25 Struttura interna del framework della EU.
65
GESTIONE DEI DATI LIVE IN !CHAOS In questo capitolo sarà trattata in modo dettagliato la gestione dei dati “live”
della strumentazione, saranno illustrate le soluzioni adottate per
massimizzarne l’accesso simultaneo. La necessità è di condividere a più
“reader” possibili i valori attuali dei canali di Output, Input e degli Allert della
strumentazione. La configurazione descritte è quella di un “writer” e molti
“reader”.
4.1 Architettura
Figura 4.1 schema d’interazione del driver di !CHAOS e i client nella gestione dei dati live.
La figura 4.1 mostra la topologia introdotta nel sotto paragrafo 3.2.3, durante
la descrizione della tecnologia scelta a questo scopo. Il “dev_1” rappresenta la
strumentazione che, ad intervalli scelti, invia i dati sopra elencati nella cache
centrale. Una volta nella cache centrale, questi sono disponibili a chiunque ne
faccia richiesta. Nella figura le “ui_x” sono le interfacce utente o gli algoritmi
di controllo che, a differenti intervalli, prelevano il dato per poterlo mostrare o
analizzare. L’invio dei dati è svolto dalla Control Unit durante il metodo
“run”, usando le api messe a disposizione dal CUToolkit. La topologia di
questa progettazione permette di togliere dalla Control Unit, spostandolo sulla
livecachedev_1
push data
ui_1
ui_2
eu_1
66
cache centrale, il carico di molti “reader” che tentano di accedere ai dai. La
lettura del dato avviene su iniziativa delle UI. Le scritture e letture in questo
modo sono asincrone, questo può ovviamente portare a perdite di pacchetti
nel caso la lettura sia più lenta della scrittura. In realtà questo, in un sistema di
slow control, non è un problema enorme, lo è invece nel caso di algoritmi di
controllo che hanno l’esigenza di non perdere assolutamente nessun
pacchetto. Per risolvere questo inconveniente è stata introdotta nella
progettazione la possibilità da parte dei reader di potersi registrarsi nella
cache centrale in modo di ricevere i dati in modalità “push”. Differentemente
dalla lettura in polling, questa modalità consiste nell’invio di nuovi dati
direttamente dalla cache centrale ai reader. Una volta avvenuta la
registrazione, il reader (tramite un servizio in ascolto) attenderà la notifica con
i nuovi dati aggiornati. La differenza fondamentale tra “pollig” e “push” sta
nel fatto che l’invio delle notifiche è fatto con la stessa frequenza di
aggiornamento dei dati da parte del writer. È evidente che se tutti i reader
usassero il push anche solo per il monitoring, si avrebbe un notevole consumo
di banda inutilmente. L’uso di entrambi i metodi quindi permetterà di gestire
in modo ottimale la larghezza di banda utilizzata per il caching dei dati live.
4.2 Implementazione Nella versione di !CHAOS attuale è stato sviluppato un driver per il direct I/O
che supporti il software Memcached. Purtroppo a tutt’oggi questo software
non supporta la modalità push dei dati, quindi dovrà essere modificato ai fini
di integrare questa modalità. Nella versione corrente di CHAOS l’uso del live
è quindi limitato al polling e tutti i test esposti nel prossimo capitolo sono
quindi stati fatti in questa modalità. Ogni Control Unit, al momento
dell’inizializzazione viene quindi fornita un’istanza del MemcachedIODriver
(Figura 4.2) per la gestione dei dati live(Figura 4.3). In questo modo tutte le
operazioni di push del dato sono ridirette sul live caching.
67
Figura 4.2 Implementazione su Memcached.
Il fail over avviene secondo le logiche dei client di memcached mediante un
algoritmo di “Consistent Hashing”. La logica alla sua base è di distribuire le
chiavi omogeneamente sui vari server. L’algoritmo però basa i sui calcoli sui
caratteri che compongono la chiave. Questo ovviamente non tiene conto della
dimensione dei dati e della frequenza di aggiornamento, portando cosi un alta
probabilità di avere i server sbilanciati nel carico (quantità di dati acquisiti ed
erogati). Questa logica quindi non può essere usata in !CHAOS e andrà
implementato l’algoritmo descritto nel paragrafo 3.3.
Figura 4.3 Uso di Memcached Nel Live Data.
Come vedremo nel capitolo 4.3 Memcached è molto performante, un solo
processo riesce a gestire un rapporto di 1 a 40 tra writer e readers.
Nel caso di problemi dovuti al fatto che i dati live risiedono su un solo server,
sono state studiate modalità e tecnologie alternative a quella proposta sopra
68
mediante l’uso delle Reflective Memory (RM):
• Uso delle RM per clonare la memoria di Memcached su un altro server
(in modo da poter supportare più readers);
• Uso delle RM per sostituire Memcached;
Le Reflective Memory sono schede di memoria interconnesse tra loro da una
rete ad hoc. Garantiscono precisione nelle tempistiche e un elevato
determinismo nel trasferimento dei dati tra le schede. Ciò è reso possibile
dall’uso di un network dedicato in fibra ottica con algoritmi specifici per la
trasmissione dei dati tra nodi, con calcolo dei ritardi.
Figura 4.4 Esempio di network tra banchi di Reflective RAM.
L’uso delle RR è abbastanza semplice e permette di leggere, scrivere e
monitorare una locazione di memoria. Ogni operazione di scrittura è
sincronizzata tra tutti i nodi del network. I tempi di aggiornamento e le latenze
dei dati tra i nodi sono deterministici e dipende dal tipo di RM usata.
L’uso delle RM nella replica di memcached (Figura 4.5), permette di poter
usare l’ethernet per collegare Control Unit, User Interface ed Execution Unit
al caching dei dati. Grazie al determinismo dei trasferimenti sotto un certo
ritardo, viene garantito che i dati su altri server memcached siano presenti e
aggiornati per la lettura. Questo permette di aumentare ulteriormente il
numero di readers per determinate strumentazioni. In questo modo inoltre è
69
aumentata la sola complessità della cache centrale rimanendo inalterata quella
delle CU, EU e delle UI, non necessita quindi lo sviluppo di un nuovo driver
di direct I/O. Questa configurazione necessita di una modifica sostanziale nel
modo in cui memcached usa la memoria e organizza le chiavi. Andra quindi
fatta un’analisi specifica per poter apportare le modifiche necessarie.
Figura 4.5 Uso di memcached nel Live Data replicato con le RM.
Dove è richiesta una velocità e un determinismo maggiore sui ritardi di
lettura, memcached potrà essere sostituito interamente con le RM.
Assicurando una sincronia tra banchi differenti di uno stesso network con un
ritardo ben determinato e fisso, questa nuova implementazione del live
caching potrà essere usato per controlli che richiedano tempi molto più sicuri
e veloci in lettura e scrittura dei dati rispetto a quelli che si possono avere con
l’uso di MC.
70
Figura 4.6 Implementazione del Live Data Con la Reflective RAM
La figura 4.7 mostra la differenza del live data tra l’uso di Memcached e l’uso
delle Reflective Memory. È semplice notare come sia per i “getters” che per i
“setter” il modo di funzionamento non è cambiato.
Figura 4.7 Differenze di topologia della cache live, nell’uso di memcached o delle Reflective RAM.
In conclusione è evidente come il disegno architetturale è stato orientato
modellando il gestore dei live data come si stesse usando una vera e propria
memoria ram. Man mano che nel tempo le prestazioni del network e dei
computer saranno sempre più veloci, le applicazioni di questo livello potranno
spingersi sempre più avanti.
4.3 Performance Lo studio su questo memcached, usato come live data, è stato principalmente
impostato dal punto di vista del calcolo delle performance sotto un graduale
aumento di carico. Il parametro da osservare era il tempo di trasferimento da
un singolo writer ad un numero crescente, ad ogni prova, di readers.
71
L’operazione di “set” su memcached aveva un rate fisso di 100hz23 con un
buffer di dati (serializzati tramite BSON) di dimensione pari a 150 kbyte. La
lettura aveva una frequenza di 1khz24 con un numero variabile di readers nelle
diverse prove effettuate. Il grafico in figura 4.8, mostra la distribuzione dei
tempi rilevata dai reader. Il tempo è stato calcolato sottraendo al timestamp
preso dal reader terminata la serializzazione dopo l’operazione di “get”, il
timestamp preso dal writer prima di serializzare ed eseguire l’operazione si
“set” del pacchetto nella cache.
Figura 4.8 Distribuzione dei tempi di trasferimento dal writer ai reader
La distribuzione dei tempi va da uno a quattordici millisecondi e si mantiene
pressoché costante tra gli uno e i dodici millisecondi. L’aumento del numero
di lettura (40000 al secondo nell’ultima prova) non disturba più di tanto la 23 Un invio ogni dieci millisecondi 24 Mille interrogazioni al secondo
40 c
lient
s
0
5
10
20 c
lient
s
0
5
10
10 c
lient
s
0
5
10
5 cl
ient
s
0
5
10
CU-client transfer time0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
72
distribuzione. Ciò dimostra che il comportamento di memcached è ottimale
come cache centralizzata di tati ad alte performance. Il test dimostra quindi
che tale cache può essere usata sia come monitor che come fonte di lettura di
dati per algoritmi di controllo in cui i ritardi calcolati non siano un problema.
73
GESTIONE DEI DATI STORICI IN !CHAOS In !CHAOS, i dati denominati come “storici” oltre ad avere la necessità di
essere memorizzati e devono anche essere ricercati. Questi due,
apparentemente, semplici requisiti pongono diversi problemi se posti
all’interno di un sistema di controllo che deve gestire migliaia di strumenti.
Uno dei problemi fondamentali sono le performance in scrittura e lettura. Il
sistema di storage deve quindi fornire, oltre ad un’alta affidabilità e
disponibilità anche una flessibile scalabilità in modo di garantire la gestione
di alti carichi; per l’inserimento di dati da parte del writer in un flusso
costante ad alto rate di, e contemporaneamente, richieste di letture da più
“readers”. Riportando questo requisito ad un alto numero di strumentazione è
evidente la difficoltà.
Lo “storage” dei dati è innanzi tutto soggetto ad “ageing25” definito su uno o
più strumenti. Questo permetterà di eliminare quei dati la cui finestra
temporale di validità sia scaduta. Ciò risulta utile quando si hanno tipologie di
strumentazione i cui dati sono necessari per un breve periodo.
Per quanto riguarda la “ricerca” sono:
• Scalabilità, affidabilità e disponibilità del servizio d’interrogazione sui
dati;
• Uso del sistema di storage descritto in precedenza.
• Possibilità di definire algoritmi d’indicizzazione su uno o più attributi
del dataset della strumentazione;
• Gestione degli indici coordinata con lo storage dei dati.
Il primo punto è ovviamente necessario affinché i dati siano reperibili sempre
e il più velocemente possibile (come nel caso dello storage).
Il secondo punto elimina l’idea di utilizzare un database che replichi i dati, va
quindi utilizzato il sistema di storage usato per l’archiviazione del dato, si
evita la duplicazione di dati e lo spreco di spazio.
Il terzo punto dipende dal fatto che essendo !CHAOS un sistema senza
schema definito, non è quindi possibile a priori definire delle logiche di
25 invecchiamento dei dati
74
indicizzazione globali. L’ultimo punto infine pone l’attenzione sul fatto che
gli indici devono essere gestiti in considerazione alle regole (ageing) di
storage dei dati indicizzati.
Questa breve introduzione rende evidente come non sia possibile usare un
database (SQL o NOSQL) “classico”26. Le regole di ageing potrebbero
permette di non eliminare “mai” i dati acquisiti ed è quindi impensabile
l’indicizzazione totale e continua di tutti i dati memorizzati.
A questo semplice ma enorme vincolo, è stato aggiunto il seguente requisito:
L’indice deve essere creato su uno o più strumenti, per un determinato
intervallo di tempo (parametri obbligatori). Il motivo di tale richiesta dipende
dal fatto che sarebbe impensabile ( ovvero dispendioso in termini di spazio)
indicizzare ogni attributo di ogni strumento per ogni dato inserito.
Nel caso di migliaia di strumenti si avrebbero vari “tera” o “peta” bytes di
dati, l’indice quindi occuperebbe ancora di più. La logica poi è che si debbano
creare indici, con algoritmi proprietari in un intervallo temporale per correlare
e studiare eventi o situazioni precise. Una volta terminato tale studio l’indice
potrà essere eliminato. Quello invece che è necessario tracciare sempre è la
locazione nello storage di un dato per intervallo di tempo. Le informazioni di
default del pacchetto descritte nel sotto paragrafo 3.4.5 permettono di creare
un indice sempre presente che è quello utilizzato per trovare velocemente la
posizione nel filesystem di un pacchetto di dati di uno strumento per un
determinato istante di tempo.
26 Per “classico” si intende il database che gestisce sia lo storage, indicizzazione e richieste di
query.
75
5.1 Architettura
L’architettura della gestione dello storico, nasce basandosi all’alta
affidabilità, disponibilità ed alta scalabilità. Per risolvere tutti questi
problemi si è introdotto un layer interposto tra i client che eseguono
inserimenti e query di ricerca, e lo storage dei dati e gli indici da
interrogare.
Figura 5.1 Nodi usati per la gestione dello storico (interprete del linguaggio CHAOSQL
e di Indexer).
L’architettura si basa principalmente su tre tipi di nodi:
• L’interprete CHAOSQL (Proxy Node, PN);
• Il nodo indexer (Indexer Node, IN);
• Il nodo di management dello storage (Management Node, MN);
L’interprete CHAOSQL è in realtà un proxy che interpreta i pacchetti
CHAOSQL e provvede agli inserimenti o alle ricerche dei dati. La sua
funzione è anche quella di separare i client che scrivono e leggono i dati, dalle
implementazioni per la realizzazione dello storage e degli indici. I nodi
indexer, non sono visibili ai client, vivono all’interno della nuvola dei dati di
storico. Il loro compito è di provvedere, secondo le regole di ageing e degli
algoritmi all’indicizzazione dei nuovi dati memorizzati nel filesystem o alla
rimozione degli indici non più necessari. Il nodo di management infine ha il
compito di gestione automatica dello storage ed è dipendente dall’ageing dei
dati, la sua trattazione sarà esposta approfonditamente nel paragrafo 5.2.4.
L’architettura software si basa principalmente sull’uso del common layer
(layer base delle CU, EU ed UI) e sull’uso di due driver che permettono di
76
astrarre l’uso del sistema di storage e del sistema di indicizzazione. I due
driver permettono quindi di personalizzare la logica di storage e di gestione
degli indici. Il Common Layer permette alle due tipologie di nodi di integrarsi
all’interno di !CHAOS. I messaggi RPC e gli eventi saranno usati per
implementare le seguenti funzioni:
• Registrazioni delle due tipologie dei nodi all’interno dei metadata
server;
• Scambio d’informazioni tra i nodi proxy e gli indexer per informazioni
sullo stato di aggiornamento e gestione degli indici;
• Creazione di differenti domini di appartenenza dei serve;
• Ricezione asincrona dei risultati di ricerca.
I domini sono nuvole di dati distinti tra loro da una differente
implementazione dello storage e della gestione degli indici. Il dominio non va
confuso con la scalabilità. Ognuno di esso è costituito da un certo numero dei
tre tipi di nodi in modo da garantirne l’affidabilità e la scalabilità. All’interno
di un unico sistema di !CHAOS potranno quindi coesistere più domini con
eguale o differenti implementazioni. I vari strumenti potranno essere associati
ad uno o all’altro dominio. La limitazione a questa logica è che differenti
domini non possono condividere dati (di fatto non servono ad aumentare
scalabilità). L’uso più immediato di avere differenti domini potrebbe essere il
seguente: Immaginiamo di avere un dominio realizzato con software open
source performante ma di dimensioni limitate e un altro con software di
storage a lunga persistenza con HSM27 in modo da non dover mai rimuovere
dati. Storage con HSM sono molto costosi. Avendo quindi due domini,
potranno essere associati al dominio più costoso quelle strumentazioni di cui
si ha effettivamente necessità di non perdere mai i dati. Per esempio in un
acceleratore i dati dei rilevatori hanno sicuramente necessità di non essere mai
persi contrariamente a quelli dello slow control.
27 Hierarchical Storage Management
77
Di seguito viene mostrato il flusso dei dati sia nelle operaizoni di insert che
di query. Immaginiamo di avere la seguente implementazione per il
filesystem e per la gestione degli indici:
• Filesystem: uso di Hadoop [8] come filesystem distribuito per lo
storage;
• Index: MongodDB [9] come sistema di gestione delle strutture degli
indici;
Disporremo quindi dei driver per lo storage che implementano le operazioni
di lettura/scrittura/creazione file su Hadoop e l’indexer che scansionando i
vari pacchetti memorizzati crea e aggiorna gli indici usando MongoDB come
sistema di gestione. Questo permette di scalare ulteriormente all’interno della
nuvola anche il filesystem e il sistema d’indici. Sia Hadoop che MongoDB
hanno un’elevata possibili di scalare. Esiste in letteratura report installazioni,
si per Hadoop28 che per MongoDB29, di migliaia di nodi.
La figura 5.2 mostra il flusso di dati e la sequenza delle operazioni eseguite
dai nodi proxy e indexer, all’atto della richiesta di lettura e scrittura dei dati.
Le linee verdi descrivono l’inserimento di un pacchetto di dati da parte della
strumentazione, le rosse la lettura da parte dell’interfaccia utente. La direzione
della freccia, indica il verso in cui viaggiano i dati.
L’inserimento di un pacchetto parte dalla CU che gestisce la strumentazione.
Quando uno strumento è associato un dominio di storico, ad essa viene
inviata, dal metadata server, la configurazione con la lista di indirizzi30 dei
nodi proxy a cui deve inviare i dati. Una volta ricevuto il pacchetto (1), il
proxy ne interpreta le chiavi di comandi, e prevede nel minor tempo possibile
alla memorizzazione su filesystem (2). Usando Hadoop il dato inserito è
replicato su altri fileserver (linea grigia). Dopo la memorizzazione, viene
mendato un evento di avvenuta memorizzazione di nuovo pacchetto (3), Il
nodo indexer più libero prende in incarico il lavoro e lo mette in coda. Al
momento di processare il pacchetto, il nodo indexer lo legge (4) da un 28 http://wiki.apache.org/hadoop/PoweredBy 29 http://www.mongodb.org/display/DOCS/Production+Deployments 30 Come descritto nel sotto paragrafo 3.3
78
qualsiasi dei nodi che lo possiede (grazie ad Hadoop) non necessariamente da
quello in cui è stato scritto. Il pacchetto è analizzato e nel caso sia da
indicizzare (secondo le regole successivamente descritte) vengono applicati
tutti gli algoritmi per determinarne il modo in cui modificare gli indici di
competenza, a quel punto avviene l’aggiornamento (5) degli indici nel sistema
di management degli stessi (MongoDB).
La richiesta di una query di ricerca o di una lettura di un determinato
pacchetto, avviene nel seguente modo; L’interfaccia utente richiede un canale
per il device di cui vuole leggere ottenere le informazioni. Il canale è
configurato con il dominio di pertinenza dello strumento. La richiesta è quindi
inviata (1) al proxy con più alta priorità in lista. Il proxy decodifica la
richiesta e mediante il driver di gestione degli indici controlla che esistano le
informazioni per portare a termine la ricerca (2) ottenendo, quindi in caso
positivo, la posizione del o dei pacchetti che rispecchiano la richiesta dal
sistema di management degli indici. Il o i pacchetti sono quindi prelevati (3)
dai vari fileserver (Hadoop) ed inviati (4) al client. Non detto che debba
essere un solo proxy a rispondere con i dati. Come in tutti i nodi le richieste e
le risposte sono asincrone, quindi se una richiesta ha più pacchetti di risposta,
ogni altro proxy, oltre a quello che ha ricevuto la richiesta, può inviare il
pacchetto di risposta.
Dalle fasi sopra descritte è evidente che un qualche sistema di
memorizzazione dello stato d’indicizzazione debba essere usato. In questo
caso usando MongoDB per la gestione degli indici, si potranno usare alcune
collection per gestire lo stato dei pacchetti da indicizzare, e lo smistamento di
questo tramite i vari indexer più liberi. Altre collection invece saranno usate
per i dati degli indici.
79
Figura 5.2 Possibile implementazione dell’inserimento e della lettura dei dati da storico.
5.2 Implementazione In questo paragrafo saranno descritti:
• ChaosQL il modo di descrivere una query;
• Riposte sincrone ed asincrone alle query;
• Gestione degli indici;
• Gestione dell’ageing sui dati;
5.2.1 ChaosQL Il ChaosQL in realtà non è un vero è proprio “linguaggio” ma un insieme di
valori associati a delle chiavi ognuna delle quali corrisponde ad un comando
nella gestione dei dati nello storico. In questo modo si perde effettivamente
80
leggermente di velocità ma si aumenta la flessibilità di aggiungere nuove
funzioni.
Figura 5.4 Schema del pacchetto del CHAOSQL.
La figura 5.4 mostra schematicamente com’è composto il pacchetto
CHAOSQL:
• L’header, di 6 byte, porta con se informazioni che servono a capire
velocemente la versione del protocollo e di che tipo di comando si
tratta e i due byte per la dimensione dei dati opzionali per il comando
e due byte per la dimensione dei dati;
• Il campo Optional Command data contiene nel caso ci fosse bisogno
di ulteriori dati necessari per il processamento del comando. La
dimensione massima è di 2^16 bit (dimensione tracciata dagli ultimi
due byte dell’header;
• Per ultime ci sono le informazioni key/value (K/V) codificate secondo
la serializzazione scelta (di default quella BSON) con dimensiona
header: 6 byte
data: key/value serialization
optional command data: n byte
issuer_attribute: {sub key/value issuer document}command_attribute: {sub key/value attribute document}query_attribute: {sub key/value command data document}
Insert
Query
key/value device document
version (1b)
cmd type (1b)
opt cmd data len (2b)
data len (2b)
81
massima di 2^16 bit. Il tipo di informazioni sono contestuali
all’operazione.
Il fatto di avere l’header in versione raw e non K/V permette senza
deserializzare il dato di poter capire come trattarlo. Alcune funzioni
potrebbero non avere necessità di capire il contenuto. Cosi facendo lo
smistamento dei dati nei processi di gestione sarà più performante.
I primi due byte dell’header descrivono la versione e il tipo di comando,
ognuno del quale può variare da 0 a 255. La versione descrive il tipo di
protocollo usato. Il tag di tipo invece, descrive l’operazione codificata nel
pacchetto e possono essere (ad oggi); Inserimento e Ricerca.
Per descrivere meglio il compito dell’header, la figura 5.5 schematizza in
maniera più dettagliata, l’architettura del nodo proxy visto nel paragrafo
precedente. I pacchetti CHAOSQL arrivano direttamente dal CHAOSQL
Direct I/O server. Questo servizio assicura l’interazione con il CHAOSQL
Direct I/O driver nelle CU, EU, ed UI (paragrafo 3.4.3).
Figura 5.5 Schema dettagliato dell’architettura del nodo di proxy.
L’operazione di “Insert”, deve provvedere nel minor tempo possibile alla
memorizzazione del pacchetto. In questo caso i dati opzionali dopo l’header
hanno l’informazione del identificativo univoco del device e la chiave di
autorizzazione (si deve evitare che altri strumenti inseriscano per errore dati
non propri). A verifica effettuata, il pacchetto è inviato nel livello di “Insert
Logic” (IL) che, prendendo l’identificativo del device, prevede a
82
memorizzarlo tramite lo storage driver. La parte K/V del pacchetto contiene la
sola parte “data” che, senza essere interpretata, è trasferita dalla “IL”
direttamente sul filesystem. Il client può richiedere o no di rimanere in attesa
finche il dato non è memorizzato.
L’operazione di “Ricerca” è in due fasi:
• Fase di richiesta;
• Fase di ricezione.
Il campo di dati opzionali dei comandi in questo caso non è usato, a
differenza dell’inserimento, si può rinunciare a piccoli ritardi aumentando la
flessibilità. In questo caso la parte di dati del pacchetto contiene, come
mostrato in figura 5.4, in formato K/V tutte e tre le chiavi:
• Issuer Attribute, identifica il mittente della richiesta;
• Command Attribuite, definisce le opzioni della ricerca e la
destinazione dei risultati, se differente dal mittente;
• Data, definisce le regole della ricerca.
5.2.2 Riposte sincrone ed asincrone alle query di ricerca L’operazione di ricerca può essere effettuata in due modi (definendo una
chiave nella sessione degli attributi di comando) i quali portano a differenti
comportamenti del client e dei proxy nella fase di ricezione dei risultati; si
parlerà di richiesta sincrona o asincrona.
La richiesta sincrona prevede che il client rimanga in attesa dei risultati e che
questi siano ricevuti direttamente dal proxy a cui si è stata fatta la richiesta.
83
Figura 5.6 Richiesta sincrona del nodo client al nodo proxy.
La richiesta asincrona si basa sull’uso un apposito canale QueryChannel.
Questo si basa sia sul CHAOSQLDriver che sull’RPC del common layer ed è
in grado di mandare richieste sincrone ed asincrone. Alla creazione di tale
canele, è registrato un suo metodo come endpoint RPC e vien allocato un
nuovo ID !CHAOS (per la ricezione di messaggi RPC). Il canale, quando si
inviata una query di ricerca sincrona, inserisce nell’header il nuovo tag che la
identifica come sincrona e nella chiave “command_attribute”, nei dati nel
pacchetto, le informazioni necessarie affinché possa ricevere messaggi RPC.
Il proxy, una volta ricevuta la richiesta, divide il lavoro in parti eguali tra gli
altri nodi più liberi. Anche se non specificato le query, si basano sempre su un
intervallo di tempo. Quando non specificato, sarà considerato come periodo di
partenza il primo timestamp disponibile fino all’ultimo memorizzato. A
questo punto il pacchetto viene replicato in un numero di pacchetti uguale al
numero di server scelti (compreso quello che ha ricevuto la richiesta). A
questo punto i nuovi pacchetti vengono opportunamente modificati con i
nuovi parametri e inviati agli altri proxy, ognuno dei quali effettua la ricerca
descritta dal pacchetto ricevuto e quando pronte, invia le risposte al client che
84
ne ha fatta richiesta. Le rispose arriveranno dai proxy selezionati in modo del
tutto asincrono mediante il protocollo RPC di !CHAOS.
Figura 5.7 Flusso dei dati nella richiesta asincrona.
5.2.3 Gestione degli indici La differenza fondamentale dei dati gestiti in !CHAOS rispetto ad un modello
standard di sistema informativo è il tempo. Ogni pacchetto di dati generato
dalla Control Unit è acquisito in un determinato istante di tempo e l’insieme
dei valori (timestamp e valori canali di I/O) non verrà più modificato, al più
cancellato. Come introdotto nel precedente paragrafo, nel sistema di
archiviazione di !CHAOS non sarebbe pensabile indicizzare tutti i pacchetti
inseriti, il problema principale è dato dallo spazio.
La gestione degli indici si basa sue tipologie:
• Time Machine Index (TMI) permette di recuperare il pacchetto di un
determinato strumento in un determinato istante di tempo;
• Dataset Index (DSI) permette di trovare un device su logiche applicate
ai valori dei canali di I/O.
La gestione di entrambi è astratta dall’IndexDriver, permettendo quindi di
realizzarla con qualsiasi tecnologia si voglia. Entrambe le tipologie di indici
85
sono comunque pensate per essere realizzate trami un database relazionale o
NOSQL.
Figura 5.8 Schema della tracciatura degli eventi nel tempo con il TMI.
Il TMI è un indice che permette di conoscere, dato un preciso istante di
tempo, quali pacchetti archiviati, sono stati generati in quell’istante al meglio
di una certa quantizzazione. La sua utilità è ovviamente anche quella di
conoscere quale intervallo di tempo coprono la totalità dei pacchetti
memorizzati.
Ogni livello è costituito da un certo numero di “quanti” (t0-t1…etc.), il
successivo è a sua volta una suddivisione (in ‘i’ intervalli) di ogni quanto a
livello precedente. Il livello zero, per esempio, rappresenta gli anni in cui ogni
quanto identifica un anno. Il livello uno è quindi la suddivisione in mesi di
ogni quanto precedente. Il numero di livelli dipende dalla configurazione
iniziale di quanta quantizzazione è necessaria. Il timestamp presente nei
pacchetti, come gia detto, viene creato direttamente dal framework della
Control Unit. Questo a seconda della quantizzazione che è stata richiesta nello
scheduling del metodo run, pulisce le cifre non necessarie del timestamp
quantizzando alla creazione il timestamp. Questo permette quindi
86
velocemente di calcolare su quale livello il pacchetto deve essere messo.
Consideriamo ad esempio il seguente timestamp:
TS=YYYY:MM:DD:SS:000:000 le ultime sei cifre (microsecondi e
millisecondi) sono a zero quindi il livello in cui il pacchetto verrà inserito sarà
quello dei secondi. Tutta la catena YYYY:MM:DD:SS sarà quindi necessaria
a trovare il quanto dei secondi relativo a tutto il timestamp a cui verrà
associato il pacchetto.
La struttura è quindi una struttura ad albero in cui i nodi sono identificati da i
quanti di tempo. Le foglie sono i quanti di tempo più piccoli.
L’indice DSI è usato per query di ricerca sui canali di I/O della
strumentazione. La sua gestione avviene per mezzo del CHAOSQL con il tipo
di comando appropriato e diversamente dal TSI non viene creato di default..
La sua creazione avviene definendo i seguenti parametri (nel Command
Attribute del pacchetto del pacchetto CHAOSQL):
• Intervallo di tempo su cui si vuole creare l’indice;
• Identificativo della strumentazione;
• Nome attributo.
Il pacchetto per la creazione del DSI appena è ricevuto dal proxy, viene
suddiviso (come nel caso della query asincrona) per intervallo di tempo e
inviato ai nodi Indexer. Questi, usando il TSI, reperiranno i pacchetti dei dati
della strumentazione per il periodo di tempo desiderato e creeranno per ogni
valore dell’attributo un record come quello in figura 5.9. Ogni driver avrà il
compito di mappare i differenti tipi degli attributi a quelli del database usato .
Figura 5.9 Struttura del record per indicizza una colonna coi suoi valori.
Entrambi gli indici sono realizzabili mediante i moderni database, ed entrambi
sono sia realizzabili mediante delle normali tabelle realzionali o mediante i
87
più moderni database NOSQL. La realizzazione delle strutture necessarie alla
loro implementazione, cambierà quindi, a seconda della tecnologia che si
userà per la loro memorizzazione.
L’architettura degli indici proposta offre una grande flessibilità ad
implementazioni di nuove tipologie di indici. Infatti si è gia pensato, in futuro,
di offriere la possibilità di creare indici su funzioni definite dall’utente, ma la
dinamica e l’architettura di questa soluzione ancora non è stata affrontata. La
logica dei driver e comunque la grande duttilità del CHAOSQL
permetteranno agli implementatori del sistema di definire i propri indici
custom.
5.2.4 Gestione dell’ageing sui dati. L’ageing nello storico di !CHAOS è intenso come, quel processo per cui
superato un determinato intervallo di tempo un pacchetto diventa “vecchio” e
quindi subisce un trattamento. Questo si divide in due differenti operazioni sui
pacchetti:
• Cancellazione dei pacchetti non più necessari;
• Archiviazione dei pacchetti su un diverso supporto di archiviazione a
lunga persistenza;
La cancellazione dei paccehtti è presa in considerazione per gestire lo spazio a
disposizione nello storage dello storico. Il sistema usa questa operazione per
mettere a disposizione spazio libero sullo storage per i nuovi dati. In questo
caso l’ageing è rappresentato da una finestra temporale superata la quale i
pacchetti di una strumentazione possono ritenersi non necessari.
Nell’altro tipo di operazione invece, superata tale finestra i dati non sono
cancellati ma bensì archiviati, dopo di che saranno taggati come
“cancellabili”. I cosi taggati sono quelli che, nel momento di bisogno di
spazio nello storage, possono essere cancellati dallo storico. In realtà in caso
di mancanza di spazio l’operazione viene comunque avviata anche nel caso in
cui la finestra di ageing non sia superata. La logica è sempre quella di
cominciare la migrazione dei pacchetti più vecchi.
Il nodo di gestione (MN) introdotto all’inizio di questo capitolo, si occupa
della gestione delle attività sopra preposte. Il suo lavoro viene astratto come
88
negli altri due casi dei driver di storage e di indicizzazione. L’eliminazione
dei dati avviene in tre fasi:
• Vengono eliminati tutti gli indici TMI e DSI relativi ai pacchetti da
cancellare, in modo da rendere i pacchetti invisibili alle query di
ricerca;
• Avviene l’effettiva rimozione dei dati dal filesystem.
5.2.4 Gestione dell’archiviazione dei pacchetti nel filesystem Il driver che implementerà archiviazione dovrà essere progettato in modo che
i dati memorizzati nel filesystem siano raggruppati in chunk temporali. Con
chunk temporali si intende un file fisico che contiene pacchetti acquisiti in un
intervallo di tempo (e.s 30 minuti). Questa organizzazione dei pacchetti
permette di ottimizzare le operazioni di cancellazione e archiviazione
descritte nel precedente paragrafo; lo storage driver infatti al momento della
cancellazione dei pacchetti, eseguirà la rimozione del chunk, che li contiene,
solo dopo che sia stata richiesta l’eliminazione dell’ultimo pacchetto in esso
contenuto. I pacchetti saranno quindi fisicamente eliminati solo quando sarà
eliminato il chunk che li contiene.
Figura 5.10 Struttura di un file logico per uno strumento.
La figura 5.10 mostra la struttura a chunk temporali in cui sono archiviati i
dati di uno strumento identificato da un determinato DeviceID (DID). “Pi”
rappresenta il pacchetto i-esimo dello strumento. Ogni chunk contiene quindi
un insieme di pacchetti appartenenti all’intervallo definito dal sistema per
ogni strumento, ad esempio: 30 secondi, 1 minuto, 2 minuti etc. Ogni chunk
quindi determina l’intervallo di tempo successivo al chunk precedente. I
chunk non possono essere vuoti quindi la mancanza di pacchetti per un
determinato periodo non comporterà aumento del numero di chunk. In questo
modo si avrà un file logico rappresentato dalla concatenazione di tutti i chunk.
Questa logica permette inoltre di risolvere i problemi dovuti a file
89
troppo lunghi e di avere accessi molto veloci ai singoli pacchetti; i chunk già
chiusi non verranno mai più riaperti in scrittura e quindi le letture saranno
notevolmente veloci. Per ogni DID si avrà un solo chunk aperto in scrittura
alla volta, e sarà quello in cui si aggiungeranno i nuovi pacchetti. Le
informazioni per trovare il pacchetto dato un DID e un timestamp saranno
reperibili dal TMI. Per descrivere il file nell’insieme dei sui chunk si è
pensato di usare l’indice descritto in figura 5.11.
Figura 5.11 Struttura del indice dei file.
Il File Info Index (FII) tiene traccia della sequenza di tutti i chunk. Le
informazioni FS_INFO (usato anche negli altri indici) sono definite in una
struttura dipendente dall’implementazione del filesystem, che contiene la
localizzazione del chunk nel filesystem e nel caso degli altri due indici (TMI
e DSI) anche le informazioni di localizzazione del pacchetto all’interno del
chunk. Tali informazioni di localizzazione sono in realtà l’offset del pacchetto
all’interno del file reale che rappresenta il chunk del file virtuale.
90
GESTIONE DEI DATI LIVE E STORICI IN UN UNICO
SERVIZIO Le soluzioni per la gestione dei dati live e storico soffrono di un problema. I
nodi che devono archiviare dati in entrambe le modalità, sono costretti ad
usare due driver con due flussi differenti di dati. Questo porta un doppio
carico di lavoro dei nodi che inviano dati. Tale problema può essere evitato
modificando l’architettura dei due gestori di dati, unendo in un unico nodo i
due servizi.
6.1 Architettura proposta
Figura 6.1 Nuova struttura del nodo proxy con l’aggiunta del caching dei dati live.
La figura 6.1 mostra le modifiche apportate al nodo proxy descritto nel
precedente capitolo. È stato aggiunto un nuovo driver per il caching dei dati
live, con il compito di astrarre l’implementazione di come i dati live vengono
gestiti. La gestione del caching viene quindi demandata al CHAOSQL,
usando due nuovi comandi; uno per il solo caching live e l’altro per il caching
e storicizzazione. Con questi due comandi il pacchetto potrà essere
storicizzato e inserito nella cache dei dati live con un unico invio. Eliminando
quindi la necessità di due invii da parte dei nodi.
Alla ricezione di un pacchetto col nuovo comando, il proxy passa la sua
gestione al Cache Driver: questo inoltra all’implementazione della cache
l’intero contenuto parte dati del pacchetto. Va considerato che non avviene
nessuna deserializzazione per l’inserimento in cache, questo per ottenere il
massimo delle prestazione e per rimanere coerenti al funzionamento di
91
Memcached e di una cache in generale che non tiene conto del contenuto in
memoria.
Un primo studio in questa direzione è stato fatto prendendo in esame la
possibilità di creare il CacheDriver con la versione embedded di memcached.
La comodità di avere un header prima della serializzazione in questo caso
permetterà dia vere performance simili a quelle di memcached reale. Di fatto
il proxy, nel caso dei dati live si comporterà esattamente dome Memcached.
6.2 Problematiche Ovviamente questo porta un overhead nel singolo nodo proxy che dovrà
gestire oltre alle query di inserimento di storico anche le query di inserimento
nel live caching ma anche per le letture. Infatti per i problemi di performance
descritti nel capitolo quattro, per quanto riguarda i dati live, questi vanno letti
nella cache dove sono inseriti. Rimangono comunque valide tutte la varie
ottimizzazioni esposte come la replica con le Reflective Memory oppure
l’uso delle RM al posto di Memcached.
92
OBIETTIVI RAGGIUNTI E FUTURO PROSSIMO Lo sviluppo sin qui portato a termine ha prodotto una prima versione dei
seguenti layers:
• Common Layer;
• CUToolkit;
• UIToolkit;
• Metadata Server lite.
• Eventi
Il common layer manca solo dell’algoritmo di fail-over.
La mancanza del fail-over al momento non pregiudica i tests che si stanno
effettuando sul controllo delle Contro Unit per mezzo di algoritmi che usano
l’UIToolkit. Ovviamente tutti in controlli sono eseguiti in modalità polling.
Per colmare la mancanza del metadata server definitivo si è arrivati a
svilupparne una versione light per rispondere ai messaggi di registrazione e di
update del Dataset delle Control Unit e alle query base dell’UIToolkit. Nei
prossimi mesi lo sviluppo continuerà parallelamente nell’implementazioni dei
seguenti layers:
• Gestione degli eventi;
• Metadata Server completo;
• Gestore unificato dei dati live e di storico.
Per quanto riguarda l’ultimo punto, una sua prima implementazione sarà
incentrata sull’uso di Hadoop come filesystem e di Mysql o MongoDB come
gestori degli indici. Si cercherà di usare prodotti che possano garantire un’alta
scalabilità proprio per riuscire ad effettuare tests sulle performance, per il live
e lo storico, al crescere del carico. Infine, lo sviluppo sarà concentrato sulla
replica del caching dei dati tramite Reflective Memory o l’uso delle stesse
direttamente come caching.
Ultimamente si è preso in considerazione la libreria ZMQ [10] in grado, da
sola, di coprire le tre tipologie di networking di !CHAOS. Per test è stato
implementato il solo driver di RPC e la prova ha dato esito positivo. Resta
ancora da valutare l’effettivo beneficio di tale libreria nell’uso pratico. Ciò è
servito anche a verificare l’alta adattabilità del framework al cambio di
93
tecnologie. In futuro si procederà ad una seria implementazione di ognuno dei
tre driver di comunicazione ed ai rispettivi tests.
94
CONCLUSIONI L’architettura di !CHAOS è stata proposta come un nuovo standard di sistema
di controllo per l’applicazione su infrastrutture di ricerca di media e larga
scala dell‘INFN e vede anche l'interesse di alcune realtà industriali e istituti di
ricerca quali SLAC (Stanford, www.slac.stanford.edu), National Instrument
(www.ni.it), Sidea (http://www.sidea.it).
L’architettura esposta in questa tesi è stata presentata a conferenze
internazionali e pubblicata nei rispettivi proceeding:
• ICALEPCS 2011 (Exploring a New Paradigm for Accelerators and
Large Experimental Apparatus Control Systems) [11];
• IPAC 2011 (High Performance Web Applications for Particle
Accelerator Control Systems) [12].
L’architettura per la gestione dei dati di live e di storico è stata presentata alla
conferenza XLDB 2012 con un poster. Il progetto ha suscitato l’interesse di
quanti, tra i partecipanti, avevano esperienza nei controlli o acquisizione dati
negli esperimenti di fisica nucleare.
Quello che maggiormente ha colpito nella soluzione dello storage di !CHAOS
è stata la scelta di definire una sequenza di chunk (ceppo) come file logico. Di
fatto anche se esistono tecnologie per creare file in grado di contenere enormi
quantità di dati strutturati, HDF5 (http://www.hdfgroup.org) ne è un esempio,
avere un file che può diventare enorme alla fine è comunque sconveniente e
difficilmente gestibile.
HDF5 è un formato di file gestibile tramite un framework che presenta le
seguenti caratteristiche:
• Dimensione illimitata;
• Struttura dei dati definibile dall’utente;
• Gestione dei gruppi e link tra differenti struttura memorizzate nel file;
• Astrazione sullo storage;
• Efficienza
Il problema del HDF5, ma in generale di usare un unico file per tutti i dati
acquisiti da uno strumento, è quello della cancellazione. Nel caso specifico
delle applicazioni previste per !CHAOS il tempo di persistenza dei dati può
95
arrivare a tempi dell’ordine della durata dell’esperimento, tipicamente diversi
anni. È evidente quindi che se si fosse di fronte alla sola necessità di
archiviare dati che mai verranno cancellati, l’HDF5 sarebbe un’ottima
soluzione.
L’uso dei chunk in !CHAOS, dai feedback ricevuti, rappresenta ad ogni modo
un ottimo compromesso per l’ottimizzazione dello spazio (per quei pacchetti
soggetti ad ageing) e semplicità nella memorizzazione e archiviazione per i
dati che non saranno mai eliminati. Ne migliora anche la gestione dell’accesso
ai dati archiviati e non disponibili nell’area di stage (prelevamento
dall’archivio e memorizzazione su filesystem). Comunque, data l’alta
astrazione di !CHAOS sarà possibile implementare lo storage sia mediante
l’uso dell’HDF5 che altre tipologie di file o filesystem.
Altre considerazioni sono state fatte sull’utilità di disporre di API per
regolamentare l’accesso al file virtuale dei device, similmente a come accade
con le api posix di Linux. Sarà quindi previsto lo sviluppo di un client o un di
un libreria software per accedere allo storico di !CHAOS come ad un vero
Filesystem.
La sensazione che si è avuta è comunque quella di un diffuso interesse verso
un approccio nuovo che si affaccia nell’orizzonte del vasto e articolato settore
dei controlli e dell’automazione.
La strada al completamento del progetto passa per alcuni temi non toccati
dalla tesi. Sono stati lasciati fuori differenti punti che, anche se critici,
dipendenti comunque alla parte comune che ad ogni modo è già in fase di
completamento. Lo studio ha evidenziato la necessità di coprire le
funzionalità successivamente descritte.
Controllo esclusivo della strumentazione da parte di uno o più controllori
attraverso l’associazione di uno o più device ad uno o più UI o EU. Questa
condizione risulta essere molto importante dal punto di vista della sicurezza.
La soluzione ipotizzata è quella di costruire tale sicurezza basando la
contestualità su una chiave condivisa e facendo coordinare il processo al
metadata server (MDS) attraverso la seguente sequenza di azioni:
96
• Ogni EU, UI e CU al proprio avvio genera una chiave RSA pubblica e
privata (nel caso non si già stata generata). La pubblica viene inviata
all’MDS che invia ad ognuno di essi la propria.
• Richiesta da parte di un processo di controllo (automatico o manuale)
al metadata server di accesso esclusivo ad uno strumento;
• L’MDS controlla se la richiesta può essere soddisfatta (nessun’altro
già controlla esclusivamente lo strumento richiesto);
• L’MDS genera una chiave casuale ed univoca da inviare sia al device
su cui è stato richiesto l’uso esclusivo e sia al processo che ne ha
richiesta l’esclusività. La chiave generata viene cifrata con la chiave
privata dell’MDS. Prima dell’invio avviene un’ulteriore cifratura con
la chiave pubblica della CU,EU o UI a cui si deve inviare;
• I vari processi ricevono la chiave via RPC, con un comando di sistema
specifico, la decifrano con la propria privata e poi con la pubblica
dell’MDS e impostano questa come chiave di cifratura per i successivi
messaggi da inviare verso le risorse appartenenti al gruppo, cosi
creato, di controllori e strumenti da controllare.
Questa soluzione è simile a quella utilizzata da Kerberos [13]. In questo
contesto però l’obiettivo non è di proteggere i dati (che sono comunque
pubblicati) ma quello di permettere ad una CU di eseguire i soli comandi
ricevuti da processi appartenenti al gruppo di esclusività. Gruppo che
ovviamente potrà vedere i propri membri aumentare o diminuire, il tutto
sempre coordinato dall’MDS con una qualche logica di autorizzazione.
La funzione sopra descritta è, di fatto, l’unica funzione mancante nella parte
common, ogni altra funzione è una composizione di tutte quelle già presenti.
97
BIBLIOGRAFIA [1] Apache Thrift: http://thrift.apache.org/
[2] Apache Avro: http://avro.apache.org/
[3] Google Protobuf: http://code.google.com/p/protobuf/
[4] 10gen BSON: http://bsonspec.org/
[5] F. Sadayuki, http://msgpack.org/
[6] Msgpack RPC. (Sadayuki, F.)
http://wiki.msgpack.org/display/MSGPACK/Design+of+RPC
[7] B. Fitzpatrick, 2003 (LiveJournal) http://memcached.org/
[8] Apache Hadoop: http://hadoop.apache.org
[9] 10Gen MongoDB: www.mongodb.org
[10] ZMQ The Intelligent Transport Layer, http://www.zeromq.org
[11] Bisegni C., Catani L., Zani F., Calabrò, S., Ciuffetti P., Di Pirro G.,
(2011). Exploring a New Paradigm for Accelerators and Large Experimental
Apparatus Control Systems. ICALEPCS2011. Grenoble: ICALEPCS.
[12] Bisegni C., Giovanni M., Ciuffetti P., Di Pirro G., Stecchi A., Calabrò S.,
(2011). High Performance Web Applications for Particle Accelerator Control
Systems. IPAC2011. San Sébastian: IPAC.
98
[13] MIT Kerberos: The Network Authentication Protocol.
http://web.mit.edu/kerberos/