Distribuire il nuovo codice in tempo reale


29

Qual è la migliore pratica per distribuire un nuovo codice su un sito live (e-commerce)?

Per ora ho smesso di apache per +/- 10 secondi quando ho rinominato directory public_html_newin public_htmle vecchio a public_html_old. Questo crea un breve tempo di inattività, prima di riavviare Apache.

La stessa domanda vale se si utilizza Git per estrarre il nuovo repository nella directory live. Posso estrarre il repository mentre il sito è attivo? E se avessi bisogno di copiare anche un DB?

Durante la compressione tar (scopo di backup) del sito live ho notato che si sono verificati cambiamenti nella directory multimediale. Ciò mi ha indicato che i file continuano a cambiare periodicamente. E se queste modifiche possono interferire se Apache non viene arrestato durante la distribuzione.

Risposte:


13

L'uso di un bilanciamento del carico è una buona idea. Se il sito è abbastanza importante da preoccuparsi di alcuni secondi di inattività, è abbastanza importante preoccuparsi della tolleranza agli errori.

A parte questo, se questo è su un sistema UNIX, puoi mettere in attesa Apache durante la ridenominazione (o l'aggiornamento del collegamento simbolico, ecc.):

killall -STOP httpd  # Pause all httpd processes
mv public_html public_html_orig
mv public_html_new public_html
killall -CONT httpd  # Resume all httpd processes

Ciò impedirà ad Apache di accettare nuove richieste durante la ridenominazione. Se preferisci i symlink o qualche altro approccio, puoi usare la stessa idea:

killall -STOP httpd  # Pause all httpd processes
rm /var/www/html
ln -s /var/www/version/03 /var/www/html
killall -CONT httpd  # Resume all httpd processes

Si noti che eventuali connessioni o pacchetti in sospeso verranno messi in coda nel sistema operativo. Per un sito estremamente occupato, considerare l'ottimizzazione di ListenBacklog, se appropriato per il tipo di lavoratore httpd, e controllare le impostazioni del sistema operativo relative al backlog di ascolto TCP.

È inoltre possibile modificare DocumentRoot in httpd.conf ed eseguire un riavvio grazioso ( apachectl graceful). Lo svantaggio qui è l'aumento del rischio di errori, dal momento che dovresti aggiornare anche qualsiasi Directoryconfigurazione.


La sessione di pausa continuerà a far funzionare il sito?
nicoX,

4
Smette di dare tempo alla CPU ad Apache. Se hai tentato di accedere al sito in un browser mentre Apache è in pausa, il browser sarà in attesa di connettersi fino alla ripresa di Apache (o il timeout del browser, se Apache è in pausa più a lungo del periodo di timeout). Se qualcuno sta scaricando un file, Apache interromperà l'invio dei dati mentre è in pausa, di nuovo perché non sta ottenendo alcun tempo CPU. Ancora una volta ciò causerà problemi solo se Apache viene interrotto per così tanto tempo che il trasferimento scade.
GargantuChet

5
Detto in altro modo, il sito non risponderà mentre Apache è in pausa, ma le operazioni in sospeso termineranno quando viene ripreso. Gli utenti non riceveranno "connessione rifiutata" e i download non si interromperanno, ma le operazioni continueranno solo quando si riprende Apache. Ciò assicurerà che le transazioni esistenti possano essere completate, ma le nuove richieste verranno gestite solo dopo che i nuovi contenuti saranno stati spostati.
GargantuChet,

1
Si noti che in qualsiasi sito Web ad alto traffico, questo potrebbe uccidere molto facilmente il servizio Apache. 200 rq / s elimineranno facilmente il pool di connessioni non appena "sbloccerai" il processo Apache dopo lo spostamento (se lo spostamento richiede un po 'di tempo)
CloudWeavers,

1
Su un sito ad alto traffico, ci saranno molte richieste in volo da terminare quando Apache viene ripreso. Ciò scaglionerà l'elaborazione di nuove richieste. È anche un buon argomento per assicurarsi che le impostazioni di Apache (numero massimo di thread / server / client) siano ragionevoli e di regolare di conseguenza il backlog TCP. Anche se sono confuso su cosa intendi per "uccidere" il servizio. Apache è molto sintonizzabile.
GargantuChet

32

Il più semplice e veloce è usare una directory di versione come

/var/www/version/01
/var/www/version/02

e usa un link simbolico corrente come html_root:

/var/www/html -> /var/www/version/02

Questa tecnica si integra perfettamente in un sistema di controllo delle revisioni (svn, git, mercurial, ...) poiché puoi controllare rami e tag, modificare il collegamento simbolico e ricaricare Apache. Il tempo di inattività è minimo utilizzando questa tecnica e consente un rollback molto semplice .

Si integra bene anche con un sistema di distribuzione più complesso come pacchetti RPM o infrastruttura di gestione delle modifiche alla configurazione (cuoco, pupazzo, ecc.).


4
La soluzione più semplice è sempre la migliore ... :-) Naturalmente non dimenticare di menzionare che potrebbero essere necessari alcuni FollowSymlink e tali flag apache nelle configurazioni.
Peter dice di reintegrare Monica il

Prestare particolare attenzione a ciò che ha detto @PeterHorvath. Apache può diventare molto scontroso quando si lavora con DocumentRoots con collegamento simbolico. Assicurati di testare attentamente!
mhutter,

@mhutter Grazie :-) La cosa veramente problematica è che abilitare FollowSymlink su apache può causare problemi di sicurezza ...
Peter dice che ripristina Monica il

L'aggiornamento di un collegamento simbolico non è un'operazione atomica. Anche usando qualcosa di simile ln -snfper bloccare il link simbolico originale, l'operazione sottostante è un unlinke symlink. È possibile che gli utenti ottengano un 404 durante l'aggiornamento. Non è meglio che rinominare la directory originale e rinominarne una nuova (supponendo che non si stiano attraversando i filesystem). Vedere la risposta sopra con un segno di spunta accanto ad essa, che risolve questo problema.
GargantuChet

14

Anche la ridenominazione delle directory senza chiudere Apache dovrebbe funzionare. Ciò ridurrà significativamente la finestra. mv public_html public_html_old && mv public_html_new public_htmldovrebbe finire in una frazione di secondo.

Un paio di inconvenienti sono che questo approccio darà una risposta 404a qualsiasi richiesta che riesca ancora ad accadere durante la finestra. E se si esegue il comando sopra senza avere una public_html_newdirectory fallirà e ti lascerà con un sito che dà 404su ogni richiesta.

Farlo atomicamente con le directory non è supportato. Ma potresti farlo con i collegamenti simbolici. Invece di avere una directory denominata public_html, avere una directory denominata public_html.version-numbere un link simbolico chiamato che public_htmlpunta a quella directory. Ora puoi creare una directory chiamata public_html.new-version-numbere un nuovo symlink chiamato public_html.new.

Poi si può rinominare public_html.newa public_htmlpassare atomicamente. Si noti che mvè "troppo intelligente" per eseguire tale ridenominazione, ma potrebbe essere fatto utilizzando os.renameda Python o qualsiasi altra cosa che chiamerà ilrename chiamata di sistema senza cercare di essere intelligente.

Cosa fare con il database dipende dal database che si sta utilizzando e da cosa lo si sta utilizzando. Devi fornire molti più dettagli sul database prima di poterti dare una buona risposta a quella parte della tua domanda.


1
Sul mio sistema Debian, mvha -Tun'opzione che gli impedisce di seguire il collegamento simbolico. Questo vi permetterà di rinominare atomicamente public_html.newsopra public_html, assumendo entrambi sono soft link.
GargantuChet

11

Symlink e mv sono i tuoi amici, tuttavia, se hai davvero bisogno di evitare che gli utenti finali ricevano una pagina di errore durante la distribuzione di una nuova versione, dovresti avere un proxy inverso o un bilanciamento del carico davanti ad almeno 2 server back-end (apache nel tuo caso).

Durante la distribuzione, è sufficiente arrestare un back-end alla volta, distribuire il nuovo codice, riavviarlo e quindi scorrere i restanti back-end.

Gli utenti finali saranno sempre indirizzati a buoni backend dal proxy.


4
Stavo lavorando a questa risposta quando ti ho visto che l'hai già pubblicata. Balancer + 2 server rende il processo invisibile e più facile da recuperare da un aggiornamento errato ...
Bart Silverstrim,

9

Se si applicano regolarmente modifiche su un sistema di produzione, mi occuperei di un ciclo di vita strutturato. Una buona pratica è Capistrano http://capistranorb.com/ . Questa è una soluzione open source per la distribuzione di software su uno o più server su più piattaforme e configurazioni.

Per Magento esiste persino un plugin: https://github.com/augustash/capistrano-ash/wiki/Magento-Example

Per i singoli server e le transizioni quasi senza soluzione di continuità, consiglio di utilizzare i collegamenti simbolici.


4

Il modo in cui lo faccio è eseguire il commit delle mie modifiche dal mio ambiente di sviluppo locale a un repository Git online come Github. Il mio ambiente di produzione esegue un repository remoto, quindi tutto ciò che devo fare è ssh sul server ed eseguire git pullper annullare le ultime modifiche. Non è necessario arrestare il tuo server web.

Se nel progetto sono presenti file le cui impostazioni e / o contenuti differiscono dalla versione locale (come file di configurazione e caricamenti multimediali), è possibile utilizzare le variabili di ambiente e / o aggiungere questi file / directory a un .gitignorefile per impedire la sincronizzazione con il repository.


3

La mia prima idea è:

# deploy into public_html_new, and then:
rsync -vaH --delete public_html_new/ public_html/

Una buona soluzione era usare rsync. Ha cambiato solo i file realmente cambiati. Attenzione, le barre alla fine dei percorsi sono importanti.

Normalmente Apache non ha bisogno di un riavvio, non è il mondo Java. Controlla la modifica di ogni file php su richiesta e rilegge (e ri-tokenizza) la modifica automaticamente.

Git pull era simile, anche se era un po 'più difficile da scrivere. Ovviamente ha consentito un ampio spettro di diverse possibilità di rilevamento di fusioni / modifiche.

Questa soluzione funzionerà senza problemi solo se non ci sono cambiamenti davvero importanti - se ci sono grandi cambiamenti nella distribuzione, un po 'di pericolo non può essere chiuso, perché c'è un intervallo di tempo non trascurabile, quando il codice verrà parzialmente modificato e parzialmente no.

Se ci sono grandi cambiamenti, il mio suggerimento era la soluzione iniziale (due rinominare).


Ecco una soluzione atomica un po 'hardcore, ma al 100%:

(1) fai un mount alternativo del tuo filesystem, dove si svolge il tuo magento:

mount /dev/sdXY /mnt/tmp

(2) fai un --bindmount del tuo public_html_new in public_html:

mount --bind /path/to/public_html_new /path/to/public_html

Da questo punto, l'apache vedrà la tua nuova distribuzione. Qualsiasi cambiamento di 404 è impossibile.

(3) esegui la sincronizzazione con rsync, ma sul punto di montaggio alternativo):

rsync -vaH --delete /mnt/tmp/path/to/public_html_new/ /mnt/tmp/path/to/public_html/

(4) rimuovere il supporto di rilegatura

umount /path/to/public_html

Il comando eliminerà public_html e distribuirà public_html_new in esso?
nicoX,

@nicoX No, copierà solo le modifiche.
Peter dice di reintegrare Monica il

@nicoX Passa attraverso entrambe le strutture di directory e, se trova una differenza (nuovo file, file modificato, file eliminato), modifica la seconda directory in modo che corrisponda alla prima, se necessario. Il risultato se hai eliminato public_html e poi spostato public_html_new al suo posto, ma senza alcuna possibilità di un problema temporaneo 404.
Peter dice di reintegrare Monica il

1
No, questa non è una buona idea. A seconda delle modifiche, potresti avere un breve periodo di tempo in cui il codice public_htmlè in uno stato incoerente e non vuoi correre questo rischio.
Sven

@SvW Hai ragione, la mia idea va bene solo se ci sono solo piccole modifiche. Ho esteso la mia risposta di conseguenza.
Peter dice di reintegrare Monica il

1

Spostare / sostituire la http_publiccartella può essere ottenuto con semplice mvoln -s comandi o equivalenti mentre il server http continua a funzionare. È possibile eseguire alcuni script per ridurre significativamente i tempi di inattività, ma controllare attentamente i codici di ritorno dei comandi nello script se si automatizza il processo.

Detto questo, se non si desidera ottenere tempi di inattività, anche l' applicazione deve supportarlo. La maggior parte delle applicazioni utilizza un database per la persistenza. Avere la versione N della tua applicazione in disordine con la versione N + 1 (o viceversa) del tuo modello di dati può rompere le cose se non previsto dal team di sviluppo.

Per esperienza, mantenere tale coerenza attraverso gli aggiornamenti non è un dato di fatto per la maggior parte delle applicazioni. Un arresto corretto, nonostante i tempi di inattività, è un buon modo per evitare problemi di coerenza.

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.