Dovremmo progettare programmi per uccidersi a caso? [chiuso]

76

In breve, dovremmo progettare la morte nei nostri programmi, processi e thread a un livello basso, per il bene del sistema generale?

Gli errori accadono. I processi muoiono. Pianifichiamo il disastro e occasionalmente ci riprendiamo. Ma raramente progettiamo e implementiamo la morte del programma imprevedibile. Speriamo che i tempi di attività dei nostri servizi siano lunghi quanto ci preoccupiamo di mantenerli in esecuzione.

Un esempio di macro di questo concetto è Scimmia del caos di Netflix. , che termina casualmente le istanze AWS in alcuni scenari. Affermano che questo li ha aiutati a scoprire i problemi e creare sistemi ridondanti.

Quello di cui sto parlando è il livello più basso. L'idea è che i processi tradizionalmente di lunga durata escano casualmente. Ciò dovrebbe forzare la ridondanza nella progettazione e, in definitiva, produrre sistemi più resilienti.

Questo concetto ha già un nome? È già in uso nel settore?

Modifica

Sulla base dei commenti e delle risposte, temo di non essere stato chiaro nella mia domanda. Per chiarezza:

  • Sì, intendo a caso,
  • sì, intendo in produzione e
  • no, non solo per i test.

Per spiegare, mi piacerebbe disegnare un'analogia con gli organismi multicellulari.

In natura, gli organismi sono costituiti da molte cellule. Le celle si forzano per creare ridondanza e alla fine muoiono. Ma dovrebbero esserci sempre cellule sufficienti dei tipi giusti per il funzionamento dell'organismo. Questo sistema altamente ridondante facilita anche la guarigione quando feriti. Le cellule muoiono così l'organismo vive.

Includere la morte casuale in un programma costringerebbe il sistema più grande ad adottare strategie di ridondanza per rimanere redditizia. Queste stesse strategie potrebbero aiutare il sistema a rimanere stabili di fronte ad altri tipi di errori imprevedibili?

E, se qualcuno ha provato questo, come si chiama? Mi piacerebbe saperne di più se esiste già.

    
posta jimbojw 25.06.2013 - 01:18
fonte

16 risposte

60

No.

Dovremmo progettare una corretta gestione dei percorsi non validi e progettare casi di test (e altri miglioramenti di processo) per convalidare che i programmi gestiscono bene queste condizioni eccezionali. Stuff come Chaos Monkey può farne parte, ma non appena fai "crash casualmente", un requisito dei crash casuali veri e propri diventano cose che i tester non possono archiviare come bug.

    
risposta data 22.06.2013 - 17:37
fonte
19

Il processo di introduzione di difetti nel software o nell'hardware per testare i meccanismi tolleranza agli errori è chiamato iniezione predefinita .

Da Wikipedia:

The technique of fault injection dates back to the 1970s when it was first used to induce faults at a hardware level. This type of fault injection is called Hardware Implemented Fault Injection (HWIFI) and attempts to simulate hardware failures within a system. The first experiments in hardware fault injection involved nothing more than shorting connections on circuit boards and observing the effect on the system (bridging faults). It was used primarily as a test of the dependability of the hardware system. Later specialised hardware was developed to extend this technique, such as devices to bombard specific areas of a circuit board with heavy radiation. It was soon found that faults could be induced by software techniques and that aspects of this technique could be useful for assessing software systems. Collectively these techniques are known as Software Implemented Fault Injection (SWIFI).

    
risposta data 22.06.2013 - 19:56
fonte
9

Sì. No. Forse.

La terminazione periodica è un'arma a doppio taglio. Stai per essere colpito da un lato o dall'altro, e quale è il minore di due mali dipende dalla tua situazione.

Un vantaggio è l'affidabilità: se imponi la fine del programma in modo casuale (o prevedibile) e in modo ordinato, puoi essere preparato per quell'evento e affrontarlo. Puoi garantire che il processo uscirà quando non è occupato altrimenti a fare qualcosa di utile. Ciò garantisce anche che i bug che si manifesterebbero oltre il tempo di esecuzione sanzionato non aumenteranno la produzione delle loro brutte teste, il che è una buona cosa. Apache HTTPD ha un'impostazione che ti permetterà di mettere a punto quante richieste un processo figlio (o thread in versioni più recenti) verranno pubblicate prima di terminare.

L'altro vantaggio è anche l'affidabilità: se non permetti al programma di funzionare a lungo, non troverai mai bug che si manifestano nel tempo. Quando finalmente si imbattono in uno di questi bug, è molto più probabile che il programma restituisca una risposta errata o non ne restituisca affatto uno. Peggio ancora, se si eseguono molti thread con lo stesso lavoro, un bug indotto dal tempo o dal conteggio potrebbe influire su un numero molto grande di attività tutte in una volta e comportare tutto il viaggio di un 3 in ufficio.

In un'impostazione in cui si eseguono molti thread uguali (ad esempio, su un server Web), la soluzione pratica consiste nel prendere un approccio misto che si traduca in un tasso di errore accettabile. Se si eseguono 100 thread, l'esecuzione di un rapporto breve-lungo di 99: 1 significa che solo uno mostrerà bug a lungo termine mentre gli altri continueranno a fare qualsiasi cosa facciano senza fallire. Confrontalo con una corsa lunga al 100%, dove corri un rischio molto più elevato di avere tutti i thread falliti allo stesso tempo.

Dove hai un singolo thread, probabilmente è meglio lasciarlo girare e fallire, perché il tempo morto durante il riavvio può causare latenze indesiderate quando c'è del lavoro da fare che si completerebbe con successo.

In entrambi i casi, è importante che ci sia qualcosa che supervisiona i processi in modo che possano essere riavviati immediatamente. Inoltre, non esiste una legge che dica che le tue decisioni iniziali sulla durata di esecuzione di un processo debbano essere gettate nella pietra. La raccolta di dati operativi ti aiuterà a ottimizzare il tuo sistema per mantenere i guasti fino a un livello accettabile.

Suggerirei di non eseguire la terminazione casuale, poiché ciò rende più difficile individuare i bug correlati al tempo. Chaos Monkey fa in modo che il software di supervisione funzioni, il che è un problema leggermente diverso.

    
risposta data 22.06.2013 - 19:09
fonte
9

Intendi veramente casuale? Avere il tuo software in modo casuale uccidersi sembra una pessima idea. Che cosa servirebbe?

Immagino che quello che intendi sia che dovremmo essere realistici sui thread / processi di lunga durata e accettare che più a lungo corrono, più è probabile che abbiano incontrato una sorta di bug nascosto e siano entrati in un stato non funzionale. Quindi, come misura puramente pragmatica, la durata dei processi e dei thread dovrebbe essere limitata.

Credo che alla fine degli anni '90 il server web Apache usasse qualcosa del genere. Avevano un pool di processi di lavoro (non thread) e ogni processo di lavoro sarebbe stato ucciso dopo una vita fissa. Ciò impediva al server di essere monopolizzato da processi di lavoro che erano rimasti bloccati in uno stato patologico.

Non ho lavorato nell'area per un po 'di tempo, quindi non so se questo è ancora il caso.

    
risposta data 22.06.2013 - 19:18
fonte
7

Il problema che vedo è che se un tale programma muore, diremo semplicemente "Oh, è solo un'altra terminazione casuale, niente di cui preoccuparsi". Ma cosa succede se c'è un problema reale che deve essere risolto? Sarà ignorato.

I programmi già "casualmente" falliscono a causa degli sviluppatori che creano mystaykes, bug che si trasformano in sistemi di produzione, guasti hardware, ecc. Quando questo si verifica, vogliamo saperlo in modo che possiamo ripararlo. Progettare la morte in programmi aumenta solo la probabilità di fallimento e ci costringerebbe solo ad aumentare la ridondanza, che costa denaro.

Non vedo nulla di sbagliato con i processi di uccisione casuali in un ambiente di test quando si verifica un sistema ridondante (questo dovrebbe accadere più di quanto non sia) ma non in un ambiente di produzione. Potremmo estrarre un paio di dischi rigidi da un sistema di produzione live ogni pochi giorni o disattivare uno dei computer su un aereo mentre sta volando pieno di passeggeri? In uno scenario di test - bene. In uno scenario di produzione dal vivo - preferirei di no.

    
risposta data 23.06.2013 - 11:09
fonte
4

L'aggiunta di codice di uscita casuale all'applicazione non dovrebbe essere necessaria. I tester possono scrivere script che uccidono in modo casuale i processi dell'applicazione.

In rete, è necessario simulare una rete inaffidabile per il collaudo di un'implementazione del protocollo. Questo non viene integrato nel protocollo; può essere simulato a livello di driver di periferica o con un hardware esterno.

Non aggiungere codice di prova per il programma per situazioni che possono essere raggiunte esternamente.

Se è destinato alla produzione, non posso credere che sia serio!

Prima di tutto, a meno che i processi non abbandonino in modo repentino in modo che le transazioni in corso e i dati volatili vengano persi, non si tratta di una implementazione onesta del concetto. Le uscite pianificate e aggraziate, anche se a tempo determinato, non aiutano in modo adeguato a preparare l'architettura per gestire i crash reali, che non sono graziosi.

Se nell'applicazione sono incorporati malfunzionamenti reali o realistici, potrebbero causare danni economici, proprio come i veri malfunzionamenti e un danno economico intenzionale è fondamentalmente un atto criminale quasi per definizione.

Potresti essere in grado di superare le clausole contenute nel contratto di licenza che esonerano la responsabilità civile da qualsiasi danno derivante dal funzionamento del software, ma se tali danni sono dovuti alla progettazione, potresti non essere in grado di rinunciare alla responsabilità penale.

Non pensare nemmeno ad acrobazie come questa: falla funzionare nel modo più affidabile possibile e inserisci scenari di errori fasulli solo in configurazioni speciali o configurazioni.

    
risposta data 25.06.2013 - 00:10
fonte
3

Potresti cercare " recupero proattivo " e " ringiovanimento " nel contesto di sistemi distribuiti a tolleranza d'errore, per far fronte a errori arbitrari (es. solo processi bloccati, ma dati corrotti e anche comportamenti potenzialmente dannosi). C'è stata molta ricerca su quanto spesso e in quali condizioni un riavvio (in senso astratto, potrebbe essere effettivamente una VM o un host). Intuitivamente, puoi capire i vantaggi dell'approccio come preferendo affrontare un processo morto piuttosto che con un processo di tradimento ...

    
risposta data 23.06.2013 - 15:21
fonte
2

Questo non è molto diverso dal test. Se stai progettando una soluzione di failover sempre disponibile (come Netflix), allora sì - dovresti testarla. Non so che le uscite casuali sparse per tutto il codice base siano un modo appropriato per testarlo, però. A meno che tu non sia davvero intenzionato a testare che il tuo design è resiliente a spararti nel piede, sembrerebbe più appropriato testarlo manipolando l'ambiente attorno al codice e verificando che si comporti in modo appropriato. / p>

Se non stai progettando sistemi ridondanti, allora no - non dovresti aggiungere quella funzione perché hai aggiunto delle uscite casuali. Dovresti semplicemente rimuovere le uscite casuali, e quindi non avrai questo problema. Il tuo ambiente potrebbe non funzionare ancora, a quel punto lo cancellerai come non supportato / non risolto o indurirai il tuo codice contro quell'errore e aggiungerai un test per questo. Fatelo abbastanza spesso e vi renderete conto che in realtà state progettando un sistema ridondante - guardate lo scenario # 1.

A un certo punto, potresti decidere di non essere più sicuro di quali guasti sono o non sono gestiti. Ora puoi iniziare a estrarre casualmente il tappeto per rilevare i punti di errore.

L'unica cosa interessante dell'esempio di Netflix è che eseguono questi test in produzione. Questo ha un certo senso: alcuni bug sono in realtà solo delle cose che sono molto difficili o impossibili da simulare in un ambiente isolato. Sospetto che Netflix abbia passato molto tempo in ambienti di test prima che fossero abbastanza comodi da farlo in produzione. E in realtà tutto ciò che stanno facendo è cercare di ottenere arresti anomali durante l'orario di lavoro, il che ha un certo senso per il loro mercato ma non per molti altri.

    
risposta data 22.06.2013 - 19:38
fonte
2

Il termine che stai cercando è stato recentemente coniato da Nassim Nicholas Taleb: Antifragility. Il suo libro Antifragile è decisamente raccomandato. Cita a malapena l'IT, ma i paralleli ovvi e chiari sono molto stimolanti. La sua idea è di estendere la scala della fragile < - > robusto a fragile < - > robusto < - > antifragile. Rotture fragili con eventi casuali, gestioni solide con eventi casuali e guadagni anti-fragili con eventi casuali.

    
risposta data 10.07.2013 - 14:18
fonte
1

Dipende. Ho notato che i programmatori tendono a generalizzare eccessivamente le tecniche che si applicano al loro dominio specifico ignorando tutti gli altri. Per esempio ottenere programmi rilasciati al costo di riparare tutti i bug può essere buono ... a meno che non si programmino controllori aeronautici, reattori nucleari, ecc. "Non ottimizzare - il costo del programmatore è maggiore del costo del programma in esecuzione" non è necessario valido per HPC in quanto un programma relativamente semplice può occupare cluster per mesi ecc. (o anche un programma popolare utilizzato da una grande quantità di utenti). Quindi, anche se la società X sta facendo Y per una buona ragione, non è necessario seguire le loro orme perché la situazione potrebbe essere diversa.

Di solito le routine di gestione degli errori sono la parte più testata del codice - mentre sembra semplice è difficile simulare che ci sia memoria insufficiente o che alcuni file importanti non ci siano. Per questo motivo ho letto testi che proponevano che il kernel Unix fallisse casualmente alcune chiamate di sistema. Tuttavia, sarebbe più difficile scrivere programmi semplici (se ho bisogno di collegare 3 librerie C ++ insieme per eseguire un programma su 2 file una volta che non voglio preoccuparmi di gestire gli errori). Anche con eccezioni, GC devi assicurarti di aver lasciato uno stato coerente dietro (immagina l'eccezione a metà dell'aggiunta del nodo all'elenco collegato).

Maggiore è il numero di servizi distribuiti e più i fallimenti sono la domanda "quanto frequente", quindi "se" o "quando". Nei data center la sostituzione del disco in RAID fa parte delle operazioni di routine da quello che so - non un errore inaspettato. Se operi su larga scala, devi tenerne conto perché anche se la probabilità di fallimento di un componente è piccola, è probabile che qualcosa fallirà.

Non so cosa stai facendo esattamente, ma per sapere se ne vale la pena, devi pensare se il fallimento è qualcosa che devi prendere in considerazione (come ignorarlo) o è qualcosa di troppo costoso da analizzare ( come tenere conto degli errori nel tempo di sviluppo dei costi).

    
risposta data 22.06.2013 - 21:24
fonte
1

Il server IIS ha una funzione configurabile che ricicla automaticamente i processi di lavoro sia dopo che hanno usato una certa quantità di memoria o dopo aver servito un certo numero di richieste o dopo essere stati in vita per un periodo specificato. ( link ) e ( collegamento )

Quando un CONTAINER come IIS lo fa, ha senso proteggere il server da processi anomali. Tuttavia, preferirei tenerlo disattivato, perché non ha senso se il codice è stato testato a sufficienza.

Lavoriamo già su livelli inaffidabili (hardware, rete), quindi non scriverei mai codice che uccida casualmente i suoi thread o processi intenzionalmente. Anche l'omicidio casuale è una cattiva idea dal punto di vista economico: nessuno userebbe la mia API se pensasse che l'ho programmata per bloccarla in modo casuale. Infine, se dovessi consumare un'API o utilizzare un sistema con thread che si bloccano casualmente, dovrei spendere un sacco di soldi per creare un meccanismo di monitoraggio sufficientemente robusto per poter dormire serenamente durante la notte.

Invece, se sviluppassi un sistema o un'API, scriverei degli script o userei un'imbracatura che farebbe questo solo per mettere alla prova la capacità di recupero del sistema. E farei un test di questo tipo su tutte le build per identificare build scadenti. Tuttavia, mentre questo sarebbe un test necessario, non potrebbe mai essere un test "sufficiente".

    
risposta data 10.07.2013 - 12:54
fonte
1

C'è una letteratura legata a questa idea, si chiama software Crash-Only (anche Recovery Oriented Computing) e puoi iniziare con questa carta usenne di Candea & Fox del 2003. Piuttosto che uccisioni casuali, l'autore sostiene che è possibile migliorare l'affidabilità del sistema arrestando solo i programmi uccidendoli, quindi con un singolo kill switch come pulsante di spegnimento e un singolo percorso di avvio ben esercitato per il ripristino.

Anche se non sono sicuro di quanto l'idea sia stata presa, alcune delle tecniche specifiche rimangono utili. Ad esempio, non fidarsi del fatto che il proprio software sia in grado di spegnersi quando richiesto e quindi utilizzare programmi di supervisione specializzati (ad es. Supervisord ecc.), E anche riflettere attentamente su quale stato del programma è essenziale e assicurarsi che sia registrato in momenti appropriati in un data store progettato per abilitare il recupero (ad es. un database sql).

    
risposta data 27.07.2013 - 21:46
fonte
1

Davvero a caso, no. Ma probabilmente è una buona idea che processi / thread di lunga durata escano / riavviano a un determinato intervallo o dopo essere stati inattivi per una determinata durata (o dipendente da determinati criteri) o dopo aver eseguito un particolare tipo di attività. I processi a lungo termine si accumulano inevitabilmente e includono cose vecchie, possono presumibilmente aggrapparsi alla memoria impedendo lo spazio di swap da rilasciare, che viene (o dovrebbe essere) ripulito quando escono, migliorando la stabilità generale del sistema.

    
risposta data 28.07.2013 - 10:33
fonte
1

Dipende dal tipo di applicazione che stai progettando.

Gli arresti anomali casuali sono un ottimo modo per testare e migliorare la robustezza dei sistemi distribuiti (collegati in rete).

Nell'esempio di Netflix, quando il tuo programma dipende da servizi remoti che possono fallire per una serie di motivi fuori dal tuo controllo (l'hard disk va male, la perdita di energia, i crash di meteore nel data center, ecc.). Il tuo servizio deve comunque continuare a funzionare in qualche modo.

Come si fa? Aggiungere ridondanza e ridimensionamento è una soluzione comune.

Ad esempio, se un mouse mastica il cavo di alimentazione del server, il servizio dovrebbe avere qualche soluzione per continuare a funzionare. Ad esempio, può mantenere i server di backup ridondanti che verrà utilizzato al suo posto.

Tuttavia, se il tuo programma è una singola applicazione di processo che non funziona in una rete, quindi averla uccisa non testerà nulla poiché non c'è modo di recuperare da quella.

Ecco alcuni commenti in più sul concetto di Chaos Monkeys link

    
risposta data 30.07.2013 - 02:28
fonte
1

È possibile che un capovolgimento casuale dei bit avvenga a causa di radiazione cosmica . Questo problema è stato riconosciuto e le varie tecniche sono state sviluppate per impedire che il bit flipping si verifichi.

Tuttavia, non è possibile correggerlo al 100% e la corruzione della memoria può ancora causare problemi e questi problemi stanno ancora accadendo ( con probabilità molto bassa ).

Ora per rispondere alla tua domanda. Indipendentemente dal fatto che sia necessario progettare un sistema molto robusto, dipende da ciò che si sta facendo. Se hai bisogno di creare una navicella spaziale, è meglio renderla super robusta, e quindi dovrai prendere in considerazione ogni possibile problema.

Se hai bisogno di progettare una normale applicazione desktop, dovresti esaminare i crash casuali come bug nel tuo codice.

    
risposta data 02.08.2013 - 09:16
fonte
0

Questo non sembra un'idea assurda.

Il sistema operativo Android uccide e riavvia in modo casuale tutte le app / servizi utente in ogni momento. Nella mia esperienza mi ha sicuramente aiutato a riflettere più a fondo sulle condizioni di errore, oltre a progettare architetture più robuste.

    
risposta data 22.06.2013 - 21:40
fonte

Leggi altre domande sui tag