6

So che con Network Load Balancing e Failover Clustering possiamo rendere disponibili i servizi passivi . Ma per quanto riguarda le app attive ?Come rendere i servizi attivi altamente disponibili?

Esempio: una delle mie app recupera del contenuto da una risorsa esterna in un intervallo fisso. Ho immaginato i seguenti scenari:

  1. Eseguirlo in una singola macchina. Problema: se questa istanza cade, il contenuto non verrà recuperato
  2. Eseguirlo in ogni macchina del cluster. Problema: il contenuto verrà recuperato più volte
  3. Avere in ciascuna macchina del cluster, ma eseguirlo solo in una di esse. Ogni istanza dovrà controllare una sorta di risorsa comune per decidere se è il suo turno di fare il compito o meno.

Quando stavo pensando alla soluzione n. 3 mi sono chiesto quale dovrebbe essere la risorsa comune. Ho pensato di creare una tabella nel database, dove potremmo utilizzarla per ottenere un blocco globale.

Questa è la soluzione migliore? Come fa la gente di solito a fare questo?

Tra l'altro si tratta di un WCF un'applicazione C# .NET in esecuzione su Windows Server 2008

risposta

4

Per tali problemi hanno inventato code di messaggi. Immagina il caso in cui tutte le applicazioni in cluster ascoltano una coda di messaggi (cluster in sé :-)). Ad un certo punto nel tempo una istanza ottiene il comando iniziale per scaricare la risorsa esterna. Se ha esito positivo, l'istanza svuota il messaggio e ne inserisce un altro per un tempo di esecuzione successivo uguale a "tempo di esecuzione" + "intervallo". Ma nel caso in cui l'istanza muoia durante l'elaborazione, non è un problema. Il messaggio viene ripristinato nella coda (dopo il timeout) e qualche altra istanza può prenderlo. Un po 'di transazioni, un po' di code di messaggi

io sono sul lato Java EE del mondo in modo può aiutare con i dettagli di codifica

+0

up-vote b/c questo è un buon schema da seguire, tuttavia ritengo che la risposta non sia del tutto applicabile all'OP poiché sta esaminando le opzioni di disponibilità specifiche per NLB e clustering, non per enterprise arch. –

+0

dare un'occhiata al servizio Amazon Simple Queue, è possibile utilizzare un'implementazione simile (o addirittura acquistare il loro servizio). – dwery

0

In alcuni casi le persone trovano utile avere 3 macchine a fare tutto il richieste, quindi confrontare i risultati alla fine, per assicurarsi che il risultato sia assolutamente corretto e che nessun errore hardware abbia causato problemi durante l'elaborazione. Questo è quello che fanno per esempio sugli aeroplani.

In altri casi, è possibile vivere con un unico risultato negativo e un piccolo tempo di inattività per passare a un nuovo servizio, ma solo il prossimo deve essere ok. In tal caso, la soluzione numero 3 con un monitor del battito cardiaco è un'impostazione eccellente.

Altre volte ancora, le persone devono solo essere avvisate con un SMS che il loro servizio è inattivo e l'applicazione utilizzerà solo alcuni dati obsoleti fino a quando non si esegue manualmente un qualche tipo di failover.

Nel tuo caso, direi che quest'ultimo è probabilmente più utile per te. Dal momento che non puoi realmente dipendere dal fatto che il servizio all'altra estremità sia disponibile, dovresti comunque trovare una soluzione per ciò che devi fare in quel caso. Restituire dati obsoleti potrebbe essere ciò che è buono per te, e potrebbe non esserlo. Mi dispiace dover dire: dipende.

+0

Sono già sicuro che la soluzione 3 è quella per me, quello di cui non sono sicuro è il metodo di sincronizzazione. –

+0

La domanda non menziona quale tipo di contenuto viene recuperato, ma è probabilmente un presupposto sicuro che varia con il tempo (es. Quotazioni di borsa) e non ci può essere alcuna garanzia che 3 server che fanno richieste in tempi leggermente diversi riceveranno gli stessi dati . –

+0

@Tuzo nel mio caso i dati vengono aggiornati solo ogni 2 minuti e vengono recuperati una volta ogni 1m50s –

1

Una volta ho implementato qualcosa di simile usando la soluzione # 3.

Creare una tabella chiamata qualcosa come resource_lock, con una colonna (ad es.locking_key) che conterrà una chiave di blocco.

Poi ad ogni intervallo, tutte le istanze della vostra applicazione sarà:

  1. Eseguire una query come 'update resource_lock set resource_key = 1 where resource_key is null'. (puoi anche inserire un ID specifico del server, un timestamp, ecc.)
  2. Se sono state aggiornate 0 righe: non fare nulla: un'altra istanza dell'app sta già recuperando la risorsa.
  3. Se è stata aggiornata 1 riga: recuperare la risorsa e impostare locking_key su null.

ci sono due vantaggi con questo:

  • Se uno dei server non riesce, la risorsa sarà ancora recuperati dai server che sono ancora in corso.
  • Lascia il blocco al database, questo ti impedisce di implementarlo tu stesso.
+0

cosa succede se si verifica un errore durante l'esecuzione del processo? –

+0

Quindi chiedetevi: è realistico aspettarsi che la risorsa venga recuperata con successo quando si prova di nuovo? Se sì: implementare una sorta di meccanismo di ripetizione. Se no: basta saltare e attendere l'intervallo successivo. Immagino che dipenda anche da quanto sia importante che la risorsa venga recuperata ogni volta. –

+0

Stavo chiedendo il valore della riga. Se il processo che lo ha aggiornato a '1' si interrompe, il valore probabilmente rimarrà tale e nessun processo recupererà mai quella risorsa di nuovo. –

1

Dal punto di vista la semplicità, l'/ modo più semplice e veloce per realizzare quello che stai cercando potrebbe essere quella di 'round robin' il cluster in modo che per ogni richiesta, viene selezionata una macchina (da un cluster servizio di gestione o alcuni di questi) per elaborare una richiesta. Le richieste effettive del client non vanno direttamente alla macchina che la gestisce; puntano invece a un singolo endpoint, che funge da proxy per distribuire le richieste in entrata alle macchine in base alla disponibilità e al carico. Per citare il collegamento sottoindicato,

Bilanciamento carico di rete è un modo per configurare un pool di macchine in modo che a turno rispondano alle richieste. È più comunemente visto implementato nelle server farm: macchine configurate in modo identico che distribuiscono il carico per un sito Web o una farm di Terminal Server. Si potrebbe anche usarlo per una farm firewall (ISA), punti di accesso VPN, in realtà, ogni volta che si ha traffico TCP/IP che è diventato troppo carico per una singola macchina, ma si desidera comunque che appaia come una singola macchina per scopi di accesso.

Per quanto riguarda l'applicazione che è "attiva", tale requisito non tiene conto di questa equazione in quanto "attiva" o "passiva", l'applicazione effettua comunque una richiesta ai server.

Esistono servizi di bilanciamento del carico commerciale per servire le richieste in stile HTTP, quindi potrebbe essere utile esaminarlo, ma con le funzionalità di bilanciamento del carico di W2k8, è possibile che sia meglio sfruttarle.

Per ulteriori informazioni su come configurarlo in Win2k8, vedere l'articolo this.

this article è molto più tecnico e si concentra sull'utilizzo di Bilanciamento carico di rete con Exchange, ma i principi dovrebbero ancora essere applicati alla situazione.

see here per un altro dettagliato walk-through di installazione e configurazione NLB.

In caso contrario, si può essere ben serviti da ricerca/pubblicazione su ServerFault, dal momento che il codice dell'applicazione non è (e non dovrebbe essere) strettamente consapevole del fatto che il Bilanciamento del carico di rete esiste anche.

MODIFICA: aggiunto un altro link.

EDIT (il 2 °): L'OP ha corretto la mia conclusione errata nel concetto "attivo" e "passivo".La mia risposta è molto simile alla mia risposta originale, salvo che il servizio 'attivo' (che, dato che stai usando WCF, potrebbe facilmente essere un servizio di Windows) potrebbe essere diviso in due parti: la porzione di elaborazione effettiva e la porzione di gestione. La parte di gestione verrebbe eseguita su un singolo server e fungerà da bilanciamento del carico round robin per gli altri server che eseguono l'elaborazione effettiva. È leggermente più complicato rispetto allo scenario originale, ma credo che fornirebbe una buona dose di flessibilità oltre a offrire una netta separazione tra logica di elaborazione e gestione.

+0

Non hai capito cosa intendevo per attivo. Nello scenario attivo i miei server non avrebbero ricevuto alcuna richiesta. Invece, lo genererebbero. –

+0

mi scuso - aggiornerò la mia risposta per riflettere che –

+0

grazie per il vostro aggiornamento –

1

Ci sono alcuni requisiti che probabilmente conoscete ma non sono stati descritti nella domanda che rende difficile dare una risposta informata. Alcune di queste domande sono:

  • L'attività deve essere completata correttamente?
  • Se l'attività non viene completata correttamente, "chi" deve sapere e quale tipo di azioni devono essere eseguite?
  • Qual è il comportamento se l'attività non è stata completata quando arriva il momento di eseguire di nuovo l'attività? Dovrebbe funzionare o no?
  • Quanto è importante che i lavori vengano eseguiti all'intervallo specificato? Se l'intervallo è ogni 5 minuti, deve essere ogni 5 minuti oppure l'attività può essere eseguita dopo 5 minuti e 10 secondi?

Il primo passo consiste nel rispondere a come verrà pianificata l'attività periodica. Un'opzione è un'attività pianificata di Windows ma che non è intrinsecamente molto disponibile ma potrebbe essere possibile aggirare il problema. Se si utilizza SQL Server, un'altra alternativa sarebbe utilizzare SQL Server Agent come programma di pianificazione poiché eseguirà il failover come parte di SQL Server.

Il passaggio successivo da stabilire è come richiamare l'applicazione WCF. L'opzione più semplice sarebbe attivare un lavoro per richiamare il servizio WCF tramite un indirizzo IP NLB. Questo può essere considerato un no-no se il server del database (o altro server in quella zona) sta chiamando nell'area dell'applicazione (ovviamente ci sono sempre eccezioni come MSDTC).

Un'altra opzione sarebbe utilizzare il modello di coda. Questo sarebbe il più affidabile nella maggior parte delle situazioni. per esempio. SQL Server Agent potrebbe eseguire una stored procedure per immettere un record in una tabella di code. Quindi, su ciascun server delle applicazioni, un servizio può eseguire il polling alla ricerca di un record in coda da elaborare. L'accesso al record in coda verrebbe serializzato dal database in modo che il primo server eseguisse il lavoro (e quel lavoro verrebbe eseguito una sola volta).

A seconda delle risposte alle domande di apertura di questa risposta, potrebbe essere necessario aggiungere ulteriore gestione degli errori. Se il recupero della risorsa esterna è in genere piuttosto breve, è possibile mantenere semplicemente il record della coda bloccato con uno select for update e quando l'attività è completata, aggiornare lo stato (o eliminare il record se lo si desidera). Ciò bloccherà altre istanze di servizio dall'elaborazione del record mentre viene elaborato su un altro server e, se si verifica un arresto anomalo durante l'elaborazione, la transazione dovrebbe essere ripristinata e un altro servizio nel cluster può rilevare il record. (Sebbene sia possibile aumentare il timeout della transazione fino a quando si ritiene necessario.)

Se mantenere un blocco del database per un lungo periodo non è fattibile, è possibile modificare la logica e aggiungere un po 'di monitoraggio ai servizi. Ora, quando un processo viene avviato, il suo stato verrebbe modificato da in coda a in esecuzione e il server che sta elaborando il record verrebbe aggiornato sul record. Potrebbe essere creata una sorta di tabella di stato del servizio e ogni istanza del servizio aggiornerebbe l'ora corrente ogni volta che esegue il polling. Ciò consentirebbe ad altri servizi nel cluster di rielaborare i lavori che mostrano come in esecuzione ma il servizio su cui dovrebbero essere eseguiti non è stato "archiviato" entro un certo periodo.

Questo approccio presenta anche limitazioni: cosa succede se l'attività è stata effettivamente completata ma in qualche modo la connettività del database è stata persa - il lavoro potrebbe potenzialmente essere eseguito di nuovo. Naturalmente, non penso che il problema di avere azioni di database atomico combinate con altre risorse non transazionali (ad es. Richiesta web, file system) possa essere risolto facilmente. Suppongo che tu stia scrivendo un file o qualcosa del genere: se il contenuto esterno viene inserito anche in un database, una singola transazione garantirà che tutto sia coerente.

+0

mi è piaciuto il suggerimento di SQL Server Agent. Sono sicuro che molti RDBMS hanno caratteristiche simili. –

0

Zookeeper è un buon esempio di blocco distribuito. Zookeeper ha z-nodi che sono come directory con dati.

Anche il curatore di netflix ha molte ricette già fatte e da usare. Ad esempio: elezioni dei leader, blocco distribuito e molti altri.

Penso che abbiamo client di guardiano per C#. Dovresti assolutamente provare questa opzione. # Option3

Problemi correlati