To aplikacja PHP. Jak zminimalizować czas przestoju podczas aktualizacji całej bazy kodu?
To aplikacja PHP. Jak zminimalizować czas przestoju podczas aktualizacji całej bazy kodu?
Odpowiedzi:
To, co zazwyczaj robimy, w pracy to:
/www/app-2009-09-01
/www/application
/www/app-2009-09-08
/www/application
, ale który wskazuje na nowe źródła:/www/app-2009-09-08
Cały ten proces odbywa się za pomocą automatycznego skryptu (jedyną nieautomatyczną rzeczą jest uruchomienie go w razie potrzeby). To znaczy :
Kolejną zaletą tego symbolicznego precedensu dla łącza symbolicznego jest to, że bardzo łatwo jest „wycofać” aktualizację, jeśli zauważymy katastrofalny błąd dopiero po uruchomieniu nowej wersji źródeł: musimy tylko przełączyć linki symboliczne z powrotem.
Oczywiście nie przeszkadza to w testowaniu nowej wersji na serwerze testowym przed wprowadzeniem jej do produkcji - ale kto wie ... Czasami istnieje naprawdę duży błąd, którego nikt nie był w stanie zobaczyć testowanie :-(
Na przykład, ponieważ nie wykonuje się regularnych testów obciążenia na maszynie pomostowej.
(Widziałem, że funkcja „cofania” używała czegoś takiego jak 4 lub 5 razy w ciągu 3 lat - za każdym razem uratował dzień - i strony internetowe ^^)
Oto jakiś szybki przykład: załóżmy, że mam VirtualHost w mojej konfiguracji 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>
Dość „standardowy” ... Jedyne, co nie jest, /www/application
to nie jest prawdziwy katalog: to tylko symboliczny link do bieżącej wersji źródeł.
Co oznacza, że po umieszczeniu źródeł na serwerze, ale jeszcze nie przełączeniu, będziesz mieć coś takiego:
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
Zauważ, że symlinc wskazuje na „starą wersję”
Teraz, gdy nowa wersja została całkowicie przesłana na serwer, przełączmy:
root@shark:/www
# rm /www/application
root@shark:/www
# ln -s /www/app-2009-09-08 /www/application
A teraz /www/application
punkty do nowej wersji źródeł:
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
Musimy tylko ponownie uruchomić Apache:
root@shark:/www
# /etc/init.d/apache2 restart
* Restarting web server apache2
Trzy kroki: „ usuń łącze; utwórz nowe łącze; uruchom ponownie apache ” powinny być wykonane szybko; tj. za pomocą automatycznego skryptu, a nie przez człowieka.
Korzystanie z tego rozwiązania:
A jeśli użyję pamięci podręcznej opcode, takiej jak APC z opcją stat na 0, to może to oznaczać jeszcze mniejsze ryzyko przestoju, jak sądzę.
Oczywiście jest to „prosta” wersja - jeśli na przykład masz jakieś przesłane pliki, będziesz musiał użyć innego łącza symbolicznego, innego VirtualHost lub cokolwiek ...
Mam nadzieję, że to jest bardziej jasne :-)
Czy nie możesz pobrać istniejącego kodu i przeprowadzić migrację projektu do osobnego testowego pliku php i użyć go podczas aktualizacji? Mam na myśli to, że powinieneś mieć serwer testowy i serwer produkcyjny, aby podczas aktualizacji nie było żadnych przestojów.
Skonfiguruj drugi serwer ze zaktualizowaną bazą kodów i przełączaj je tak szybko, jak to możliwe. :-)
Jeśli nie jest to możliwe, upewnij się, że twoja baza kodu jest podzielona na dziesiątki mniejszych części. Wtedy przestoje byłyby ograniczone do jednej podsekcji w tym samym czasie. Mniejsze kody są łatwiejsze do wymiany i większość z nich będzie działać bez problemów. Najpierw jednak wypróbuj to w środowisku testowym!
Po pierwsze, często używam i lubię metodę podobną do odpowiedzi Pascala Martina.
Inną metodą, która mi się podoba, jest użycie mojego SCM do wypchnięcia nowego kodu. Dokładny proces zależy od typu SCM (git vs svn vs ...). Jeśli używasz svn, lubię tworzyć oddział „online” lub „produkcyjny”, który kasuję jako katalog główny dokumentu na serwerze. Następnie, ilekroć chcę przesłać nowy kod z innej gałęzi / znacznika / pnia, po prostu zatwierdzam nowy kod w gałęzi „online” i uruchamiam aktualizację svn w katalogu głównym dokumentu. Pozwala to na bardzo łatwe wycofywanie zmian, ponieważ istnieje kompletny dziennik zmian tego, co poszło w górę / w dół do serwera oraz kto to zrobił i kiedy. Możesz również z łatwością uruchomić tę gałąź „online” na polu testowym, co pozwala zweryfikować aplikację, którą chcesz wypchnąć.
Proces jest podobny w przypadku git i innych stylów SCM, po prostu zmodyfikowanych, aby były bardziej naturalne dla ich stylu pracy.
Chcesz pobrać / sondować zamiast wypychać aktualizacje? Po prostu miej zadanie crona lub inny, mądrzejszy mechanizm automatycznie uruchomi aktualizację svn.
Dodatkowo: możesz również użyć tego procesu do tworzenia kopii zapasowych plików zapisanych przez aplikację na dysku. Wystarczy mieć zadanie crona lub inny mechanizm uruchamiający svn commit. Teraz tworzone są kopie zapasowe plików utworzonych przez aplikację w SCM, rejestrowane wersje itp. (Np. Jeśli użytkownik aktualizuje plik na dysku, ale chce go przywrócić, wystarczy wcisnąć starą wersję).
Używam również podobnego podejścia do Pascala MARTINA. Ale zamiast przesyłać wiele wersji mojej aplikacji na serwer produkcyjny, „kompilacje” trzymam za zaporą ogniową, każda w osobnym katalogu z numerem kompilacji i datą. Kiedy chcę załadować nową wersję, używam prostego skryptu, który zawiera „rsync -avh --delay-updates”. Flaga „opóźnienie = aktualizacje” spowoduje przesłanie wszystkiego (innego) do folderu tymczasowego, dopóki wszystkie aktualizacje nie będą dostępne, a następnie przeniesienie wszystkiego naraz na koniec przesyłania na właściwe ścieżki, aby aplikacja nigdy nie była w stan na wpół stary na wpół nowy. Ma taki sam efekt jak powyższa metoda, z tym wyjątkiem, że przechowuję tylko jedną wersję aplikacji na stronie produkcyjnej (najlepiej mieć tylko same niezbędne pliki na serwerze produkcyjnym, IMO).