Massive Software Simulator Architecture [chiuso]

4

Sto cercando di eseguire una revisione completa su un complesso sistema di simulazione che simula diverse istanze di diversi modelli di veicoli in un ambiente di formazione in classe. Ad esempio, 24 studenti potrebbero eseguire simulazioni su tre diversi veicoli per la manutenzione e il funzionamento. Gli istruttori dovranno disporre di tablet in grado di connettersi a una delle 24 simulazioni attive per controllare lo scenario di allenamento.

Il sistema principale sarà eseguito su Linux ma non ci sono altri requisiti per OS e le specifiche della macchina possono essere costruite secondo necessità. Le prestazioni di ogni passaggio simulato devono essere in grado di funzionare costantemente a intervalli di ~ 10 ms con una tolleranza di + -2 ms.

L'obiettivo principale è rendere questo sistema molto modulare in modo che possa essere esteso e riutilizzato da altre strutture di formazione con veicoli e bisogni unici.

Il mio pensiero era di usare un'architettura a strati (sistema, azienda, interfaccia utente). La definizione di ciascun modello di veicolo può essere memorizzata in un database e quindi modificata indipendentemente da un superutente (modularità / estensibilità dei veicoli). Ogni livello dovrebbe leggere questo database per allocare dinamicamente le risorse richieste da quel particolare layer.

Inizialmente pensavo di utilizzare la memoria condivisa per il livello di sistema, impostando le autorizzazioni e l'autenticazione per qualsiasi livello aziendale per tentare di accedere. La logica di business di simulazione primaria aggiornerebbe continuamente i dettagli del veicolo in base ai dati attivi. L'interfaccia per l'istruttore avrebbe un server del livello aziendale che si connette a tutti i 24 client e registra anche nel livello di sistema per modificare i parametri di simulazione. Tutti gli input dallo studente e gli output visivi avranno ciascuno un livello aziendale che può accedere anche allo strato del sistema di memoria condivisa. Tutti questi agiscono come applicazioni separate in modo che possano essere rimossi / aggiunti / estesi secondo necessità.

Il problema allora è arrivato quando ho capito che le classi non funzionano bene con la memoria condivisa. Avrei bisogno di serializzare ogni get / set della memoria condivisa in una struttura di memoria piatta. Non avendo ancora lavorato con questa architettura, non sono sicuro che questo piano creerà un grande successo nelle prestazioni. Tecnicamente posso dedicare alcuni core alla logica del livello aziendale principale che esegue la simulazione.

La memoria condivisa con una suite di applicazioni sarebbe un modo appropriato per risolvere questo sistema? Un altro tipo di comunicazione tra processi come i tubi sarebbe più consigliabile della memoria condivisa? Sarebbe meglio mantenere il sistema e la logica aziendale in una singola applicazione e utilizzare semplicemente mutex e cross-threading per garantire le prestazioni? Sto sbagliando tutto questo?

    
posta Gren Meera 07.02.2018 - 17:53
fonte

1 risposta

4

Ho lavorato su esattamente 1 applicazione di simulazione, con requisiti più deboli (cioè dovevamo avere tutto l'aggiornamento 1 / s). Sentitevi liberi di prendere questo con un granello di sale, ma è un posto dove iniziare. Penso che avrete difficoltà a realizzare i vostri obiettivi di temporizzazione con i sistemi operativi azionari. Posso solo evidenziare alcune lezioni apprese:

  • A volte i requisiti sono sovradicati
    • Esempio: hai intervalli di 10ms con attività eseguite in +/- 2ms, potrebbe essere abbastanza buono per avere quella velocità complessiva ma la versione reale è più simile a 100ms con attività svolta in +/- 20ms. Stessa tariffa, ma molto più ragionevole da progettare per.
    • Esempio: probabilmente i tuoi client esterni non hanno gli stessi requisiti quasi in tempo reale della tua applicazione
  • Devi essere in grado di interrompere l'elaborazione in anticipo, o interrompere l'estrazione dalla coda se sei vicino alla fine della finestra o se annulli effettivamente il lavoro esistente
  • A seconda di cosa viene simulato, il modello di attore o un approccio simile potrebbe essere la scelta migliore per il tuo progetto generale

Nella simulazione su cui stavo lavorando, stavamo modellando le comunicazioni con i dispositivi di segnale e le torri e gli effetti dei dispositivi che si muovevano quasi in tempo reale. Considerando il numero di dispositivi che dovevamo simulare non potevamo dedicare un thread completo a ciascun attore (dispositivo e tower), ma potremmo avere un numero finito di thread che lavorano contro il corpus per elaborare i messaggi fino al tempo di simulazione corrente- francobollo.

L'unica cosa che consiglierei è di iniziare con una fondazione stabile e sottoporre a stress la simulazione. Sono quegli stress test che ti costringono a prendere decisioni difficili su dove poter scambiare l'assoluta fedeltà con qualcosa che ti dà lo stesso effetto complessivo. Ti garantisco che nessun utente umano noterà la differenza tra 10ms e 100ms.

Qualsiasi simulazione è un compromesso tra fedeltà al modello di lavoro e qualcosa che lo avvicina.

Inoltre, non prendere le decisioni sulla memoria condivisa rispetto a pipe o socket inizialmente. Concentrati sul comportamento principale.

Qualcosa che sto imparando con alcuni dei miei sforzi più recenti è che a volte un approccio shared nothing fornisce la migliore scalabilità complessiva. Per avere un'idea dell'approccio dei microservizi, si avrebbe un'architettura in cui un servizio di simulazione fornisce l'intero ambiente per gli eventi di cronometraggio ad alta precisione. Il trucco consiste nel partizionare l'ambiente in modo sicuro negli ambienti più piccoli. Questo può essere fatto per veicolo o per spazio aereo.

Abbiamo le seguenti note:

  • Il tuo codice critico soddisfa i requisiti
  • Non tutto ha i requisiti temporali rigorosi (in base ai tuoi commenti sopra e sotto)
  • Le comunicazioni socket sono lente, anche sulla stessa macchina
  • La memoria condivisa può essere complicata e ha ancora costi di serializzazione, ma ti limita a una macchina

Essenzialmente, per far lavorare insieme più nodi di simulazione è necessario pacchettizzare e trasmettere lo stato ai nodi interessati a intervalli regolari. Hai bisogno che quella trasmissione sia veloce e densa . Le opzioni sono:

  • named pipe, abbastanza alta velocità, alta affidabilità
  • Pacchetti UDP, abbastanza veloci, i pacchetti possono essere divisi da router con una dimensione massima sicura di circa 1134 byte di payload.
  • Pacchetti TCP, più lenti, ma molto più affidabili

Le comunicazioni possono essere eseguite in modo asincrono invocando eventi nel nodo ricevente. Nel mio caso abbiamo optato per pacchetti UDP poiché l'intero sistema era destinato ad essere eseguito in una sottorete. Abbiamo anche utilizzato un formato di trasmissione binario come i buffer del protocollo di Google per massimizzare le informazioni per byte.

Nel mio progetto, la maggior parte delle simulazioni potevano essere eseguite su una macchina, ma il software di visualizzazione del sensore veniva tipicamente eseguito in remoto.

In questo caso è stato un trade-off di quanto frequentemente abbiamo aggiornato il sistema esterno e la quantità di dati. Ogni nodo aveva una coppia di socket aperti, uno per l'invio e uno per la ricezione.

Nella maggior parte dei casi siamo riusciti a proiettare matematicamente il nostro movimento con una precisione tale da non consentire l'osservazione delle correzioni di percorso ricevute e la simulazione era ancora valida.

Ma ancora una volta, un approccio come questo deve essere testato rispetto ai criteri conosciuti per il tuo sistema.

    
risposta data 07.02.2018 - 19:09
fonte

Leggi altre domande sui tag