Pull to refresh

Comments 20

Спасибо, полезная информация.
Слышали ли вы про PHP-функции realpath_cache_get() и realpath_cache_size()?

Phpstorm не слышал на удивление.
Переводчику: не забывайте переводить слово «деплой».
какое слово вы перевели словом «деплой»?)
Содержание статьи — еще одна палка в сторону PHP.

m1el@m1el:/tmp$ cat symlink.php 
<?php
chdir("/tmp");
system("rm lnk; ln -s dir1 lnk");
print(realpath("lnk/file.txt") . "\n");
system("rm lnk; ln -s dir2 lnk");
print(realpath("lnk/file.txt") . "\n");

m1el@m1el:/tmp$ php symlink.php 
/tmp/dir1/file.txt
/tmp/dir1/file.txt
UFO just landed and posted this here
Если это перевод, то где ссылка на оригинал?
(или я немного ослеп..)
Под стрелочками для голосования какая-то странная иконка, возле неё надпись «перевод», и потом имя автора, которое является ссылкой. Да, ссылкой зеленого цвета, не удивляйтесь. Наверное так и задумано, я не знаю
Ох, ну точно ослеп :)
Сколько миллионов раз в секунду вы дергаете realpath() и зачем?
Да взять хотя бы автолоадеры… Я их пишу через realpath как раз из-за керишованного резолвинга путей.
Все намного проще. Сценарий получения ошибки такой:

Веб-сервер смотрит в папку /var/www/htdocs
Структура папки www следующая:

$ ls -al /var/www
htdocs -> version-71928
version-59189
version-71928

Новая версия кода выкладыватется в отдельную папку, ссылка htdocs переключается на новую версию.

В коде в новой версии добавляется инклюд (новая библиотека, класс, служебный файл, любая сущность на диске). PHP разрешил путь до /var/www/htdocs в виде /var/www/version-71928 и закешировал. После переключения ссылки старый кэш будет актуален вплоть до 2 минут (по умолчанию, в зависимости от realpath_cache_ttl) и все новые файлы будут искаться в прошлой версии.

Итого: версию выложили, переключили ссылки, и около 2 минут сыпятся фаталы
Unknown: Failed opening required '/var/www/htdocs/include.php'
Хуже, если старая версия удалена — фаталы будут сыпаться гуще. А в случае, когда необходимо синхронное переключение, могут возникнуть неведомые ошибки, которые никогда больше не воспроизведутся и могут принести сильную попа головную боль.

Дергать миллион раз ничего не нужно, достаточно использовать Composer Autoload :)
Достаточно выкладывать билды в новый каталог вида /path/to/application/$revisionNumber и обновлять конфигурацию веб-сервера.

Это решает и множество других проблем — атомарность переключения (не получится, что в какой-то момент будут использованы два файла от разных версий), возможность отката на предыдущий билд.
Атомарности переключения вообще очень сложно добиться. Есть два варианта:
1) Разорвать текущие соединения (restart), при этом будет атомарность, но клиенты получат ошибки
2) Нормально завершить текущие соединения (reload), в этом случае атомарности не будет — параллельно будут работать и старые, и новые, но клиенты ошибок не получат.
В зависимости от требований, выбирается подходящий вариант.

Что касается кофигурации, решение со ссылкой решает одну очень важную проблему — права доступа. Для изменения ссылки не требуется привелегий, достаточно прав на запись в папку с проектом. Для перезапуска же сервера требуется привелегированный доступ (читай: root), да и возможности ошибиться там намного больше. Возможность отката сохраняется.

У php-fpm есть проблемы с reload: bugs.php.net/bug.php?id=60961, поэтому в любом случае приходится искать решение уровнем выше.
Чтобы сохранить окружение целым и не давать рутовых прав CI, для нас оптимальным вариантом стало отключать ноду на балансировщике, ждать завершения процессов, обновляться, включать ноду обратно.
Зачем рута?

# grep nginx /etc/sudoers
%wwwctl ALL = NOPASSWD: /usr/sbin/service nginx configtest
%wwwctl ALL = NOPASSWD: /usr/sbin/service nginx reload

Проблему с релоадом знаю, да — потому без особых причин его стараюсь просто не делать. При смене пути он и не требуется.
Еще нужно конфигурацию поменять, чтобы было, что релоадить. А это — потенциальная брешь.
А зачем для конфигурации рутовые права? include /path/to/app/config/nginx/*.conf.

Или про сам факт? Ну она ж автоматически генерируется, из ровно того же шаблона, который проверен на стейджинге.
Проблема с релоадом решается, например, корректной конфигурацией nginx-а (т.е. уровнем выше, как вы и написали):
fastcgi_param   DOCUMENT_ROOT           $realpath_root;
fastcgi_param   SCRIPT_FILENAME         $realpath_root$fastcgi_script_name;

В этом случае переключение атомарное, т.к. php-fpm работает уже с настоящим путем, а не ссылкой. И релоад вообще делать не надо.

Впрочем, если при этом надо БД обновлять, тут уже вариантов нет =)
А что касаемо TTL устаревания, есть какие-то рекомендательные значения?
Sign up to leave a comment.

Articles