Обновление веб-приложения без простоев

31

Это приложение PHP. Как я могу минимизировать время простоя при обновлении всей кодовой базы?

Саймон Хейтер
источник

Ответы:

44

Что мы обычно делаем на работе:

  • перед обновлением корень документа сервера:
    • в /www/app-2009-09-01
    • но доступен через символическую ссылку, называемую /www/application
  • мы помещаем всю новую базу кода в /www/app-2009-09-08
  • когда вся база кода там:
    • удаляем старую символическую ссылку
    • мы создаем новую символическую ссылку, которая все еще называется /www/application, но которая указывает на новые источники:/www/app-2009-09-08
  • мы перезагружаем apache, чтобы модификация была принята во внимание.

Весь этот процесс выполняется с помощью автоматического скрипта (единственная неавтоматическая вещь - мы запускаем его при необходимости). Это означает :

  • Все идет быстро (особенно переключение символической ссылки, которая является важной частью)
  • Нет риска допустить ошибку: скрипт хорошо протестирован и работает месяцами / годами


Другое преимущество этой условной ссылки состоит в том, что «откатить» обновление очень легко, если мы заметим катастрофическую ошибку только после запуска новой версии исходных кодов: нам просто нужно переключить символические ссылки обратно.

Конечно, это не мешает вам тестировать новую версию на своем промежуточном сервере, прежде чем запускать ее в производство - но, кто знает ... Иногда существует действительно большая ошибка, которую никто не смог увидеть, пока testing :-(
Например, потому что на промежуточной машине регулярно не проводится нагрузочное тестирование.
(Я видел, что «откат» использовал что-то вроде 4 или 5 раз за 3 года - каждый раз, это спас день - и сайты ^^)


Вот небольшой пример: предположим, у меня есть VirtualHost в моей конфигурации 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>

Довольно "стандартный" ... Единственное, это /www/applicationне настоящий каталог: это просто символическая ссылка на текущую версию источников.
Это означает, что когда вы поместили источники на сервер, но еще не переключили, у вас будет что-то вроде этого:

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

Обратите внимание, что символ указывает на «старую версию»

Теперь, когда новая версия полностью загружена на сервер, давайте переключимся:

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

И, теперь, /www/applicationуказывает на новую версию источников:

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

И мы просто должны перезапустить Apache:

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

Три шага « удалить ссылку; создать новую ссылку; перезапустить apache » должны быть выполнены быстро; то есть автоматическим сценарием, а не человеком.

Используя это решение:

  • вы можете потратить столько времени, сколько вам нужно, чтобы загрузить новую версию исходных текстов: apache не будет использовать их, пока символ не был изменен
  • когда все в порядке, просто переключите символическую ссылку: это пойдет быстрее, чем изменение даже 1 или 2 файлов ... Это означает, что практически нет простоев :-)

И если использовать какой-нибудь opcode-кеш, такой как APC, с опцией stat в 0, это может означать еще меньший риск простоя, я полагаю.


Конечно, это «простая» версия - например, если у вас есть загруженные файлы, вам нужно будет использовать другую символическую ссылку или VirtualHost или что-то еще ...


Надеюсь, это более понятно :-)

Паскаль МАРТИН
источник
Это тоже своего рода перестановка серверов. :-)
Вим тен Бринк
mod_rewrite для управления символическими ссылками?
@gAMBOOKa: нет: просто вопрос DocumentRoot (или VirtualHost DocumentRoot) Apache, который является / www / application ;; т.е. символическая ссылка - независимо от того, на что она указывает.
2
Потрясающий ответ. Тем не менее, еще один совет: вы можете сделать так, чтобы символическая ссылка возникала без ее отмены. Как указано: «Три шага… должны быть сделаны быстро, т. Е. Автоматизированным сценарием, а не человеком». Команда mv является атомарной операцией, поэтому вы можете создать символическую ссылку, такую ​​как 'ln -s / www / app-2011-01-28 / www / application-temp', а затем выполнить 'mv -T / www / application-temp / WWW / приложение.
1
Там что-то не было покрыто методом символической ссылки. Ваш путь работает с Apache + mod_php, но он может потерпеть неудачу на lighttpd + fastcgi. На веб-сайте с высоким трафиком запрос будет обрабатываться в середине обмена ссылки, что, зависимость php-кода не будет работать в смешанной версии.
Денис С
2

Разве вы не можете взять существующий код и перенести проект в отдельный тестовый php-файл и использовать его при обновлении? Я имею в виду, что у вас должен быть тестовый сервер и рабочий сервер, чтобы при обновлении не было простоев.

Сообщество
источник
1

Настройте второй сервер с обновленной кодовой базой и переключите их как можно быстрее. :-)

Если это невозможно, убедитесь, что ваша кодовая база разделена на десятки более мелких частей. Тогда время простоя будет ограничено только одним подразделением за раз. Меньшие кодовые блоки легче заменить, и большинство просто продолжит работать без проблем. Просто попробуйте сначала в тестовой среде!

Вим тен Бринк
источник
Поскольку приложение не было протестировано с фрагментированными модулями, это может привести к неожиданным сценариям.
Это означает, что это будет в вашем списке задач после этого обновления. :-) Сделайте его более модульным, и вы можете обновлять каждый модуль.
Вим тен Бринк
1
Это в списке задач, но это долгосрочная цель. Мы молодой стартап, поэтому организация в команде разработчиков, естественно, займет некоторое время. = D
1

Во-первых, я часто использую метод, похожий на ответ Паскаля МАРТИНА.

Другой метод, который мне также нравится, - это использовать мой SCM для добавления нового кода. Точный процесс зависит от вашего типа SCM (git vs svn vs ...). Если вы используете svn, мне нравится создавать «онлайн» или «производственную» ветку, которую я извлекаю как корневой документ на сервере. Затем, когда я хочу отправить новый код из другой ветви / тега / транка, я просто фиксирую новый код в «онлайн» ветви и запускаю svn update в корне документа. Это позволяет выполнять очень простые откаты, поскольку имеется полный журнал изменений того, что было сделано на сервере, кто и когда это сделал. Вы также можете легко запустить эту «онлайн» ветку в тестовом окне, что позволит вам проверить приложение, которое вы собираетесь запустить.

Процесс похож на git и другие стили SCM, только что измененный, чтобы быть более естественным для их стиля рабочего процесса.

Хотите вытащить / опросить вместо того, чтобы выдвигать обновления? Просто запустите cron или другой, более умный механизм, который автоматически запускает svn update

Дополнительно: вы также можете использовать этот процесс для резервного копирования файлов, которые ваше приложение записало на диск. Просто запустите cron или какой-нибудь другой механизм, запустите svn commit. Теперь файлы, созданные вашим приложением, сохраняются в SCM, регистрируются ревизии и т. Д. (Например, если пользователь обновляет файл на диске, но хочет, чтобы вы вернули его, просто нажмите старую ревизию).


источник
0

Я использую аналогичный подход к Паскалю Мартину тоже. Но вместо того, чтобы загружать несколько версий моего приложения на рабочий сервер, я сохраняю «сборки» за брандмауэром, каждая в отдельном каталоге с номером сборки и датой. Когда я хочу загрузить новую версию, я использую простой скрипт, который включает в себя «rsync -avh --delay-updates». Флаг «задержка = обновления» будет загружать все (что отличается) во временную папку до тех пор, пока не появятся все обновления, а затем переместит все сразу по окончании передачи на их правильные пути, чтобы приложение никогда не находилось в наполовину старое наполовину новое государство. Это имеет тот же эффект, что и описанный выше метод, за исключением того, что я храню только одну версию приложения на производственном сайте (лучше всего иметь только основные файлы на рабочем сервере, IMO).


источник