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

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

Вообще, эта статья задумывалась как некий чек-лист, чтобы с ним сверяться сотрудникам, которые начинают заниматься нагруженными (и критичными к downtime) проектами.

Если я что-то забыл написать, пожалуйста, дополните в комментах, я добавлю в статью.
Как вам вариант реализовать взаимодействие клиент-сервер с явным указанием версии клиентской части в запросе как это советуют делать в статье "RESTful API для сервера – делаем правильно" в разделе «Разделение на версии»?

Конечно, проблему изменения адресов это не решит, но вопросы, связанные с полями формы и данными в сессии и куках, по-моему, решит отлично.
Я бы сказал, что этот подход не решает (по крайней мере нужны все те же шаги), но отлично формализует решение проблемы: вместо хакерства — понятная версионность.
В общем виде решение можно сформулировать так: необходимо обеспечить совместимость кода версии N+1 с состоянием версии N.


Отсюда следует, что необходимо обеспечить совместимость базыбазы версии N+1 с состоянием кодом версии N+2.
Чувствую верную мысль, но не могу понять из-за ошибок копипасты :)
Это ошибки Swype, за ним глаз да глаз… про сути, ошибка одна: задвоение слова «базы», и на понятность утверждения влиять не должна…

посему, поясняю: я имел ввиду, что делая фичу, потребующую изменения базы, придется сначала частично выпускать изменение базы (в рамках версии n+1), которое будет готовить её к появлению фичи, и только потом (скорее всего, следующей версией n+2) саму фичу и подчищение хвостов в базе…

Хотя, сейчас меня по этому поводу сомнения взяли… версии всё же по всякому можно собирать…
Поправил формулировку. Это общая идея, частности (описанные ниже), как обычно, сложнее.
А, копипаста таки тоже: «с состоянием кода», конечно же.
Под состоянием (state) в данном случае подразумевается совокупность данных приложения в базе, оперативной памяти сервера, на клиенте и т. д.
Мы сделали немножко иную схему: перед кодом приложения стоит прослойка, которая смотрит версию базы данных и в зависимости от версии базы данных передаёт управления на текущий или будущий код.

Когда нужно обновиться, мы последовательно подгружаем на app-ноды к текущему коду новый код (а прослойке говорим, что появилась новая версия), а затем последовательно проводим обновление структур баз данных клиентов.

Поэтому есть тормоза на время обновления БД, но нам пока везёт — базы наших клиентов небольшие, обновления происходят за 1-2 секунды, что, в целом, незаметно.
А на чем работаете (в смысле технологий)?
В основе всего Python + PgSQL.
т.е. у вас в дополнение к фронт-ендам и БД, есть ещё один слой, отъедающий время и лишний запрос к БД за каждый запрос к серверу?
очень интересный у вас «high-load»
Не совсем =) Просто на той же ноде (на том же frontend-е) есть код, который и определяет, в какую версию кода приложения нужно «перейти». Ну и для уменьшения запросов версия структуры БД кэшируется.
> код, который и определяет, в какую версию кода приложения нужно «перейти»
ну то есть именно слой, просто прямо внутри приложения?
> для уменьшения запросов версия структуры БД кэшируется
т.е. мало того, что эта хрень жрёт лишнее время исполнения, она ещё и не риал-тайм? так зачем она вообще нужна?
Ну, если считать код вида if (newVersion()) { include 1; } else { include 2; } «отдельным слоем», то да, это отдельный слой.

Почему не realtime? Кэш с информацией о конкретной БД сбрасывается в момент обновления БД.
Если база классическая (MySQL, структура таблицы в sql), то изменение структуры данных (добавление поля, например) на таблице порядка 100'000 записей (или миллиона, но не больше) может занимать минут 15. В это время база вообще не работает и все красивые рассуждения рушатся. Обновление кода zero-downtime понятно как делать. Обновление базы — операция хитрая, есть разные способы в зависимости от деталей приложения. В большинстве систем, с учетом возможного кол-ва ошибок из-за сложного обновления, все равно эффективней (по деньгам для проекта) обновлять «ночью» с приостановкой сервиса, если требуется изменение SQL-структуры данных.
Для MySQL подход похожий, но чуть сложнее. Свежие форки table_migrator в помощь :)
Весомый довод в пользу PostgreSQL: у него только операции изменения поля и создания поля со значением по умолчанию происходят за O(n). Остальное — создание nullable поля, удаление поля и даже индексирование (create index concurrently) — происходят за O(1) и, следовательно, локами можно пренебречь.

Изменение поля при описываемом в статье подходе не требуется. Поле not null default ... во многих случаях можно заменить на прописанное в коде значение по умолчанию.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий