Накопить за 7 лет терабайты данных в монолите и решить, что пора оптимизировать систему и разбивать её на микросервисы — страшный сон для айтишника. Добавим сюда ещё база на решениях от 1С и необходимость обеспечить непрерывность процесса. Стало страшно? А для нас — возможность показать экспертность и решить нетривиальную задачу. О том, как «кролик» помог сдвинуть гору рассказал архитектор 1С компании «Автомакон» Виталий Осиповский.
С 2013 года ВкусВилл проводил внутреннюю автоматизацию с использованием программ на базе 1С. За годы активного развития и эксплуатации база увеличилась до нескольких терабайт, кратно выросло количество операций, что спровоцировало большой объем работы для администраторов, оптимизаторов и команды разработчиков. Например, тяжелые алгоритмы планирования, закрытий, генерации документов могли негативно влиять на работу всей базы.
Любые сбои и простои были неадекватно затратны и влияли на все компоненты системы в целом. А сама система не годилась для быстрого масштабирования бизнеса. Поэтому уже в 2020 году приняли решение о поэтапном разделении монолита на отдельные программные компоненты.
Команда ВкусВилла сформировала следующие ключевые требования к новому функционалу систем:
-
Работа сотрудников должна быть также комфортна, как и в исходном монолите. Механизмы интеграции должны быть скрыты от рядового пользователя.
-
Слабая связность, а именно независимое функционирование, т.е. при изменениях, техническом обслуживании или остановке одних компонент другие должны продолжать функционировать в прежнем режиме.
-
Масштабирование — возможность добавлять новые компоненты путем настройки без существенных доработок.
Процессы внутри монолита сильно связаны по коду и данным, качественно разделить их оказалось сложной задачей. На первом этапе решили запустить компоненты на единой кодовой базе, отключив в каждой из них неиспользуемый функционал, а для синхронизации общих данных использовать обмен.
Приступаем к разбиению монолита
В качестве технологии, обеспечивающей обмен данными между компонентами, был выбран RabbitMQ, а технологии сериализации сообщений — «Конвертация данных 3.0» от 1С.
В используемой программе 1C набор общих данных был довольно масштабен: все данные были доступны для всех процессов, точное разделение и рефакторинг процессов могли серьезно увеличить время реализации проекта, а их отсутствие — серьезно усложнить и перегрузить обмен.
Команда проекта разработала план. Он предполагал решение вопроса самых объемных и интенсивно изменяющихся структур данных. А уже после разделения можно было проводить плановую тонкую оптимизацию и перестройку.

Рис. 1. Старая и новая схема компонентов.
Для того, чтобы исключить влияние на работу основного функционала, в новой архитектуре отправкой и получением сообщений занимаются отдельные процессы.
На первом этапе генерацией сообщений также занимался отдельный процесс, который запускался по расписанию и формировал сообщения о текущем состоянии всех измененных объектов. Он был реализован на механизме фоновых заданий.
Такой подход привел к следующим результатам: если между запусками генератора объект успевал многократно измениться, формировалось только одно сообщение с последним его состоянием. При этом история изменений объекта в базах получателях оставалась неполной, что зачастую было неудобно пользователям. В итоге генератор сообщений поместили в процесс — источник изменения.

How It’s Made
Команда придумала, как оптимизировать процессы отправки и получения сообщений с помощью RabbitMQ. Вот какой алгоритм у нас получился в итоге.
Процесс отправки
Этап 1. Формирование сообщений для «Документа» стартует в подписке на событие «ПриЗаписи».
-
Определение, что «Документ» участвует в обмене. Иначе ничего делать не нужно.
-
Проверка, что запись выполняется не обменом. Объекты, полученные из обмена, не должны снова регистрироваться в обмен при записи. Для этого процедура приема сообщений добавляет дополнительное свойство записываемому объекту, по которому можно понять, что объект отправлять не нужно.
-
Проверка, что отправка объекта разрешена. Отсеивание объектов по сложным критериям. Например, не выгружать в статусах «Оформление/Подготовка», но выгружать в статусе «Готов». Это может кратно уменьшить количество версий в обмене.
-
Получение настроек маршрутизации. Для отправки необходимо знать сервер, точку обмена, виртуальный хост и ключ маршрутизации. Возможны два способа задания ключа маршрутизации — явное указание ключа для объекта, либо программный алгоритм для сложных случаев. Программно решаются, например, кейсы с несколькими базами складов, где решение об отправке документа принимается на основе свойств «Склада» указанного в документе.
Если ключи не определены, алгоритм завершается.
-
Сериализация объекта по правилам «Конвертации данных».
-
Запись в регистр «ИсходящиеСообщенияRMQ» сообщения и соответствующих параметров отправки.
Этап 2. Отправка сообщений. Выполняется отдельными процессами в разрезе подключения Rabbit и ключа маршрутизации.
-
Чтение массива сообщений из регистра «ИсходящиеСообщенияRMQ» для заданного ключа маршрутизации.
-
Подключение к Rabbit.
-
В цикле отправка сообщений. Если отправка прошла успешно, удаление сообщения из «ИсходящиеСообщенияRMQ» запись в «ОтправленныеСообщенияRMQ».
Процесс получения
Этап 1. Получение сообщений и сохранение объектов в базу, выполняется фоновыми заданиями в разрезе очередей. 1 очередь = 1 задание.
-
Подключение к Rabbit и чтение сообщений в цикле.
-
Десериализация сообщений в объекты по правилам «Конвертации данных».
-
Запись объекта в базу в режиме «ОбменДанными.Загрузка» = истина.
-
Запись документа в регистр «ОтложенныеДвиженияДокументов».
-
Этап 2. Допроведение документа по регистрам, выполняется фоновыми заданиями.
Одно задание отвечает за допроведение нескольких типов документов.
Например, в монолите складские документы пишут проводки во вспомогательные регистры финучета. При разделении эти регистры не нужны для функционирования базы складов, поэтому в складских базах движения не выполняются. Когда документ передается в базу «Финансов», с ним передаются данные складских регистров (не формируются заново), а проводки регистров необходимые для базы «Финансов» формируются.
Решение для двустороннего обмена
Важным вопросом были задачи двустороннего обмена: возникает конфликт, когда один и тот же объект может быть изменен сразу в нескольких базах. Мы решили это следующими способами: явного указания приоритета определенной базы и разделения доступа по реквизитам, т.е. в каждой базе разрешено менять фиксированный набор реквизитов, непересекающийся с наборами реквизитов доступных для редактирования в других базах.

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

Маршрутизация Rabbit
Маршрутизация в Rabbit очень полезна не только для самих задач маршрутизации, но и балансировки нагрузки. Мы применяем ее в разных кейсах, если есть сообщения, которые должны быть доставлены нескольким получателям. Например, это относится к данным НСИ, изменение справочника «Номенклатура» в центральной базе должно быть доставлено во все базы, где предполагается работа с номенклатурой.
Изменения многих таблиц для одного получателя можно передавать через одну очередь, но бывают ситуации, когда изменений в таблице много и для нее обмен приходится осуществлять через две и более очереди для каждого получателя. При этом определением ключа маршрутизации можем гарантировать, что определенная запись будет попадать все время в одни и те же очереди, чтобы сохранить очередность версий для каждого объекта. Иногда в связи с бизнес-логикой приходится делить изменения в таблицах на оперативные (например, текущий день) и неоперативные. Оперативные необходимо выделять в отдельную очередь для ускорения их доставки получателям.
В зависимости от сложности передаваемых объектов скорости обработки достигают до 30 сообщений в секунду, некоторые сложные объекты обрабатываются по сообщению в секунду. Как правило, скорость приема меньше скорости отправки в очередь, что может быть потенциальной проблемой в случае, если кто-то решит перепровести документы за 3 года. Сейчас проблема решается на уровне «алармов» и отключением спамера от очереди, но поиск элегантного решения продолжается.
Ошибки и мониторинг
Для поддержки безотказного функционирования системы все части подключены к мониторингам, позволяющим поддержке оперативно реагировать на нештатные ситуации. Например, как только сообщение получило недопустимый ключ маршрутизации или просрочено максимальное время отправки в очередь, поддержка получает уведомление Telegram.
Rabbit подключен к мониторингу Zabbix для постоянного контроля жизнеспособности сервера и уведомляет о своих нештатных ситуациях, например, превышение допустимых лимитов на количество сообщений в очереди, объем используемой памяти.

Бывают ситуации, когда получатель не может «переварить» полученное сообщение. После нескольких попыток он помещает сообщение в отдельную, специально созданную для каждого получателя, очередь ошибок. Сообщения из очереди ошибок периодически обрабатываются отдельным регламентным заданием, при этом мониторинг уведомляет о данном инциденте через Telegram.
Заключение
С помощью подхода использования Rabbit и «Конвертация данных 3.0» удалось создать и поддерживать систему из 5 программных компонент, обменивающихся ~2 млн. сообщений в сутки, при этом процесс разделения продолжается. Rabbit показал себя исключительно надежной системой, обеспечивающей работу без сбоев в режиме 24/7.
*По данным исследования «INFOLine Retail Russia ТOP-100. Итоги 2021 года. Тенденции 2022 года»
ссылка на оригинал статьи https://habr.com/ru/company/automacon/blog/684322/
Добавить комментарий