Es ist eine PHP-App. Wie kann ich die Ausfallzeit minimieren, während ich die gesamte Codebasis aktualisiere?
Es ist eine PHP-App. Wie kann ich die Ausfallzeit minimieren, während ich die gesamte Codebasis aktualisiere?
Antworten:
Was wir im Allgemeinen bei der Arbeit tun, ist:
/www/app-2009-09-01
/www/application
/www/app-2009-09-08
/www/application
, aber auf die neuen Quellen verweist:/www/app-2009-09-08
All dies geschieht über ein automatisches Skript (das einzige, was nicht automatisch geschieht, ist, dass wir es bei Bedarf starten). Das heisst :
Ein weiterer Vorteil dieser symbolischen Verknüpfungsvorgehensweise besteht darin, dass es sehr einfach ist, ein Update zurückzusetzen, wenn wir einen katastrophalen Fehler erst feststellen, nachdem wir die neue Version der Quellen in Betrieb genommen haben: Wir müssen nur die symbolischen Verknüpfungen zurücksetzen.
Das hindert Sie natürlich nicht daran, die neue Version auf Ihrem Staging-Server zu testen, bevor Sie sie in Betrieb nehmen - aber wer weiß ... Manchmal gibt es einen wirklich großen Fehler, den niemand gesehen hat testing :-(
Zum Beispiel, weil es auf dem Staging-Rechner keine regelmäßigen Lasttests gibt.
(Ich habe gesehen, dass das "Rollback" -Ding in 3 Jahren 4 oder 5 Mal verwendet wurde - jedes Mal den tag gerettet - und die websites ^^)
Hier ist ein kurzes Beispiel: Angenommen, ich habe diesen VirtualHost in meiner Apache-Konfiguration:
<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>
Ziemlich "Standard" ... Das einzige, was ist, /www/application
ist kein richtiges Verzeichnis: Es ist nur ein symbolischer Link zur aktuellen Version der Quellen.
Das heißt, wenn Sie die Quellen auf den Server gestellt, aber noch nicht gewechselt haben, haben Sie ungefähr Folgendes:
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
Beachten Sie, dass das Symbol auf die "alte Version" verweist
Nachdem die neue Version vollständig auf den Server hochgeladen wurde, wechseln wir:
root@shark:/www
# rm /www/application
root@shark:/www
# ln -s /www/app-2009-09-08 /www/application
Und nun die /www/application
Punkte zur neuen Version der Quellen:
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
Und wir müssen nur Apache neu starten:
root@shark:/www
# /etc/init.d/apache2 restart
* Restarting web server apache2
Die drei Schritte " Entfernen der Verknüpfung; Erstellen der neuen Verknüpfung; Neustarten von Apache " sollten schnell ausgeführt werden. dh durch ein automatisiertes Skript und nicht durch einen Menschen.
Verwendung dieser Lösung:
Und wenn Sie einen Opcode-Cache wie APC mit der Option stat bei 0 verwenden, kann dies vermutlich sogar zu einem noch geringeren Ausfallrisiko führen.
Dies ist natürlich die "einfache" Version - wenn Sie zum Beispiel einige hochgeladene Dateien haben, müssen Sie irgendwo einen anderen Symlink oder einen anderen VirtualHost oder was auch immer verwenden ...
Hoffe das ist klarer :-)
Können Sie den vorhandenen Code nicht nehmen und das Projekt in eine separate Test-PHP-Datei migrieren und diese verwenden, während Sie Ihre Updates vornehmen? Ich meine, Sie sollten einen Testserver und einen Produktionsserver haben, damit Sie keine Ausfallzeiten haben, wenn Sie ein Update durchführen müssen.
Richten Sie einen zweiten Server mit der aktualisierten Codebasis ein und wechseln Sie diese so schnell wie möglich. :-)
Wenn dies nicht möglich ist, stellen Sie sicher, dass Ihre Codebasis in Dutzende kleinerer Teile unterteilt ist. Dann wäre die Ausfallzeit auf jeweils nur einen Unterbereich begrenzt. Die kleineren Codeblöcke lassen sich leichter austauschen und die meisten funktionieren problemlos weiter. Probieren Sie dies jedoch zunächst in einer Testumgebung aus!
Zunächst einmal verwende und mag ich oft eine Methode, die der von Pascal MARTIN ähnelt.
Eine andere Methode, die ich auch mag, ist mein SCM zu verwenden, um neuen Code zu pushen. Der genaue Prozess hängt von Ihrem SCM-Typ ab (git vs svn vs ...). Wenn Sie svn verwenden, möchte ich einen "Online" - oder "Produktions" -Zweig erstellen, den ich als Dokumentstamm auf dem Server auschecke. Wann immer ich neuen Code von einem anderen Zweig / Tag / Trunk übertragen möchte, gebe ich den neuen Code einfach in den "Online" -Zweig ein und führe svn update im Dokumentenstamm aus. Dies ermöglicht sehr einfache Rollbacks, da ein vollständiges Revisionsprotokoll darüber vorhanden ist, was auf dem Server hoch- / runtergelaufen ist und wer es wann getan hat. Sie können diesen "Online" -Zweig auch ganz einfach auf einer Testbox ausführen, um die App zu überprüfen, die Sie pushen möchten.
Der Prozess ist für Git und andere SCM-Stile ähnlich, wurde jedoch so modifiziert, dass er natürlicher für die Art des Workflows ist.
Möchten Sie Aktualisierungen abrufen oder abrufen, anstatt sie zu übertragen? Haben Sie einfach einen Cron Job oder einen anderen, intelligenteren Mechanismus, mit dem svn update automatisch ausgeführt wird.
Extra: Sie können diesen Prozess auch zum Sichern von Dateien verwenden, die Ihre Anwendung auf die Festplatte geschrieben hat. Lassen Sie einfach einen Cron-Job oder einen anderen Mechanismus svn commit ausführen. Jetzt werden die Dateien, die Ihre Anwendung erstellt hat, in Ihrem SCM gesichert, die Revision wird protokolliert usw. (Wenn beispielsweise ein Benutzer eine Datei auf der Festplatte aktualisiert, aber Sie möchten, dass Sie sie zurücksetzen, drücken Sie einfach die alte Revision).
Ähnlich gehe ich auch bei Pascal MARTIN vor. Anstatt jedoch mehrere Versionen meiner App auf den Produktionsserver hochzuladen, behalte ich die "Builds" hinter meiner Firewall in einem separaten Verzeichnis mit Build-Nummer und Datum. Wenn ich eine neue Version hochladen möchte, verwende ich ein einfaches Skript, das "rsync -avh --delay-updates" enthält. Mit dem Flag "delay = updates" wird alles (was anders ist) in einen temporären Ordner hochgeladen, bis alle Updates vorhanden sind. Anschließend wird am Ende der Übertragung alles auf einmal auf die richtigen Pfade verschoben, sodass sich die App niemals in einem befindet halb alter halb neuer Zustand. Dies hat den gleichen Effekt wie die oben beschriebene Methode, außer dass ich nur eine Version der App auf dem Produktionsstandort behalte (am besten nur die wichtigsten Dateien auf dem Produktionsserver, IMO).