Aggiornamento di un'app Web senza tempi di inattività


31

È un'app PHP. Come posso ridurre al minimo i tempi di inattività durante l'aggiornamento dell'intera base di codice?

Risposte:


44

Quello che generalmente facciamo, al lavoro è:

  • prima di aggiornare, la radice del documento del server è:
    • nel /www/app-2009-09-01
    • ma si accede tramite un collegamento simbolico, chiamato /www/application
  • mettiamo tutta la nuova base di codice a /www/app-2009-09-08
  • una volta che l'intera base di codice è lì:
    • rimuoviamo il vecchio link simbolico
    • creiamo un nuovo link simbolico, ancora chiamato /www/application, ma che punta alle nuove fonti:/www/app-2009-09-08
  • ricarichiamo apache per forzare la modifica da prendere in considerazione.

Tutto questo processo viene eseguito tramite uno script automatico (l'unica cosa non automatica è che lo avviamo quando necessario). Questo significa :

  • Tutto procede rapidamente (in particolare il passaggio al collegamento simbolico, che è la parte importante)
  • Nessun rischio di errore: la sceneggiatura è stata ben testata e funziona da mesi / anni


Un altro vantaggio di questo precedente collegamento simbolico è che è molto semplice "ripristinare" un aggiornamento se notiamo un bug catastrofico solo dopo aver messo in produzione la nuova versione dei sorgenti: non ci resta che ripristinare i collegamenti simbolici.

Naturalmente, questo non ti impedisce di testare la nuova versione sul tuo server di gestione temporanea prima di metterlo in produzione - ma, chissà ... A volte, c'è un bug davvero grande che nessuno è stato in grado di vedere mentre test :-(
Ad esempio, perché non ci sono test di carico eseguiti regolarmente sulla macchina di gestione temporanea.
(Ho visto che la cosa "rollback" usava qualcosa come 4 o 5 volte in 3 anni - ogni volta, salvato il giorno - e i siti Web ^^)


Ecco un breve esempio: supponiamo di avere questo VirtualHost nella mia configurazione di Apache:

<VirtualHost *>
        ServerName example.com
        DocumentRoot /www/application
        <Directory /www/application>
            # Whatever you might need here (this example is copy-pasted from a test server and test application ^^ )
            Options Indexes FollowSymLinks MultiViews +SymLinksIfOwnerMatch
            AllowOverride All
            php_value   error_reporting 6135
            php_value short_open_tag  on
        </Directory>
</VirtualHost>

Piuttosto "standard" ... L'unica cosa è che /www/applicationnon è una directory reale: è solo un collegamento simbolico alla versione corrente dei sorgenti.
Ciò significa che quando hai inserito i sorgenti sul server, ma non sei ancora passato, avrai qualcosa del genere:

root@shark:/www
# ll
total 8
drwxr-xr-x 2 root root 4096 2009-09-08 22:07 app-2009-09-01
drwxr-xr-x 2 root root 4096 2009-09-08 22:07 app-2009-09-08
lrwxrwxrwx 1 root root   19 2009-09-08 22:08 application -> /www/app-2009-09-01

Si noti che il symlinc punta alla "vecchia versione"

Ora che la nuova versione è stata completamente caricata sul server, cambiamo:

root@shark:/www
# rm /www/application
root@shark:/www
# ln -s /www/app-2009-09-08 /www/application

E, ora, i /www/applicationpunti alla nuova versione delle fonti:

root@shark:/www
# ll
total 8
drwxr-xr-x 2 root root 4096 2009-09-08 22:07 app-2009-09-01
drwxr-xr-x 2 root root 4096 2009-09-08 22:07 app-2009-09-08
lrwxrwxrwx 1 root root   19 2009-09-08 22:09 application -> /www/app-2009-09-08

E non ci resta che riavviare Apache:

root@shark:/www
# /etc/init.d/apache2 restart
 * Restarting web server apache2

I tre passaggi " rimuovi il collegamento; crea il nuovo collegamento; riavvia apache " devono essere eseguiti rapidamente; cioè, da una sceneggiatura automatizzata e non da un essere umano.

Utilizzando questa soluzione:

  • puoi impiegare tutto il tempo necessario per caricare la nuova versione dei sorgenti: apache non li utilizzerà finché il symlic non è stato modificato
  • quando tutto va bene, basta cambiare il link simbolico: andrà più veloce della modifica anche di 1 o 2 file ... Il che significa praticamente nessun tempo di inattività :-)

E se uso un po 'di opcode-cache come APC con l'opzione stat a 0, può significare un rischio ancora minore di downtime, suppongo.


Ovviamente, questa è la versione "semplice" - se hai dei file caricati, ad esempio, dovrai usare un altro link simbolico da qualche parte, o un altro VirtualHost o qualsiasi altra cosa ...


Spero che questo sia più chiaro :-)


È anche una specie di scambio di server. :-)
Wim ten Brink,

mod_rewrite per gestire i collegamenti simbolici?

@gAMBOOKa: no: solo una questione di DocumentRoot (o VirtualHost DocumentRoot) di Apache, che è / www / application ;; cioè, il collegamento simbolico - non importa dove si punti.

2
Risposta formidabile. Un altro consiglio, però: puoi fare in modo che si verifichi il collegamento simbolico senza scollegarlo. Come citato: "I tre passaggi ... dovrebbero essere fatti rapidamente; cioè, da una sceneggiatura automatizzata e non da un essere umano". Il comando mv è un'operazione atomica, quindi puoi creare un link simbolico come 'ln -s / www / app-2011-01-28 / www / application-temp' e quindi fare un 'mv -T / www / application-temp / www / applicazione'.

1
C'è qualcosa che non è stato coperto dal metodo symlink. La tua strada funziona con Apache + mod_php ma potrebbe fallire su lighttpd + fastcgi. In un sito Web ad alto traffico, la richiesta verrà servita durante lo scambio del collegamento che, la dipendenza dal codice php non riuscirà con la versione mista.
Dennis C,

2

Non riesci a prendere il codice esistente e migrare il progetto in un file php di prova separato e utilizzarlo mentre esegui gli aggiornamenti? Quello che voglio dire è che dovresti avere un server di prova e un server di produzione in modo che quando devi effettuare un aggiornamento non subisca alcun downtime.


1

Imposta un secondo server con la base di codice aggiornata e cambiali il più velocemente possibile. :-)

Se non è possibile, assicurati che il tuo codebase sia diviso in dozzine di parti più piccole. Quindi i tempi di inattività sarebbero limitati a un solo capitolo alla volta. I blocchi di codice più piccoli sono più facili da sostituire e la maggior parte continuerà a funzionare senza problemi. Prima prova questo su un ambiente di test!


Poiché l'app non è stata testata con moduli frammentati, è possibile che si verifichino scenari imprevisti.

Ciò significa che questo sarebbe nell'elenco delle cose da fare dopo questo aggiornamento. :-) Rendilo più modulare e puoi aggiornarlo per modulo.
Wim ten Brink,

1
È nell'elenco delle cose da fare, ma è un obiettivo a lungo termine. Siamo una giovane startup, quindi l'organizzazione all'interno del team di sviluppo richiederà naturalmente un po 'di tempo. = D

1

Prima di tutto, uso spesso e mi piace un metodo simile alla risposta di Pascal MARTIN.

Un altro metodo che mi piace anche è usare il mio SCM per spingere nuovo codice. Il processo esatto dipende dal tipo di SCM (git vs svn vs ...). Se stai usando svn, mi piace creare un ramo "online" o "produzione" che controllo come root del documento sul server. Quindi, ogni volta che voglio spingere il nuovo codice da un altro ramo / tag / trunk, inserisco semplicemente il nuovo codice nel ramo "online" ed eseguo svn update nella radice del documento. Ciò consente un rollback molto semplice in quanto esiste un registro di revisione completo di ciò che è andato su / giù sul server e chi lo ha fatto e quando. Puoi anche eseguire facilmente quel ramo "online" su una casella di test, permettendoti di controllare l'app che stai per inviare.

Il processo è simile per git e altri stili di SCM, appena modificato per essere più naturale per il loro stile di flusso di lavoro.

Vuoi tirare / sondare invece di inviare aggiornamenti? Basta avere un lavoro cron o altro, meccanismo più intelligente esegue automaticamente svn update.

Extra: è anche possibile utilizzare questo processo per eseguire il backup dei file che l'applicazione ha scritto sul disco. Basta avere un lavoro cron o qualche altro meccanismo eseguire svn commit. Ora viene eseguito il backup dei file creati dall'applicazione in SCM, revisione registrata, ecc. (Es., Se un utente aggiorna un file su disco, ma desidera ripristinarlo, basta premere la vecchia revisione).


0

Uso un approccio simile anche a quello di Pascal MARTIN. Ma invece di caricare più versioni della mia app sul server di produzione, tengo le "build" dietro il mio firewall, ognuna in una directory separata con il numero e la data della build. Quando voglio caricare una nuova versione, utilizzo uno script semplice che include "rsync -avh --delay-updates". Il flag "delay = updates" caricherà tutto (che è diverso) in una cartella temporanea fino a quando non ci saranno tutti gli aggiornamenti, quindi trasferirà tutto in una volta alla fine del trasferimento sui loro percorsi corretti in modo che l'app non sarà mai in un mezzo-mezzo-mezzo-nuovo stato. Ha lo stesso effetto del metodo sopra, tranne per il fatto che mantengo solo una versione dell'app sul sito di produzione (è meglio avere solo i file essenziali nudi sul server di produzione, IMO).

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.