Attualmente ho un'applicazione distribuita che funziona su più PC embedded. L'intera applicazione è composta da un server principale e diversi nodi. Ogni nodo è un PC incorporato che esegue Windows 7 Embedded e ha una CPU dual core con 2 GB di RAM.
L'applicazione (per definizione) funziona solo se il master è attivo e in esecuzione, controllando tutti i nodi. Il server principale ha un database SQL Express in cui conserva informazioni su ogni nodo che si suppone debba controllare e in che modo sono organizzati. I nodi non hanno uno stato persistente.
Una volta che il master e i nodi sono attivi e funzionanti, saranno manipolati e messi in un certo stato che viene mantenuto solo in memoria a questo punto. Il master può essere controllato da un'interfaccia utente del client WinForm che si connette ad esso e può leggere il suo stato e inviare comandi che cambieranno il suo stato (sono fondamentalmente un gruppo di servizi Web esposti utilizzando .NET WCF).
Lo stato tenuto all'interno del master (in memoria) è ciò che conta. Lo stato all'interno di ciascun nodo può essere rigenerato se un nodo viene riavviato ad esempio. Se il master viene riavviato, perde il suo stato corrente (e il nodo dichiara di conseguenza). Ciò significa che dopo un riavvio del server master la configurazione verrà ricaricata e verrà impostato uno stato "fresco".
Tipicamente una configurazione di questa applicazione è composta da un master e 9 nodi (questa è una configurazione 3x3). In qualsiasi momento un nodo può fallire e l'applicazione continuerà senza di essa (a condizione che il master sia attivo). Se il nodo che ha fallito ritorna, il master lo rileva e lo riporta allo stato desiderato.
Mi è stato chiesto di migliorare l'architettura di questa applicazione in modo che il server master possa essere eseguito all'interno di uno dei nodi. Quindi, invece di una configurazione 9 + 1 avremo solo 9 PC embedded con uno scelto come master. Secondo i nostri test l'hardware del nodo ha abbastanza potenza per supportare insieme sia il nodo che il pezzo principale. Tuttavia, il PC integrato non può essere considerato affidabile e fallirà molto più spesso di un normale server che abbiamo usato per ospitare il master fino ad ora.
Per questo motivo mi è stato chiesto di trovare una soluzione di ridondanza. A mio avviso, la soluzione corretta sarebbe quella di inserire due o più embedded in esecuzione nei cluster, quindi se il nodo che esegue il master non funziona, un altro ne assumerà il posto.
Ora, la domanda è: come implementare un cluster leggero che può essere eseguito in quelle condizioni?
Ci sono due problemi principali che devono essere risolti:
- Persistenza dei dati: non solo la configurazione deve essere salvata ma anche lo stato principale. In questo modo quando il nodo master scende un altro nodo può assumere la funzione di master senza reimpostare l'intero stato dell'applicazione.
- Cluster di WCF: in qualsiasi momento, se il nodo master fallisce, un altro deve assumere e tutti i client connessi (l'interfaccia utente del client WinForm) devono essere in grado di riconnettersi automaticamente al nuovo nodo master rieletto. Questo non deve essere veramente trasparente per l'utente, ma i client devono essere in grado di riconnettersi automaticamente (non importa se il nuovo indirizzo IP sarà lo stesso o no).
Ci sono diversi fattori limitanti per una possibile soluzione:
- Non c'è modo di avere una memoria dati condivisa tra i nodi (ogni nodo ha il proprio HD e una rete gigabit privata tra di loro)
- Gli aggiornamenti hardware sono fuori questione
- La soluzione deve essere abbastanza leggera da poter essere eseguita su un PC integrato. Quindi installare un server cloud o un DB cluster probabilmente non sarà abbastanza veloce (se pensi che MySQL cluster funzionerà per risolvere il livello dati, sarò interessato a sentire i tuoi pensieri)
- La soluzione non può implicare l'acquisto di un costoso software
- La piattaforma generale di questa applicazione deve essere basata su Windows
La soluzione migliore che ho pensato finora è stata quella di utilizzare qualcosa come Prevayler per mantenere lo stato master persistente e quindi implementare una sincronizzazione di ogni comando il master ricevuto negli altri nodi. Questo risolverà il problema della persistenza su tutti i nodi (forse qualcosa di simile può essere implementato usando memcache, non ne sono sicuro). Non ho ancora una soluzione per risolvere il problema del servizio WCF.
Poiché ciò comporterà un enorme sviluppo e test adeguati, ho pensato che avrei dovuto ascoltarti prima di implementare qualsiasi cosa.
Penso che una soluzione potrebbe essere messa insieme usando un framework o una sorta di software open source che risolva parte del problema.
Non esitare a chiedere informazioni per migliorare il testo di questa domanda per renderlo più chiaro.