HTML Diff
0 added 0 removed
Original 2026-01-01
Modified 2026-02-26
1 <p>База данных - ключевая часть практически любой инфраструктуры. Ее потеря может привести к потере всего бизнеса. Обеспечить бесперебойную работу базы сложно, для этого требуются квалифицированные администраторы, умеющие хорошо настраивать, мониторить, бекапить, восстанавливать и масштабировать.</p>
1 <p>База данных - ключевая часть практически любой инфраструктуры. Ее потеря может привести к потере всего бизнеса. Обеспечить бесперебойную работу базы сложно, для этого требуются квалифицированные администраторы, умеющие хорошо настраивать, мониторить, бекапить, восстанавливать и масштабировать.</p>
2 <p>Задача настолько не тривиальная, что компании стараются свести свое участие в управлении базами к минимуму. Там где возможно, используются готовые облачные решения от Amazon, Google, DigitalOcean и других. Облачная база данных предоставляется как сервис, который умеет автоматически делать бекапы и восстанавливать их, обеспечивать отказоустойчивость за счет автоматического переключения на запасную копию базы и многое другое.</p>
2 <p>Задача настолько не тривиальная, что компании стараются свести свое участие в управлении базами к минимуму. Там где возможно, используются готовые облачные решения от Amazon, Google, DigitalOcean и других. Облачная база данных предоставляется как сервис, который умеет автоматически делать бекапы и восстанавливать их, обеспечивать отказоустойчивость за счет автоматического переключения на запасную копию базы и многое другое.</p>
3 <p>Даже если база данных управляется самостоятельно, она все равно должна находиться на выделенном сервере. Почему это важно:</p>
3 <p>Даже если база данных управляется самостоятельно, она все равно должна находиться на выделенном сервере. Почему это важно:</p>
4 <ol><li>База данных конкурирует с приложением за ресурсы сервера и в итоге тормозят все</li>
4 <ol><li>База данных конкурирует с приложением за ресурсы сервера и в итоге тормозят все</li>
5 <li>У баз данных свой тип нагрузки, под который нужны сервера со специфическими характеристиками</li>
5 <li>У баз данных свой тип нагрузки, под который нужны сервера со специфическими характеристиками</li>
6 <li>К базам данных предъявляются гораздо более высокие стандарты по надежности и безопасности</li>
6 <li>К базам данных предъявляются гораздо более высокие стандарты по надежности и безопасности</li>
7 <li>Программисты любят ходить на сервера с кодом и могут случайно удалить базу данных</li>
7 <li>Программисты любят ходить на сервера с кодом и могут случайно удалить базу данных</li>
8 <li>Без этого невозможно горизонтальное масштабирования</li>
8 <li>Без этого невозможно горизонтальное масштабирования</li>
9 </ol><h2>Миграции</h2>
9 </ol><h2>Миграции</h2>
10 <p>Миграции базы данных это изменения ее схемы и данных, которые возникают во время разработки. Когда разработчику нужно добавить, удалить или изменить поля в таблице, он создает миграцию. Создание таблицы это тоже миграции, как и любые другие действия над базой данных.</p>
10 <p>Миграции базы данных это изменения ее схемы и данных, которые возникают во время разработки. Когда разработчику нужно добавить, удалить или изменить поля в таблице, он создает миграцию. Создание таблицы это тоже миграции, как и любые другие действия над базой данных.</p>
11 <p>Миграции часто хранят в sql-файлах. Некоторые фреймворки вместо SQL дают свой собственный язык, который упрощает их написание:</p>
11 <p>Миграции часто хранят в sql-файлах. Некоторые фреймворки вместо SQL дают свой собственный язык, который упрощает их написание:</p>
12 <p>Во время деплоя, новые миграции "накатываются" на базу данных с помощью команды используемого фреймворка:</p>
12 <p>Во время деплоя, новые миграции "накатываются" на базу данных с помощью команды используемого фреймворка:</p>
13 <p>Бывают ситуации, когда миграции нужно откатить. Например, во время разработки, когда разработчик написал и выполнил миграцию, он, вдруг, понимает что ошибся. В таком случае он может выполнить откат миграций:</p>
13 <p>Бывают ситуации, когда миграции нужно откатить. Например, во время разработки, когда разработчик написал и выполнил миграцию, он, вдруг, понимает что ошибся. В таком случае он может выполнить откат миграций:</p>
14 <p>Откат миграций не работает сам по себе. Для отката нужно знать как это сделать. Для этого каждая миграция состоит из двух частей:<em>up</em>, в которой описывается движение вперед и<em>down</em>, в которой описывается движение назад:</p>
14 <p>Откат миграций не работает сам по себе. Для отката нужно знать как это сделать. Для этого каждая миграция состоит из двух частей:<em>up</em>, в которой описывается движение вперед и<em>down</em>, в которой описывается движение назад:</p>
15 <p>Но нужно учитывать, что миграции могут приводит к потере данных. Удаление колонок и таблиц - очень опасные операции, которые надо выполнять с большой осторожностью.</p>
15 <p>Но нужно учитывать, что миграции могут приводит к потере данных. Удаление колонок и таблиц - очень опасные операции, которые надо выполнять с большой осторожностью.</p>
16 <h2>Деплой</h2>
16 <h2>Деплой</h2>
17 <p>В какой момент применять миграции? Обычно, миграции применяют во время запуска новой версии приложения в конце деплоя. Это гарантирует минимальное время простоя. Весь процесс выглядит так:</p>
17 <p>В какой момент применять миграции? Обычно, миграции применяют во время запуска новой версии приложения в конце деплоя. Это гарантирует минимальное время простоя. Весь процесс выглядит так:</p>
18 <ol><li>Приложение устанавливается на все сервера</li>
18 <ol><li>Приложение устанавливается на все сервера</li>
19 <li>Останавливается старая версия приложения</li>
19 <li>Останавливается старая версия приложения</li>
20 <li>Накатываются миграции</li>
20 <li>Накатываются миграции</li>
21 <li>Запускается новая версия приложения</li>
21 <li>Запускается новая версия приложения</li>
22 </ol><p>Почему миграции накатываются после остановки старой версии, а не до? Миграции могут ломать работу старого кода. Например удаление таблицы, которая использовалась раньше, но после деплоя будет не нужна. Если накатывать такие миграции до остановки, то пользователи увидят ошибки 500, что плохо.</p>
22 </ol><p>Почему миграции накатываются после остановки старой версии, а не до? Миграции могут ломать работу старого кода. Например удаление таблицы, которая использовалась раньше, но после деплоя будет не нужна. Если накатывать такие миграции до остановки, то пользователи увидят ошибки 500, что плохо.</p>
23 <p>С другой стороны, иногда миграции накатываются очень долго, десятки минут, часы и даже дни. В таком случае их выполняют до деплоя. Но как это сделать, если возникает ситуация с удалением таблицы как было описано выше? А что с откатами миграций при ошибках после или во время деплоя? А как восстановить данные?</p>
23 <p>С другой стороны, иногда миграции накатываются очень долго, десятки минут, часы и даже дни. В таком случае их выполняют до деплоя. Но как это сделать, если возникает ситуация с удалением таблицы как было описано выше? А что с откатами миграций при ошибках после или во время деплоя? А как восстановить данные?</p>
24 <p>Все эти вопросы связаны между собой. Они появляются из-за нарушения обратной совместимости схемы базы данных. То есть новая схема базы данных работает с новой версией приложения и не работает со старой. Единственный способ разрешить эту ситуацию - не ломать обратную совместимость. Вносить только такие изменения, которые расширяют текущую схему, оставляя ее рабочей для предыдущей версии. Как? Не переименовывать, не удалять, менять колонки только в сторону расширения, а не сужения. Увеличивать размер текстового поля можно, уменьшать нельзя.</p>
24 <p>Все эти вопросы связаны между собой. Они появляются из-за нарушения обратной совместимости схемы базы данных. То есть новая схема базы данных работает с новой версией приложения и не работает со старой. Единственный способ разрешить эту ситуацию - не ломать обратную совместимость. Вносить только такие изменения, которые расширяют текущую схему, оставляя ее рабочей для предыдущей версии. Как? Не переименовывать, не удалять, менять колонки только в сторону расширения, а не сужения. Увеличивать размер текстового поля можно, уменьшать нельзя.</p>
25 <p>При таком подходе большая часть проблем уходит целиком:</p>
25 <p>При таком подходе большая часть проблем уходит целиком:</p>
26 <ul><li>Деплой предыдущей версии приложения не требует отката миграций</li>
26 <ul><li>Деплой предыдущей версии приложения не требует отката миграций</li>
27 <li>Не возникает конфликтов между старой и новой версией</li>
27 <li>Не возникает конфликтов между старой и новой версией</li>
28 <li>Данные никогда не теряются</li>
28 <li>Данные никогда не теряются</li>
29 </ul><p>Даже уменьшается время деплоя, за счет другого порядка действий:</p>
29 </ul><p>Даже уменьшается время деплоя, за счет другого порядка действий:</p>
30 <ol><li>Приложение устанавливается на все сервера</li>
30 <ol><li>Приложение устанавливается на все сервера</li>
31 <li>Накатываются миграции</li>
31 <li>Накатываются миграции</li>
32 <li>Останавливается старая версия приложения</li>
32 <li>Останавливается старая версия приложения</li>
33 <li>Запускается новая версия приложения</li>
33 <li>Запускается новая версия приложения</li>
34 </ol><h2>Zero Downtime Deploy</h2>
34 </ol><h2>Zero Downtime Deploy</h2>
35 <p>Бонусом к сказанному выше, мы получаем возможность выполнять деплой без остановки работы. Вы замечали, что крупные сервисы постоянно обновляются, но никогда не останавливают свою работу? Как это технически возможно?</p>
35 <p>Бонусом к сказанному выше, мы получаем возможность выполнять деплой без остановки работы. Вы замечали, что крупные сервисы постоянно обновляются, но никогда не останавливают свою работу? Как это технически возможно?</p>
36 <p>Теперь мы можем ответить на этот вопрос. Для деплоя без остановки, не нужно останавливать старую версию приложения. Сначала поднимается новая и, только, затем выключается текущая. Представьте что у нас есть приложение, в котором есть база данных, балансировщик и две машины с приложением. Вот один из вариантов деплоя:</p>
36 <p>Теперь мы можем ответить на этот вопрос. Для деплоя без остановки, не нужно останавливать старую версию приложения. Сначала поднимается новая и, только, затем выключается текущая. Представьте что у нас есть приложение, в котором есть база данных, балансировщик и две машины с приложением. Вот один из вариантов деплоя:</p>
37 <ol><li>Скачиваем новую версию приложения на сервера</li>
37 <ol><li>Скачиваем новую версию приложения на сервера</li>
38 <li>Выполняем миграции с любого из серверов</li>
38 <li>Выполняем миграции с любого из серверов</li>
39 <li>Обновляем первый сервер<ol><li>Выводим сервер из под балансировщика, чтобы он не отправлял на него запросы</li>
39 <li>Обновляем первый сервер<ol><li>Выводим сервер из под балансировщика, чтобы он не отправлял на него запросы</li>
40 <li>Останавливаем текущую и запускаем новую версию приложения</li>
40 <li>Останавливаем текущую и запускаем новую версию приложения</li>
41 <li>Добавляем сервер в балансировщик</li>
41 <li>Добавляем сервер в балансировщик</li>
42 </ol></li>
42 </ol></li>
43 <li>Повторяем тоже самое со вторым сервером</li>
43 <li>Повторяем тоже самое со вторым сервером</li>
44 </ol><p>Без правильной работы с базой данных, деплой без остановки сервиса был бы невозможен.</p>
44 </ol><p>Без правильной работы с базой данных, деплой без остановки сервиса был бы невозможен.</p>