risposta

10

Suppongo che stiate scrivendo un'applicazione di tipo server (lasciamo le app Web per un po '- ci sono alcune buone soluzioni off-shelf che possono esservi d'aiuto, quindi diamo un'occhiata a "ho questo fantastico nuovo tipo di server che ho scritto ", ma voglio che sia un problema di HA).

In un'implementazione del server, le richieste dei client sono in genere (in qualche modo o in un altro) convertite in qualche tipo di evento o tipo di comando e vengono quindi eseguite su una o più code.

Quindi, primo problema - necessità di memorizzare eventi/comandi in modo che sopravviverà nel cluster (. Vale a dire quando un nuovo nodo prende il sopravvento come master, si guarda il prossimo comando che ha bisogno di esecuzione e comincia).

Iniziamo con un unico impl del server filettati (le più facili -.. E concetti continua ad applicarsi al multi-thread, ma la sua ha una propria serie di issues0 Quando un comando è in elaborazione bisogno di una sorta di elaborazione delle transazioni

Un'altra preoccupazione è la gestione degli effetti collaterali e di come gestire il fallimento del comando corrente? Laddove possibile, gestire gli effetti collaterali in modo transazionale, in modo che siano tutto o niente, ad esempio se il comando cambia le variabili di stato, ma si blocca a metà l'esecuzione, essendo in grado di tornare allo stato "precedente", è ottima, consentendo al nuovo nodo master di riprendere il comando interrotto e di eseguire nuovamente il comando.Un buon modo è di rompere gli effetti collaterali in attività più piccole che possono essere nuovamente eseguite su qualsiasi nodo. vale a dire. memorizzare le principali attività di inizio e fine della richiesta, con molte piccole attività che gestiscono dire un solo effetto collaterale per attività.

Questo introduce anche altri problemi che influenzeranno il vostro design. Quelle variabili di stato non sono necessariamente aggiornamenti dei database. Potrebbero essere stati condivisi (ad esempio una macchina a stati finiti per un componente interno) che deve essere anche distribuita nel cluster. Quindi il modello per la gestione delle modifiche in modo tale che il codice master deve visualizzare una versione coerente dello stato di cui ha bisogno e quindi immettere tale stato nel cluster. Usando qualche forma di immutabile (almeno dal thread principale che fa l'aggiornamento) l'archiviazione dei dati è utile. vale a dire. tutti gli aggiornamenti vengono effettivamente eseguiti su nuove copie che devono passare attraverso una sorta di mediatore o facciata che aggiorna solo le copie locali nella memoria con gli aggiornamenti dopo l'aggiornamento attraverso il cluster (o il numero minimo di membri nel cluster per la coerenza dei dati).

Alcuni di questi problemi sono presenti anche per i sistemi di controllo master.

anche bisogno di una buona gestione degli errori, come il numero di cose che possono andare male sugli aumenti aggiornamento di stato (come lei ha la rete ora coinvolti).

Uso molto lo schema di stato. Invece di aggiornamenti di una riga, per gli effetti collaterali che si desidera inviare richieste/risposte e utilizzare fsm specifici della conversazione per tenere traccia dell'avanzamento.

Un altro problema è la rappresentazione dei punti finali. vale a dire. il client connesso al nodo principale deve essere in grado di riconnettersi al nuovo master e quindi ascoltare i risultati? O semplicemente annulli tutti i risultati in sospeso e permetti ai clienti di inviare nuovamente? Se si consente l'elaborazione di richieste in sospeso, è necessario un buon modo per identificare gli endpoint (client) (ad esempio una sorta di ID client in una ricerca).

anche bisogno di pulizia del codice, ecc (cioè. Non vogliono i dati in attesa di un client ricollegarsi ad aspettare per sempre).

Vengono utilizzate molte code. Molte persone useranno quindi un bus di messaggi (jms dicono per java) per spingere gli eventi in modo transazionale.

Terracotta (di nuovo per Java) risolve molto questo per voi - basta aggiornare la memoria - la terracotta è la vostra facciata/mediatore qui. Hanno appena iniettato gli aspetti per il tuo.

Terracotta (io non lavoro per loro) - introduce il concetto di "super-statica", in modo da ottenere questi single ampia a grappolo che sono fresco, ma basta essere consapevoli di come questo influenzerà il test e lo sviluppo del flusso di lavoro - es. usa molta composizione, invece dell'eredità di implementazioni concrete per un buon riutilizzo.

per le applicazioni web - un buon assistente di app può aiutare con la sessione di replica variabile e un buon opere di bilanciamento del carico. In qualche modo, l'utilizzo di questo tramite un REST (o il metodo di scelta del servizio web scelto) è un modo semplice per scrivere un servizio multi-thread. Ma avrà implicazioni sulle prestazioni. Di nuovo dipende dal tuo dominio del problema.

I messaggi (ad esempio jms) vengono spesso utilizzati per introdurre un accoppiamento lento tra diversi servizi. Con un server di messaggi decente, puoi fare un sacco di routing dei messaggi (di nuovo apache cammello o simili fa un ottimo lavoro). dire un consumatore appiccicoso contro un gruppo di produttori di jms ecc. che può anche consentire un buon failover. L'ecc della coda Jms può fornire un modo semplice per distribuire i cmd nel cluster, indetto da master/slave. (di nuovo dipende da se si sta facendo LOB o si scrive un server/prodotto da zero).

(se ho tempo dopo mi riordinare, forse mettere un po 'più in dettaglio nella correzione ortografia grammatica ecc)

-6

L'alta disponibilità riguarda più la disponibilità e la ridondanza dell'hardware rispetto alle convenzioni di codifica. Ci sono un paio di schemi che utilizzerei in quasi tutti i casi di HA: sceglierei il modello singleton per il mio oggetto di database e utilizzare il modello di fabbrica per creare il singleton. La fabbrica può quindi avere la logica per gestire i problemi di disponibilità con il database (che è dove si verificano più problemi di disponibilità). Ad esempio, se il master è inattivo, connettersi a un secondo master per entrambe le letture e le scritture fino a quando il master non è tornato. Non so se questi sono i modelli più sfruttati, ma sono i più sfruttati del mio codice.

Naturalmente questa logica può essere gestita in un metodo __construct, ma uno schema di fabbrica consente di controllare meglio il codice e la logica decisionale su come gestire i problemi di connettività del database. Una fabbrica ti consentirà anche di gestire meglio il modello singleton.

avrei assolutamente evitare il modello decoratore, e il pattern osservatore. Entrambi creano complessità nel codice che ne rende difficile la manutenzione. Sono casi in cui questi sono la scelta migliore per le vostre esigenze, ma la maggior parte delle volte non lo sono.

2

Sbagliato:

... e ci sarà un server di archiviazione

Buono:

... e ci sarà una fattoria di stoccaggio (multipla) server con (più) bilanciatori di carico davanti loro

  • Mettere bilanciatori di carico di fronte a tutto. Per ora puoi avere 4 backend, ma in futuro puoi averne 400, quindi è consigliabile gestirlo solo su LB, non su tutte le app che usano il backend.

  • Utilizzare più livelli di cache.

  • Cercare soluzioni popolari su eccesso di velocità (memcached per esempio).

  • Se si intende rinnovare un sistema, eseguirlo part-by-part in più passaggi. Se lo fai in un grande passo (spegni quello vecchio, accendi quello nuovo e prega che funzioni), molto probabilmente fallirà.

  • Usa nomi DNS per roba, per esempio. storage-lb.servicename risolve gli indirizzi di tutti i loadbalancer di memorizzazione. Se vuoi aggiungerne uno, modifica semplicemente il DNS, tutti i servizi inizieranno ad usarlo automaticamente.

  • Mantenerlo semplice. Più sistemi dai quali dipendi, più il tuo servizio ne risentirà.

5

Un approccio per la creazione di software affidabile è crash-only software:

Crash-solo il software è un software che blocca in modo sicuro e recupera rapidamente. L'unico modo per fermarlo è bloccarlo e l'unico modo per avviarlo è quello di recuperare. Un sistema solo per arresto anomalo è composto da componenti solo per arresto anomalo che comunicano con richieste ripetibili; i guasti vengono gestiti bloccando e riavviando il componente difettoso e riprovando eventuali richieste scadute. Il sistema risultante è spesso più robusto e affidabile perché il ripristino di emergenza è un cittadino di prima classe nel processo di sviluppo, piuttosto che un ripensamento, e non è più necessario il codice aggiuntivo (e interfacce e bug associati) per l'arresto esplicito. Tutto il software dovrebbe essere in grado di bloccarsi in modo sicuro e recuperare rapidamente, ma il software solo per crash deve avere queste qualità, o la loro mancanza diventa rapidamente evidente.

1

Come ho capito, stai cercando modelli specifici da utilizzare nelle applicazioni java parte di un'architettura HA. Ovviamente esiste un numero elevato di schemi e best practice che possono essere utilizzati, ma questi non sono in realtà "schemi HA". Piuttosto, sono buone idee che possono essere utilizzate nei contesti delle persone.

Credo che quello che sto cercando di dire è questo: un'architettura ad alta disponibilità è composta da numerose piccole parti. Se prendiamo una di queste piccole parti e le esaminiamo, probabilmente scopriremo che non ci sono attributi magici di HA per questo piccolo componente. Se esaminiamo tutti gli altri componenti troveremo la stessa cosa. È quando sono combinati in un modo intelligente che diventa un'applicazione HA.

Un'applicazione HA è un'applicazione in cui si pianifica il peggio dall'inizio. Se si pensa in termini di "Questo componente è così stabile che non abbiamo bisogno di ridondanza aggiuntiva per esso" probabilmente non è un'architettura HA. Dopotutto, è facile gestire gli scenari problematici che prevedi. È quello che ti sorprende che abbatte il sistema.

Nonostante tutto ciò, esistono schemi particolarmente utili nei contesti HA. Molti di loro sono documentati nel classico libro "Patterns of Enterprise Application Architecture" di Martin Fowler.

4

mi consiglia di avere una lettura di Release it! da Michael Nygard. Descrive una serie di anti-pattern che influiscono sui sistemi di produzione e schemi per aiutare a prevenire che un componente errante prenda tutto il sistema. Il libro copre tre aree principali; Stabilità, capacità e progettazione generale (copertura di reti, sicurezza, disponibilità e amministrazione).

Il mio posto di lavoro precedente è stato morso (in un momento o un altro) da quasi ogni singolo scenario di fallimento Nygard delinea (con perdita di entrate per ogni interruzione risultante). L'implementazione di alcune delle tecniche e dei modelli suggeriti ha portato a sistemi significativamente più stabili e prevedibili (e sì, il libro è un po 'Java centrico, ma i principi sono applicabili in molti contesti).

+0

Accetto. Ottimo libro! –

2

Progettazione di sistemi ad alta disponibilità (HA) è un'area di ricerca e sviluppo attiva. Se guardi ACM o IEEE, ci sono una tonnellata di articoli di ricerca sulle qualità del servizio (disponibilità, affidabilità, scalabilità, ecc.) E su come raggiungerli (accoppiamento libero, adattamento, ecc.). Se cerchi più applicazioni pratiche, dai un'occhiata ai sistemi fault-tolerant e al middleware che è stato creato per consentire funzionalità di clustering, grid o cloud.

La replica e il bilanciamento del carico (a.k.a. proxy inverso) sono alcuni dei modelli più comuni di realizzazione dei sistemi HA e possono spesso essere eseguiti senza apportare modifiche al software sottostante presupponendo che non sia troppo strettamente accoppiato. Anche molte delle recenti offerte cloud sono realizzate essenzialmente attraverso la replica e il bilanciamento del carico, sebbene tendano a creare elasticità per gestire vaste gamme di richieste del sistema.

Rendere stateless i componenti software facilita l'operazione di replica, poiché lo stato stesso non deve essere replicato insieme ai componenti software. L'apolidia è uno dei motivi principali per cui HTTP si adatta in modo ottimale, ma spesso richiede che le applicazioni aggiungano il proprio stato (ad esempio sessioni), che deve quindi essere replicato.

Pertanto, è più semplice rendere i sistemi con accoppiamento lento altamente disponibili rispetto ai sistemi strettamente accoppiati. Poiché l'affidabilità dei componenti del sistema determina l'affidabilità complessiva del sistema, potrebbe essere necessario sostituire componenti inaffidabili (guasti hardware, bug del software, ecc.). Consentendo un adattamento dinamico in fase di esecuzione, questi componenti guasti possono essere sostituiti senza influire sulla disponibilità dell'intero sistema. L'accoppiamento lento è un'altra ragione per l'utilizzo di sistemi di messaggistica affidabili in cui non è necessario che il mittente e il destinatario siano disponibili contemporaneamente, ma il sistema stesso è ancora disponibile.

1

sto interpretando "High Availability" come "Zero Downtime" `, che può essere implementato come da altra domanda SE:

Zero downtime deployment for Java apps

  1. A/B switch: (Rolling upgrade + Fallback mechanism)
  2. Implementazione parallela - Apache Tomcat: (per l'app Web solo licazioni) vincolante
  3. porta avanzata vincolante

userò alcuni di questi concetti a venire con modelli di progettazione per il sistema High Availability dal punto di vista software, che complimenta sopra approcci

  • porta ritardata.

    modelli da utilizzare:

    Proxy/Factory:

    Avere un oggetto proxy e proxy decidere dove reindirizzare le richieste. Si supponga di disporre della versione 1 & Versione 2 del software. Se i client si connettono con il vecchio protocollo, reindirizzarli al software Versione 1. I nuovi client possono connettersi direttamente alla versione 2. Il proxy può avere il metodo Factory o AbstractFactory per rendere la nuova versione del software.

    Strategy

    È possibile modificare l'algoritmo in fase di esecuzione selezionando un algoritmo da una famiglia di algoritmi. Se si utilizza l'esempio delle compagnie aeree, è possibile alternare tra gli algoritmi DiscountFare e NormalFare durante i mesi di traffico Non-peak e Peak.

    Decorator:

    È possibile modificare il comportamento dell'oggetto in fase di esecuzione. Aggiungi una nuova classe e declina ulteriori responsabilità.

    Adapter:

    Utile quando si cambia interfaccia o contratto tra l'adattatore versione 1 e 2. risponderà ad entrambe le vecchie & nuove richieste dei client in modo appropriato.

    linee guida generali:

    1. allentato l'accoppiamento tra gli oggetti
    2. Segui S.O.L.I.D principi nell'applicazione

    Fare riferimento al sito web sourcemaking articoli per i modelli di cui sopra per una migliore comprensione.

    Cosa non utilizzare:

    Oltre a modelli di progettazione, è necessario prendere alcune precauzioni per raggiungere lo zero downtime per l'applicazione.

    1. Non introdurre un unico punto di fallimenti nel sistema.
    2. Utilizzare le cache distribuite (ad esempio Terracotta)/le serrature con parsimonia.
    3. Rimuovere l'accoppiamento rigido tra i servizi. Rimuovere l'accoppiamento stretto tra i servizi utilizzando bus/framework di messaggistica (JMS, ActiveMQ ecc.)
  • Problemi correlati