LINUX.ORG.RU
ФорумAdmin

Переключение версии сайта со staging на production с 0 downtime, как?

 ,


1

3

Есть сайт, работающий на одном хосте/машине, больше хостов нет (используется VPS/VDS). Сайт работает на базе php-fpm + mysqld + nginx, используется только одна база MySQL. PHP-исходники, которые обрабатывают текущие запросы лежат в папке /site/production. На хост была залита др. папка - /site/staging с новой версией исходников.

Теперь нужно:
1. Применить апдейт для БД в виде .sql-скриптов, которые могут поменять структуру таблиц базы.
2. Переключить nginx на новую версию исходников, т.е. с /site/production на /site/staging.

Эти два пункта нужно сделать одновременно, так, чтобы юзеры это вообще не заметили, ниодного HTTP-запроса не прервалось, т.е. с 0 downtime и connection draining.

Переключить root можно с помощью команды nginx reload и таким образом переключиться с /site/production на /site/staging. Проблема в том, что /site/staging зависит от скриптов апдейта БД - нужно вначале применить их, иначе .php-скрипты в /site/staging не будут работать. Если же вначале применить скрипты апдейта БД, то сайт некоторое время будет недоступен, потому как Nginx будет использовать старые исходники /site/production какое-то время, до полного переключения на /site/staging.

Как это можно сделать? Можно ли это сделать без введения второго хоста в строй? Если нет, как это делается в случае с двумя или более хостами? Можно ли обойтись без репликации MySQL?

Я полагаю, что для 0 downtime и connection draining нужна репликация MySQL: на slave применяются апдейты, нужные для /site/staging и затем переключаются через DNS, так ли это?

В общем, кто уже строил HA кластеры или имеет опыт для одного хоста переключения с 0 downtime сайта как вы это делаете или это можно сделать? Хотелось бы обойтись без введения второго хоста, если возможно.

Перемещено leave из web-development


Если старый код сможет работать с новой схемой данных и умеет read-only, то через реплику. Если ответ на оба предположения «нет», то никак.

leave ★★★★★
()

@leave, старый код умеет частично работать с новой схемой, некоторые части сайта сломаются, если не сделать ALTER TABLE и UPDATE для некоторых таблиц. Но можно считать, что не умеет.

Ещё поясню, чтобы стало понятнее:многие сайты как-то обновляются без страницы 503 (503 Service Unavailable) и отказов в обслуживании. Нужно сделать так же, с 0 downtime, без введения второго хоста, если возможно.

ProtoH
() автор топика

Как это можно сделать? Можно ли это сделать без введения второго хоста в строй?

Если после наката скрипта на БД старая версия отъедет то в общем случае никак, даже с введением второго хоста.

ya-betmen ★★★★★
()
Ответ на: комментарий от leave

Как понять монолитного? Исходя из ваших ответов делаю вывод что нужен обязательно второй хост, правильно ли я понял вас?

Уточню основную проблему: рассмотрим 3 случая обновления:


  • Если вначале применить .sql-скрипты миграции, но оставить старый код, то некоторые или даже все HTTP запросы будут обработаны с ошибкой, т.к. старые .php-скрипты рассчитаны на старую структуру БД.
  • Если вначале обновить код сайта, но не применять .sql скрипты миграции и оставить старую структуру БД, то опять же некоторые или даже все HTTP запросы будут обработаны с ошибкой, т.к. новые .php-скрипты рассчитаны на новую структуру БД.
  • Если обновить одновременно .php-скрипты и применить .sql-скрипты миграции, то всё должно работать, но проблема в том как сделать это с 0 downtime. Тут приходит на ум такое решение:
    1) Сделать реплику/копию БД на новом сервере, например, с id == 2, назовём эту БД stage, и настроить так, чтобы все изменения из основной БД попадали и в БД stage.
    2) Применить скрипты миграции для stage.
    3) Переписывать каким-то образом SQL-запросы поступающие от основного сервера к серверу c id == 2, так, чтобы они учитывали изменения скриптов миграции, например, колонка user.pass была переименована в user.password, соответственно нужно перехватывать и переписывать все SQL-запросы, чтобы они использовали колонку user.password.
    4) Настроить Nginx, например так, чтобы он использовал новый код .php и был доступен по домену staging.$domain. Этот сайт должен быть настроен на сервер c id == 2, т.е. работать с новой БД.
    5) Переключиться на новую версию staging.$domain с помощью nginx reload.



Есть сомнения, что nginx reload даст 0 downtime, но нужно попробовать. Используется ли кем-либо такая схема переключения на новую версию? Есть ли тут какие-либо недостатки? Есть ли др. варианты?

ProtoH
() автор топика

0. Повесить на сайте красивую табличку родом из 2000х «Сайт на обслуживании» 1. Применить апдейт для БД в виде .sql-скриптов, которые могут поменять структуру таблиц базы. 2. Переключить nginx на новую версию исходников, т.е. с /site/production на /site/staging. 3. Убрать красивую табличку.

Я уверен, что требование переключение с нулевым простоем вызвано скорее переоценкой важности и крутости сайта, чем необходимостью. Небось не систему автоматизации работы авиадиспетчера делаете или управления атомной станцией))

Alve ★★★★★
()
Ответ на: комментарий от ProtoH

Есть сомнения, что nginx reload даст 0 downtime

Не сомневайся: master спавнит новые воркеры, а старые дорабатывают текущие соединения. Это самое надежное.

3) Переписывать каким-то образом SQL-запросы поступающие от основного сервера к серверу c id == 2, так, чтобы они учитывали изменения скриптов миграции, например, колонка user.pass была переименована в user.password, соответственно нужно перехватывать и переписывать все SQL-запросы, чтобы они использовали колонку user.password.

mysqlproxy

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

kawaii_neko ★★★★
()
Ответ на: комментарий от kawaii_neko

Не сомневайся: master спавнит новые воркеры, а старые дорабатывают текущие соединения. Это самое надежное.

Спасибо, понял.

mysqlproxy

Ок, гляну ;)

ProtoH
() автор топика

1. Поднимаем копию боевой БД на том же сервере БД.
2. Накатываем SQL-скрипты.
3. В новом инстансе приложения изменяем имя БД в конфиге.
4. Добавляем конфиг в nginx для нового инстанса приложения для теста работоспособности, пока боевой инстанс обрабатывает текущие запросы (опциональный пункт).
5. Изменяем конфиг nginx для работы с новой версией приложения, затем nginx reload
6. Profit

Но все это реализуемо, если позволяют ресурсы хоста/СУБД.

blackst0ne ★★★★★
()
Ответ на: комментарий от ProtoH

Нужно сделать так же, с 0 downtime, без введения второго хоста, если возможно.

Поднимаешь копию проекта там же, обновляешь, смотришь работает ли, nginx reload, удаляешь старый.

Deleted
()
Ответ на: комментарий от blackst0ne

При таком подходе в копии БД не будет записей, которые появятся в оригинальной БД пока будет вестись тестирование.

ProtoH
() автор топика
Ответ на: комментарий от winlook38

В новой схеме могут быть исправлены косяки старой схемы + добавлены новые колонки, таблицы, и др. сущности БД.

ProtoH
() автор топика
Ответ на: комментарий от ProtoH

Можно повесить триггеры на оригинальные таблицы, которые будут соответствующим образом вставлять(менять) данные в новой базе. Поверхностный гуглеж говорит о том, что можно сделать триггер на другую БД.

swelf
()
Последнее исправление: swelf (всего исправлений: 1)
Ответ на: комментарий от swelf

Судя по описанию, там монолитный кусок гомна на пыхе. Что-то я очень сомневаюсь, что эти люди осилят написать эти триггеры. А потом их придется переписывать под каждую новую версию приложения, в которой есть миграции.

Короче, это все костыли, здесь надо менять подходы к разработке и деплою.

leave ★★★★★
()

Вообще, что это за приложение такое, для которого секунды простоя - это бизнес критикал?

blackst0ne ★★★★★
()
Ответ на: комментарий от ProtoH

Это все понятно. Вопрос в том, зачем вы ломаете схему БД для старой версии, а не исправляете схему таким образом, чтобы работали обе версии? Приведи мне пример, когда для исправления ошибки нужно сломать схему.

Мы не используем подход BlueGreenDeployment, но мы так же поддерживаем валидность схемы для версии n-1 именно для уменьшения времени даунтайма.
Схема такая: поднимаешь реплику; апдейтишь ее; если нужно, прогоняешь тесты; докатываешь на нее WAL (он накатывается, т.к. схема валидна для старой версии); переключаешься на реплику.

Но у нас без даунтайма не получается по некоторым причинам. Тебе, возможно, удастся упростить схему: апдейтишь схему; поднимаешь новый сервер приложения; переключаешься на него (сам придумаешь стратегию насчет пользовательских сессий и прочего, если нужно).

winlook38 ★★
()

с 0 downtime

работающий на одном хосте/машине

как?

Никак. Вернее способ есть - раскидать все по микросервисам и поднять docker :)

Создать по два контейнера, два БД, два приложения. nginx в качестве роутера/балансировщика. Все.

robot12 ★★★★★
()
Последнее исправление: robot12 (всего исправлений: 2)
Ответ на: комментарий от robot12

В общем случае задача обновления монолитного проекта с миграциями БД и без даунтайма нерешаема.

Решаема, с контейнерами.

Расскажи, как контейнеры помогут в случае _монолитного_ сервиса.

tailgunner ★★★★★
()
Последнее исправление: tailgunner (всего исправлений: 1)
Ответ на: комментарий от leave

Если можно впихнуть контейнер - нужно впихнуть контейнер.

swelf
()
Ответ на: комментарий от robot12

Контейнер - монолитный сервис 1 шт. + Контейнер СУБД 1 шт. Перед ними балансировщик HTTP (nginx)

Прекрасно. И что дальше?

tailgunner ★★★★★
()
Ответ на: комментарий от robot12

два БД

Угу и как накатывать рассинканные данные?

anonymous
()
Ответ на: комментарий от tailgunner

И что дальше?

Расжевать ? Ладно.

Делаем в nginx upstream, туда вписываем app-контейнеры, с разными весами, выбираем время когда нагрузка на сайт снизится и вырубаем старый app-контейнер.

robot12 ★★★★★
()
Ответ на: комментарий от winlook38

хипстерской конференции.

микросервисы и per-process namespaces придуманы задолго до культуры хипстеров. И местами успешно применяются.

robot12 ★★★★★
()
Ответ на: комментарий от ProtoH

для этой проблемы, очевидно, нет универсального решения 8)

Deleted
()
Ответ на: комментарий от robot12

У ТСа кривой процесс деплоя, при котором приложение ломается от изменения схемы БД. Если ты обновишь оба контейнера, получишь даунтайм. Если ты обновишь один - даунтайм получат те, чьи данные были в БД обновленного контейнера. Где-то ты забыл рассказать нам про синхронизацию двух БД. Если в описываемой схеме добавить требование валидности схемы для обеих версий приложения, получится BGD, который я упоминал выше. Неужели на хипстерсокй конференции про BGD не рассказывали?

winlook38 ★★
()
Ответ на: комментарий от robot12

В описываемой тобой схеме контейнеры, докеры, микросервисы - лишние слова. Убери их и ничего не изменится.

winlook38 ★★
()
Ответ на: комментарий от robot12

При синтаксических ошибках nginx при reload старую конфигурацию не трогает. При логических — think before implement!

И таки да, ты нам не расказал, как ты собираешься синхронизировать 2 DB — новые записи в старой, новая схема в новой.

beastie ★★★★★
()
Последнее исправление: beastie (всего исправлений: 1)
Ответ на: комментарий от robot12

Делаем в nginx upstream, туда вписываем app-контейнеры, с разными весами, выбираем время когда нагрузка на сайт снизится и вырубаем старый app-контейнер.

И получаем две несинхронизированные БД.

tailgunner ★★★★★
()
Ответ на: комментарий от ProtoH

В данном случае — никак. Но вот тебе чуть-чуть чтива: http://www.grahambrooks.com/continuous delivery/continuous deployment/zero do...

TL;DR: если сделать так, что бы и старая и новая версия app могла работать с одной версией DB, то тогда это было бы возможно.

beastie ★★★★★
()
Ответ на: комментарий от robot12

Зачем эта ссылка на комикс полный картинок и воды? ТС ССЗБ и ломает схему. Что ты там собрался мигрировать? Выше написали, новые данные в старой базе, в новой базе старые данные. Тебе нужно мигрировать данные, но не схему.

winlook38 ★★
()
Ответ на: комментарий от ProtoH

В новой схеме могут быть исправлены косяки старой схемы + добавлены новые колонки, таблицы, и др. сущности БД.

Тут должен быть целый курс лекций на тему поддержка многих версий клиента при работе с СУБД. Если нужен плавный переход, то при внесении изменений в структуру это надо предусматривать. Это я вам как программист клиент-серверных приложений с большииим стажем говорю.

+ добавлены новые колонки, таблицы, и др. сущности БД.

Добавление никак не должно влиять на работу старого клиента.

anc ★★★★★
()
Ответ на: комментарий от winlook38

Вопрос в том, зачем вы ломаете схему БД для старой версии, а не исправляете схему таким образом, чтобы работали обе версии? Приведи мне пример, когда для исправления ошибки нужно сломать схему.

Вначале уточню, что я понимаю под схемой в данном контексте. Схема это структура сущностей БД (таблиц, views и т.д). Если у вас используется один движок (в данном случае это https://github.com/morpho-os/framework), то в процессе развития неизбежно изменение структуры таблиц - движок развивается, а сайты могут использовать старую версию. Если изменится структура таблиц, старый код перестанет работать без применения патчей. Если сделать патчи, то нужно обеспечить 0 downtime.

ProtoH
() автор топика
Ответ на: комментарий от ProtoH

Переформулирую вопрос. Что мешает изменять структуру БД таким образом, чтобы старая версия приложения не ломалась? Добавляя новые таблицы и столбцы вы не ломаете приложение. Удаляя, переименовывая - ломаете. Приведите пример, когда невозможно обойтись без удаления элемента модели данных или изменения его имени.

Вы ознакомились с материалами по ссылкам, которые вам предоставили?

winlook38 ★★
()
Ответ на: комментарий от winlook38

Вы в какие-то дебри уходите. Задача переключиться на новый код и БД с 0 downtime при этом все данные в БД должны быть синхронизированы.

ProtoH
() автор топика

В этой теме kawaii_neko привёл интересный вариант с mysqlproxy.

robot12 предложил вариант с Docker, однако который был тоже рассмотрен ещё до создания этой темы.

BGD не несёт ничего нового, очередной новый термин от Martin Fawler.

Большинство отвечающих похоже не читали предыдущие сообщения.

ProtoH
() автор топика
Ответ на: комментарий от ProtoH

Уже 200 раз разжевали же. Кроме как дополнить вариантом где в БД хранится некий scheme_version, равный например 1 для старой схемы и 2 для новой - ничего не могу предложить. А приложение соответственно переписать так, чтобы в зависимости от scheme_version - использовались возможности либо старой версии, либо новой.

Но есть 2 проблемы:

а) такое надо закладывать при проектировании;
б) если по-быдлятски реализовать сейчас - переход со схемы без версии на схему с версией чреват многими многими багами(и я тут даже не про отсутствие в схеме scheme_version - нет переменной, считай равной нулю, делов-то). И c zero downtime тут не получится.

Вообще, ИМХО, zero downtime надо или закладывать сразу(обычно - дорого), либо быть готовым к простою при переходе на систему где простоев при апгрейде больше не будет(в идеале).

Pinkbyte ★★★★★
()
Последнее исправление: Pinkbyte (всего исправлений: 1)
Ответ на: комментарий от ProtoH

3) Переписывать каким-то образом SQL-запросы поступающие от основного сервера к серверу c id == 2, так, чтобы они учитывали изменения скриптов миграции, например, колонка user.pass была переименована в user.password, соответственно нужно перехватывать и переписывать все SQL-запросы, чтобы они использовали колонку user.password.

Не угадал. Была добавлена колонка user.password, на user.pass навесили триггер, автокопирующий туда. Запускается миграция данных, которые были до триггера.

Когда миграция закончится — пушится новый код. Потом уже можно удалять старую колонку.

x3al ★★★★★
()
Ответ на: комментарий от x3al

Но в общем случае — грабли, поэтому нужно было думать о zero downtime раньше.

x3al ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.