От монолита к модулям: как отстроены бизнес-процессы склада Lamoda

Привет! Меня зовут Евгений Рябышев, я разработчик в одной из команд направления Warehouse Management System (WMS) компании Lamoda. Я занимаюсь тем, что автоматизирую склад. В этой статье расскажу, как мы строим нашу модульную архитектуру.

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

k24uqaluf0mwctug_l-gajbghtc.jpeg


Складские бизнес-процессы: от поступления товара до отправки заказчику

В настоящий момент WMS — это монолитная архитектура, которая поставляется единым .ear-файлом и разворачивается в контейнеры приложения в Wildfly. Она позволяет управлять тремя основными бизнес-процессами на складе.

Inbound отвечает за входящий поток товаров, партнерских или наших собственных, которые мы покупаем для реализации через сайт или мобильное приложение. Внутри есть бизнес-процессы, связанные с товарами: Rejects и Claims (возвраты и претензии, соответственно). Если одежда или обувь не подошла покупателю, мы возвращаем эти вещи и кладем обратно на склад.

rhcvtf8hqyldle41mqpkkt_teiu.png

Тут же находится бизнес-процесс CIC (Central Inbound Clearing). Он позволяет сотрудникам склада решать проблемы во время приемки товаров. Например, на товаре нет наклейки, и они перепечатывают ее, или товар не соотносится с картинкой, к которой он привязан.

Outbound — исходящий поток товаров. Когда пользователь делает заказ в Lamoda, все начинается с Order Management. Это подпроцесс, который отвечает за старт сборки заказов.

gd8iwwle5_uzdib9w9rdst1btdg.png

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


  • Полуавтоматическая упаковка Item Sorter.
  • Ручная упаковка через minibatch. Это рабочее место с компьютером и столом, где находится упаковочный материал.
  • Автоматическая упаковка через АВМ (Auto Bagging Machine или автоматическую упаковочную машину).

Процесс ручной упаковки с помощью minibatch

После этого мы размещаем товары на паллеты. Начинается подпроцесс Palletising: заказы отправляются к месту назначения. Тут же есть подпроцесс СОС (Central Outbound Clearing). Он используется для аналогичных целей, что и Central Inbound Clearing, но только на этапе отгрузки.

Stock — последний основной бизнес-процесс.

3ltg6jxmwb1wh4t3_gdhq-voup8.png

В нем есть три подпроцеса.


  • Putaway занимается размещением товаров на складе.
  • Picking отвечает за сборку товаров для заказа и для внутреннего аудита. Например, когда менеджеры хотят проверить срок годности косметики.
  • Inventory (инвентаризация). Он нужен, чтобы проводить частичную или полную инвентаризацию на складе.

Архитектура WMS: из чего она состоит

zfkkpwtzt9yv9rlcrp4sk-eygjy.png

Первый компонент — Printing service, который отвечает за распечатывание этикеток. Они расклеиваются везде: на паллеты, товары, контейнеры, рабочие станции — в общем, на все сущности, которыми управляет WMS. Следовательно, этикетка позволяет сотруднику склада понять, с чем сейчас он имеет дело.

6joctmb4hpco16bupeycjecyto8.jpeg

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

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

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

И последний компонент — ESB (Enterprise Service Bus). Он позволяет общаться с внешними системами, обрабатывать и получать заказы, отправлять сведения о том, что мы обработали заказы.


Почему бы не перейти на микросервисы? А вот почему

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

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

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

Допустим, пришла поставка и пользователь сканирует последний товар из нее, а затем делает запрос на наш сервер. Состояние товара сразу же меняется на «принят после сканирования». Меняется состояние заказа, затем поставки и грузовика. После этого должен измениться стейт склада, так как товар стал доступен для заказа на сайте.

У нас есть связанность между бизнес-процессами Stock и Inbound. И если что-то пойдет не так, мы всегда сможем откатиться благодаря механизмам транзакций в базе данных. Так что, микросервисы нам не очень подходят.

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

Также мы рассматривали для модульной архитектуры OSGI-фреймворк, но для себя нашли в нем несколько минусов. Например, проблему с большим количеством зависимостей в разных модулях, которые могут конфликтовать между собой. К тому же, это не самая популярная технология, а связка spring и osgi тоже не очень распространена. Поэтому мы решили отказаться от него.


К какому решению пришли

Итак, у нас есть три основных бизнес-процесса. Значит, мы хотим иметь три сервиса, которые будут отвечать за каждый из них.

vsbyzggzsdliqlpmacupg0fkeoc.png

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

xntvhmkb8aapgsxzt4k2df_y7vs.png

Идея такова: мы делим бизнес логику на 3 основных модуля, а технические процессы (Printing Service, Conveyor Service, Tote Service и Auth Service) делаем общими, независимыми сервисами. Выглядит достаточно логично, поскольку оборудование на складе может выходить из строя, не работать, модернизироваться, обновляться. Допустим, сейчас у нас один поставщик оборудования, завтра придет другой, и на складе будет совсем другая автоматизация. Нам важно, чтобы это никак не влияло на наши основные бизнес-процессы.

-jofxqavdqf4lwuc94zejl6dbbw.png

В итоге получается следующая схема: три основных бизнес-процесса и четыре вспомогательных сервиса. Самое прикольное, что до сих пор остается одна база данных. То есть мы не теряем наших преимуществ в транзакции, и у нас нет проблем с распределенными транзакциями.

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


Что происходит сейчас


  • Завершили внедрение сервиса авторизации, который был написан на базе Keycloak. Сейчас мы активно переписываем наш Printing Service с использованием второго SpringBoot и Kotlin на беке.


  • Выпустили новый клиент для мобильных устройств, переписав его с JSP на Android — WMS Mobile. Теперь у нас нативное приложение для мобильных устройств, которое тратит меньше энергии и имеет огромное количество возможностей.


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


В итоге мы получили инкапсулированные бизнес-процессы внутри каждого бизнес-сервиса. Изменения в одном никак не будут влиять на логику в других.

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

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

© Habrahabr.ru