Как стать автором
Обновить

5 способов деплоя PHP-кода в условиях хайлоада

Время на прочтение14 мин
Количество просмотров22K
Всего голосов 48: ↑44 и ↓4+40
Комментарии19

Комментарии 19

Не могли бы вы спрятать виде под кат. Вы ломаете rss ленту
Скажу просто. ТО что написано просто дичь какая-то.
1. Если деплой делать хорошо — тогда лучше blue-green выкатывая тупо новую версию сразу на виртуальные на НОВЫЕ виртуальные машины, так можно и релизить кусками (ака 1% пользователей — 10%… 100%) и так нет проблем с откатом тк все 100% независимое и рабочее
2. Если все плохо судя из того что пишете. То имхо стоит использовать то что люди дааааавно придумали с releases -> symlink to -> current dir дешево сердито и не нужен рут. Да орд кульно но работает стабильно и если вдруг что пошло не так тупо меняем симлинк онбартно на предидущий релиз. Есть 100500 готовых решений для того деплоя просто бери и юзайте.
3. Если все плохо но хочется докер. НА*** маунтить директорию ??? Зачем что за дичь? Почему просто не собрать готовый образ со всем вместе со всеми папками, правами, php-fpm and nginx просто вот такой веб-бокс который можно запустить где угодно хоть локально хоть на проде. Релиз-откат тогда это просто переключение между тегами для образа — дешево -сердито-стабильно.

Релиз это не магия с какими-то танцами с бубном это просто тупой однообразный процесс, причем абсолютно бездумный и он таким и должен быть.
1. Неясно, зачем здесь виртуальные машины. Можно обновить 50% машин и будет в целом то же самое — половина трафика будет обслуживаться старым кодом, половина — новым. Для того, чтобы делать так, как вы хотите, особенно с PHP, нужно либо «жить в облаке» (а-ля Amazon или Google Cloud), либо использовать что-нибудь вроде Kubernetes. В то время как это «модные» и «новые» технологии, внедрять их только ради blue-green deployment звучит не очень разумно. Отдельный вопрос есть вообще про полезность blue-green deployment — это не всегда хорошо, когда есть 2 разных версии кода, которые одновременно работают в продакшене.
2. Я ничего не понял, извините
3. Не забывайте про то, что код раскладывался не только на те машины, где вообще стоит Docker (там даже версия ядра может Docker не поддерживать, или поддерживать его весьма старой версии). То есть, схема должна быть совместимой с Docker, но это не значит, что деплой должен осуществляться средствами Docker. Более того, учитывая, как работают слои в Docker, сделать такой же эффективный (в плане потребления места) инкрементальный деплой было бы сложно: самое эффективное, что можно сделать — всё время будет раскладываться разница между «базовым образом» и текущим состоянием, и эта разница будет постоянно расти, а пересоздание образа будет занимать как минимум размер этого образа :), то есть в какой-то момент будет нужно хранить как минимум 2x места. Потребляемое место немаловажно, т.к. кода и всего остального каждый раз деплоится ~1 Гб, и далеко не на всех машинах есть достаточное количество места под большое количество копий директории. Я не говорю, что на эту схему нельзя перейти, но только вопрос — зачем? Эта система делалась не «с нуля», и на всех серверах уже всё было настроено, без докера (потому что делалось давно). «If it ain't broken, don't fix it».
2. Это модифицированная версия с двумя директориями, только их неограниченное (в разумных пределах) количество. Давно автоматизировано для ruby и php (типа порта с ruby) как минимум.
2. Как решить вопрос того, что при создании директории нового релиза, пользователи загружают файлы (на сайте) в директорию еще старого релиза? При переключении релизов, пользователи теряют свои файлы в старом релизе.

Как-то так:


current -> /releases/ver2
releases/
  ver1/
    public/
      uploads -> /shared/public/uploads
      index.php
    src/
      file1.php
      file2.php
      file3.php
      file4.php
  ver2/
    public/
      uploads -> /shared/public/uploads
      index.php
    src/
      file1.php
      file2.php
      file3.php
      file4.php
shared/
  public/
    uploads/
      file1.jpg
      file2.jpg
      file3.jpg
      file4.jpg
      file5.jpg

т.е. в каждом релизе есть символьные ссылки на директории с общими файлами.

В любой подобной статье ищу фразу «Проблемы с docker»
«У соцсети N есть 2 000 серверов, на которых 150 000 файлов объемом по 900 Мб PHP-кода...


Поскольку у нас 2000 серверов, то требуется 2000 раз залить 900 Мб.


Так уж выходит не «по 900 Мб», а «в сумме на 900 Мб».

Деплой, как уже писали, должен быть максимально простой, даже тупой, и понятный с первого взгляда. А здесь он, какой-то, очень нетривиальный.


У меня сложилось впечатление, что вы проблему решаете не с того конца. Вы пытаетесь усложнением деплоя решить проблемы архитектуру.


Те же долгоиграющие CLI-скрипты, из-за которых, как я понял, весь сыр-бор, можно было бы отделить от обычной веб-серверной нагрузки в отдельный кластер. Тогда, глядишь, и rsync бы подошёл.


Короче, шире надо смотреть на проблемы.

А что насчёт миграций баз и других хранилищ данных во время деплоя? Как обеспечивается согласованность версии структуры данных и кода, который с ней работает, во время деплоя и в случае неудачного деплоя?
Согласен. Это важный вопрос, который не может быть оторван от темы.
PHP-код не знает, в какой из директорий он был запущен

Что мешает ему это знать?

Если в пути не было симлинков, то, в целом, ничего, и __DIR__ будет прекрасно работать (хотя часто используют document_root в качестве основы). Если же посередине пути симлинки присутствуют, то __DIR__ в теории (да и на практике тоже) может показывать не тот же путь, по которому действительно был загружен скрипт, если в процессе исполнения запроса симлинк в пути поменял свое значение. Это заодно вызывает артефакты при кешировании опкода — мы наблюдали, как в opcache попадала не та (старая) версия файла. Поэтому лучше избегать симлинков в пути, или использовать realpath_root, или же не полагаться на то, что при изменении симлинка все будет правильно работать
Алгоритм:

0. На входе путь до скрипта в котором возможно симлинки
1. Разрезолвить симлинки (man realpath)
2. Вызвать скрипт по полученному пути
3. ???
4. Profit.
Rsync позволяет синкать на удаленный сервер в новый каталог, заменяя неизмеившиеся файлы хардлинками на уже существующие там. Таким образом получаете обновленный вариант каталога с исходниками, отдельно, и передав только изменения. Это решает проблему нагрузки на диски при большом кол-ве файлов (хотя ссд должен бы справиться, но да ладно). После этой операции можно переключить симлинк или переименовать каталог. Это будет неатомарно, но в свежих линуксах есть сисколл, чтобы обменять имена у двух каталогов за 1 сисколл.
Про задачник по хайлоаду можем только мечтать

Зато cookbook по хайлоаду вполне уже можно сделать, будет такой же толстый, как и у perl в своё время ^_^

Статья написана здорово, читается легко, но её содержимое (мягко говоря) отталкивает. Складывается стойкое убеждение что решаете проблему не с той стороны — не дроблением монолита на сервисы с независимым деплоем каждого по отдельности по мере необходимости на, скажем, k8s, а пытаетесь закостылять то "что есть", выдавая это за некоторое подобие инновации и "мы разработали деплой кит".
Вот бы статейку о том, как молит дробили, да под каждый конкретный сервис подбирали наиболее подходящий язык/службу/идею — вот этому цены бы не было

А как вы определили, «с той стороны» решается задача или «не с той»? Дробление на микросервисы — это задача, в целом, отдельная от деплоя, и их можно делать независимо. Я решал достаточно конкретные проблемы, которые были у деплой-системы — необходимость часто применять патчи, но при этом позволять скриптам, которые были работают «долго» (несколько часов), всё ещё работать с консистентной версией кода. Разделение на микросервисы в теории могло бы уменьшить «боль» от этого, но, кажется, решить эту проблему на уровне системы деплоя было бы намного эффективнее в плане затраченных на разработку ресурсов (на деплой было потрачено максимум несколько месяцев, в то время как на распиливание монолита я бы сказал, что ушло бы много человеколет).
На ФС с поддержкой Copy-on-Write можно сильно увеличить эффективность rsync (а возможно, и других методов) следующим образом: копируем (разумеется, так, чтобы фактически копии не создавались) существующие файлы проекта в новое место, делаем на нём rsync (с удалением, это важно), переключаем на новые файлы
Зарегистрируйтесь на Хабре, чтобы оставить комментарий