Управление купонами на скидки в маркетплейсе Trendyol с Apache Kafka и Couchbase

Apache Kafka примеры курсы обучение, обучение дата-инженер Kafka, курсы Apache Kafka для разработчиков и дата-инженеров, Big Data Kafka маркетинг e-commerce кейсы примеры обучение, обучение большим данным, Школа Больших Данных Учебный Центр Коммерсант

Сегодня рассмотрим пример программы лояльности турецкого интернет-магазина Trendyol, где Apache Kafka и документо-ориентированная NoSQL-СУБД Couchbase используются для генерации купонов на скидки. Почему при большом объеме данных случаются проблемы тайм-аутов в Couchbase, как их решить и  при чем здесь коннекторы к Apache Kafka.

Архитектура системы управления купонами

Trendyol – это популярный турецкий маркетплейс с высокой посещаемостью. Основанная в 2010 году, сегодня эта e-commerce платформа насчитывает около 20 миллионов активных клиентов, среди которых не только частные лица, но и компании. Одним из способов повышения лояльности в ритейле являются скидки. Как и другие интернет-магазины, Trendyol активно пользуется этим инструментом, предоставляя своим пользователям купоны, которые дают скидки на покупки. Скидка по купону применяется к сумме корзины покупок. Купон может иметь различные условия, который ограничивают его область применения. Например, марка или категория товара, а также период длительности с привязкой к дате. В Trendyol один купон может быть создан с более чем 10 условиями и этим отличается от промокода, который обычно применяется в более простых кейсах.

Продавцы и команда CRM могут создавать купоны для клиентов, используя средства платформы Trendyol. Этот процесс отслеживается с помощью событий Google Analytics, чтобы маркетологи и разработчики могли повысить эффективность данной деятельности. Количество ежедневных запросов на создание купонов от продавцов считается ключевым показателем эффективности. Конверсия применения купона сравнивается с количеством созданных купонов, чтобы дать продавцам рекомендации по более эффективной работе с этим инструментом привлечения клиентов. В частности, разработана таблица для определения оптимального размера нижнего предела и скидки в зависимости от средней суммы корзины.

Получая запрос продавца на создание купона с информацией о бюджете, скидке, состоянии и пр., платформа определяет целевых клиентов с помощью интеллектуальных алгоритмов и генерирует купоны. Запросы передаются команде, которая отвечает за управление обслуживанием клиентов с помощью сценариев автоматизации. Команда CRM создает метаданные о купоне (имя, ссылки на изображения и пр.) и назначает купоны целевым клиентам, отправляя POST-запрос в API сервиса купонов.

Trendyol может генерировать около 8 миллионов купонов в час с помощью собственного средства с механизмом создания сообщения в топике Kafka и его считывания оттуда. До ноября 2021 года ежедневно создавалось около 30 миллионов купонов. Просроченные купоны перемещаются в архивную базу данных, а затем удаляются безвозвратно.

В изначальной архитектуре купоны с истекшим сроком действия искались через вторичный индекс в разделе купонов документо-ориентированной NoSQL-СУБД Couchbase. Но по мере роста количества таких купонов увеличивалась и нагрузка на Couchbase. Поэтому дизайн всей системы был изменен.

Информация о дате окончания срока действия купона и его идентификатор отправлялись в другую базу данных. Идентификатор купона позволяет отправлять запросы типа «ключ-значение» в Couchbase. Благодаря этой архитектуре можно архивировать примерно 10 миллионов купонов в день. Однако, при использовании вторичного индекса в Couchbase возникают проблемы с тайм-аутом. Поэтому была спроектирована новая архитектура, однако и она имела ряд сложностей, которые мы рассмотрим далее.

Apache Kafka Couchbase
Архитектура системы на Apache Kafka и Couchbase в Trendyol

Проблемы с тайм-аутом Couchbase и коннектор к Kafka

Благодаря широкому набору возможностей гибко настраивать условия для купонов, к ноябрю 2020 года в базе данных Trendyol было создано 300 миллионов активных купонов. Этот объем данных вызывал проблемы с тайм-аутом. В частности, из-за одного такого инцидента, который длился 12 часов, было невозможно применить купоны к разделам, поэтому покупатели не воспользовались скидками в тот период. Чтобы найти первопричину этих инцидентов, были проанализированы логии Couchbase SDK, включая регистрацию прохождения запроса с уровня приложения на уровень базы данных. Здесь были обнаружены потери на сетевом уровне. Для устранения этих проблем были выполнены аппаратные улучшения на стороне БД и изменен кластер.

Напомним, Couchbase — это распределенная база данных документов JSON с возможностями реляционной СУБД. Это надежная система для микросервисов и бессерверных облачных вычислений. Также она подходит для граничных вычислений и локально подключаемых пограничных устройств Mobile/IoT. Couchbase управляет документами JSON, устраняя необходимость в жестко закодированной схеме в базе данных. Определение объекта приложения, доступное в JSON, представляет собой схему, контролируемую разработчиком. JSON-документ записывается один раз в Couchbase и становится доступным для применения различных обработки данных, от SQL-подобных запросов для кэширования, полнотекстового поиска, аналитики и реактивного программирования, управляемого событиями для этой единственной копии данных.

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

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

Однако, после опроса удовлетворенности клиентов Trendyol в 2021 году было обнаружено, что тип скидки по купону не устраивает клиентов. По сути, пользователи не применяли купоны, которые ранее выдавались им алгоритмом таргетинга. Поэтому во второй половине 2021 года были разработаны новые фичи, например, «следить за магазином продавца и выиграть купон» и «собрать купон из сведений о продукте», список самых привлекательных купонов, игра по получению купона и др. Эти новые функции платформы увеличили коэффициент использования купонов в 10 раз. Поскольку количество способов создания купонов возросла, нужен эффективный способ листинга применимых купонов. Для этого используется архитектурный паттерн CQRS (Command Query Responsibility Segregation), основанный на идее того, что модели обновления и чтения информации могут различаться. Этот паттерн активно используется в системах на базе Apache Kafka, о чем мы писали здесь. Поскольку в платформе Trendyol очень много операций записи, было нужно разделить источники записи и чтения.

Чтобы получать уведомления, когда новая запись о купоне с истекшим сроком действия сохраняется в соответствующем разделе, было создано решение по принципу публикации/подписки на это событие. Apache Kafka часто применяется в подобных системах, поскольку поддерживает данную концепцию благодаря слушателям – специальным обработчикам, которые реагируют на определенные события. Это позволило создать конвейер публикации документа, сохраненного в раздел Couchbase как купон с истекшим сроком действия счета, в определенный топик Kafka.

Для связи Kafka c Couchbase использовался соответствующий коннектор, который передает документы с Couchbase Server с использованием высокопроизводительного протокола изменения базы данных (DCP) и публикует последнюю версию каждого документа в топике Kafka практически в режиме реального времени. Этот source-коннектор подписывается на топики Kafka и записывает сообщения в Couchbase.

Коннектор источника гарантирует по крайней мере одну (at least once) доставку последней версии каждого документа и в некоторых случаях может откатывать поток документов назад, чтобы перезапуститься с более ранней точки. За исключением перемотки, source-коннектор сохраняет порядок изменений в том же разделе Couchbase, и изменения в документе публикуются в том порядке, в котором они произошли. Однако, порядок между изменениями в разных разделах Couchbase не гарантируется. Когда документ удаляется из Couchbase из-за истечения срока действия, коннектор к Kafka не публикует удаление до тех пор, пока просроченный документ не будет удален из Couchbase.

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

Коннектор приемника гарантирует доставку по крайней мере одной (at least once) каждой записи в топике Kafka, записывая каждую запись Kafka в Couchbase, если запись не будет намеренно удалена специальным обработчиком приемника. Чтобы повысить вероятность того, что каждая запись сохранится после аварийного переключения Couchbase Server, рекомендуется настроить свойство конфигурации cockbase.durability. Если коннектору приемника не удается сохранить запись в Couchbase, он повторяет попытку до тайм-аута, указанного в свойстве конфигурации cockbase.retry.timeout. Если тайм-аут истек до того, как запись завершается успешно, коннектор закрывается. При перезапуске коннектора он возобновляет чтение из раздела Kafka со смещением, предшествующим остановке. Поэтому некоторые записи могут быть записаны в Couchbase более одного раза.

Если коннектор-приемник повторно обрабатывает записи после перезапуска, он сохраняет порядок изменений в том же разделе Kafka, и записи записываются в Couchbase в том порядке, в котором они были опубликованы в топике. А порядок между записями для записей в разных разделах Kafka не гарантируется. Чтобы гарантировать, что документы в Couchbase в конечном итоге согласуются с записями в теме Kafka, следует избегать случайного назначения разделов Kafka при публикации в топике. Лучше использовать стратегию назначения разделов по умолчанию или ту, которая назначает записи с одним и тем же ключом одному и тому же разделу.

Больше практических кейсов по администрированию и эксплуатации Apache Kafka для потоковой аналитики больших данных вы узнаете на специализированных курсах в нашем лицензированном учебном центре обучения и повышения квалификации для разработчиков, менеджеров, архитекторов, инженеров, администраторов, Data Scientist’ов и аналитиков Big Data в Москве:

Я даю свое согласие на обработку персональных данных и соглашаюсь с политикой конфиденциальности.

Источники

  1. https://medium.com/trendyol-tech/trendyol-coupon-journey-survive-active-500m-coupons-6d853f8d9bbb
  2. https://docs.couchbase.com/server/current/introduction/why-couchbase.html
  3. https://medium.com/trendyol-tech/implementing-a-delay-queue-with-kafka-connectors-and-couchbase-eventing-b83727d3d4c6
  4. https://docs.couchbase.com/kafka-connector/current/index.html

 

Поиск по сайту