Горизонтальное масштабирование#

Для реализации горизонтального масштабирования SourceControl использует высокодоступную кластеризацию, спроектированную в соответствии с методиками обеспечения высокой доступности.

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

Кластеризация приложений#

В минимальной конфигурации кластер SourceControl включает в себя сервера балансировки, 2 сервера приложений, кластер базы данных, высокодоступное распределенное хранилище файлов репозиториев.

Особенности реализации:

  • Балансировка распределяет рабочие нагрузки по всем узлам, чтобы предотвратить перегрузку любого отдельного узла.

  • Сбой на одном из серверов кластера не приводит к отказу приложения.

  • На время недоступности какого-либо из экземпляров приложения, происходит автоматическое переключение на работу через другой экземпляр.

  • Поскольку для обслуживания доступно больше узлов, заметно улучшены пропускная способность и время отклика.

Запуск фоновых задач#

В SourceControl часть технических процессов, необходимых для обслуживания инсталляции, происходит в фоновом режиме:

  • Проверка состояния всех репозиториев;

  • Проверка статистики репозиториев;

  • Удаление старых архивов репозиториев;

  • Синхронизация данных внешних пользователей;

  • Очистка удаленных ветвей;

  • Обновление ID миграций;

  • Очистка таблицы задач хуков;

  • Очистка устаревших пакетов;

  • Удаление неактивированных учетных записей;

  • Удаление архивов репозиториев;

  • Сборка мусора для репозиториев;

  • Обновление файла с ключами SSH;

  • Обновление файла с данными участников;

  • Повторная синхронизация hooks pre-receive, update и post-receive во всех репозиториях;

  • Переинициализация всех отсутствующих Git репозиториев, для которых существуют записи;

  • Удаление записей о репозиториях с отсутствующими файлами Git;

  • Удаление сгенерированных аватар репозиториев;

  • Удаление старых действий из базы данных;

  • Проверка обновлений;

  • Удаление старых системных уведомлений из базы данных;

  • Сборка мусора метаобъектов LFS.

Многие из этих процессов обрабатывают большие объемы данных, поэтому являются ресурсоемкими.

При использовании кластерной архитектуры, когда запущено несколько экземпляров приложения, может возникать ситуация, когда копии одного и того же фонового процесса будут несколько раз запущены на разных экземплярах.

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

Для предотвращения этого предусмотрен механизм блокировки:

  • при запуске определенного фонового процесса выставляется блокировка на запуск копий данного процесса;

  • при завершении выполнения фонового процесса блокировка снимется.

В таком случае при запуске фоновых процессов другие копии этих процессов не смогут запуститься до завершения исходных процессов.

Блокировка на запуск реализована через отдельную таблицу базы данных.

Просмотр таблицы фоновых задач#

Для фиксирования неудачных запусков в таблицу фоновых задач добавлены 2 колонки:

  • last_failed_run: время последнего неудачного запуска;

  • last_failed_run_message: сообщения об ошибке при неудачном запуске.

При запуске очередной задачи проводится проверка: если признак блокировки lock=true и с момента запуска задачи прошло более 30 секунд, то в колонку last_failed_run записывается время, а в колонку last_failed_message записывается ошибка: «Задача не была запущена».

При удачном статусе — поля last_failed_run и last_failed_run_message для задачи сбрасываются.

При наличии ошибок в задаче они будут выведены в интерфейсе просмотра задач планировщика с указанием времени — для просмотра администратором инсталляции:

alt text

По каждой такой задаче выводятся иконка статуса и кнопки «Сбросить статус» и «Запустить задачу».

При нажатии «Сбросить статус» статус сбрасывается в finished, lock ставится false, то есть задача возвращается в состояние, когда при следующем запуске она будет корректно запущена.

При нажатии «Запустить задачу» аналогично статус сбрасывается в finished, lock ставится false, и задача сразу запускается не из механизма планировщика, а из кода обработчика кнопки в асинхронном режиме.

Варианты отображения статуса:

Статус

Отображение в интерфейсе

registered

alt text

cancelled

alt text

error

alt text

finished

alt text

process

alt text

Механизм миграции БД#

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

Для механизма запуска скриптов миграции реализована возможность отключения.

Флаг включения/выключения запуска миграций устанавливается в конфигурации инсталляции и выставляется для всех экземпляров в значение AUTO_MIGRATION = true.

Автоматическое обновление БД#

Если установка доработок функциональности производится не вручную, а pipeline-скриптами сборки, может возникать ситуация, когда скрипты миграции будут запущены одновременно на нескольких экземплярах приложения.

Для такого случая система применения миграций БД работает в Liquibase-like формате:

  • при запуске миграции выставляется блокировка на запуск миграций;

  • при завершении миграции фиксируется версия примененной миграции и снимается блокировка.

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

Блокировка на запуск миграций реализована через отдельную таблицу.

Процесс миграции, который при запуске столкнулся с блокировкой, ожидает завершения предыдущей миграции в течение 30 секунд. Если за это время предыдущая миграция не завершается, то данный процесс также завершается.

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

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

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