Всем привет! Меня зовут Андрей Капустин. Я работаю системным аналитиком в Mail.ru Group. Наши продукты формируют единую экосистему для пользователя, в которой данные генерируют множество независимых инфраструктур: службы заказов такси и еды, почтовые сервисы, соцсети. Сегодня чем быстрее и точнее мы можем спрогнозировать потребность клиента, тем быстрее и вернее мы можем предложить ему наши продукты.

Многие системные аналитики и инженеры сейчас задаются вопросами:

  1. Как спроектировать архитектуру триггерной платформы для real-time маркетинга?
  2. Как организовать структуру данных, соответствующую требованиям маркетинговой стратегии взаимодействия с клиентами?
  3. Как обеспечить стабильную работу подобной системы в условиях очень высоких нагрузок?

В основе таких систем лежат технологии высоконагруженной обработки и анализа больших данных. Мы накопили немалый опыт в этих сферах. И на примере одной реальной истории расскажу о нашем подходе к аналитике и разработке решений в сфере Real-time Marketing с использованием Tarantool.

Однажды к нам за помощью обратился крупный телеком-оператор.

Задача была такая:

У нас больше 100 млн абонентов. Мы о них знаем очень много: текущий баланс, объём трафика, подключенные услуги, поездки, любимые места. Используем информацию, как умеем: собираем данные в течение дня, кладем в хранилище (DataLake) огромные объемы информации. Ночью запускаем обработчики, к утру формируем рекламные кампании и рассылаем предложения.

А хотим делать всё то же самое в реальном времени!

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



Что нужно для решения бизнес-задачи:

  • Определить потребность можно через Профиль клиента.
  • Определить момент — по событиям жизни человека.
  • Стимулировать отклики — выбрав оптимальный канал коммуникации.

Это называется маркетинг в реальном времени (Real-Time Marketing). Применительно к телеком-сфере — отправка абонентам релевантных персонифицированных сообщений в нужный момент с возможностью СРАЗУ откликнуться на предложение. Предложения могут формироваться как для целевой группы, так и для конкретного пользователя, при этом обработка запроса в любом случае должна выполняться real-time.

С технической точки зрения мы должны решить следующие задачи:

  • Поддержание в актуальном состоянии данных более 100 млн абонентов;
  • Обработка потока событий в режиме реального времени при нагрузке 30000 RPS;
  • Формирование и маршрутизация адресных предложений абонентам с выполнением нефункциональных требований (время отклика, доступность и т.д.);
  • Бесшовное подключение новых источников разнородных данных по абонентам.

«Реальное время» в данном случае означает обработку информации за 30 секунд. Дольше — уже бессмысленно, момент упущен, клиент ушел. А самое печальное, что в такой ситуации будет непонятно, почему (?) — мы предложили не то или не успели вовремя?

Получить ответ на этот вопрос очень важно для развития продукта:

  1. Маркетинговое продвижение своих продуктов: проверяем гипотезы, повышаем доход.
  2. Привлекаем потенциальных клиентов: вкладываемся в рекламу, захватываем рынок.
  3. Подключаем дополнительные сервисы или услуги: расширяем продуктовую линейку.

На каждом этапе легко ошибиться. И цена ошибки велика. Надо бить быстро и точно! А для этого информация о клиенте должна быть полная и актуальная. В этом случае информация действительно стоит денег!

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

  1. Клиентская база постоянно растет.
  2. Набор услуг расширяется.

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

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

На рисунке ниже пример трехмерной модели стратификации из детства. Шарик — это абонент.



Для каждого клиента мы можем посчитать, сколько потратили на его привлечение, сколько заработали и как именно. То есть мы знаем, сколько стоит информация, и сколько мы теряем, если не обновляем её.

Посчитали и решили — надо обновлять! И сразу появляются проблемы: всегда чего-то не хватает. В каждом проекте от заказчика приходят новые требования, которые противоречат ТЗ, архитектуре, друг другу и… здравому смыслу. Поддерживать целостность и актуальность данных с каждым днем всё сложнее. Появляются новые источники информации с новыми атрибутами, которые непонятно где хранить и как обрабатывать.

При этом надо учитывать, что чем сильнее нормализованы данные, тем больше в них ограничений, справочников, проверок. Тот, кто пробовал добавить «на ходу» пару полей в таблицу, знает какой это «головняк»: не лезет в текущую модель данных! И как заказчику объяснить, что если добавить новое поле, то придется переписать половину кода проекта?! «Лишние» аналитики на входе мы схлопываем или отбрасываем, и в итоге не можем сформировать релевантные предложения.

Западные коллеги называют этот эффект «Shit in — Shit out».

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

Вывод: для маркетинга в реальном времени нормализация не подходит при 100+ млн абонентов.

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

У нас получилась комбинация из:

  • Статических атрибутов, которые редко обновляются (ФИО, паспорт, адрес). Обязательный блок с ID.
  • И динамического «хвоста» произвольной длины — часто обновляющихся данных, которые зависят от источника. Несколько независимых блоков для каждого источника.

Такой подход называется денормализация. Чем это удобно?

  1. «Хвост» можно не валидировать.
  2. Сохраняем «сырые» данные как есть без обработки.
  3. Сохраняем всю входящую информацию, ничего не теряем.
  4. Для загрузки данных источника достаточно знать ID клиента, по которому привязываем блок.
  5. Данные хранятся компактно (экономия до 2-3 раз), что особенно важно при больших объемах.
  6. Упрощается доступ к данным: мы можем обновлять и запрашивать только нужный блок информации.

Большие данные


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

Заголовок этой главы намекает, что наш сервис будет обрабатывать много данных. А много — это сколько? Давайте разберемся.

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

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

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

Высокая нагрузка


Теперь разберёмся с интенсивностью нагрузки, то есть с количеством запросов. Термин «высокая нагрузка» применяется для описания ситуаций, когда оборудование перестает выдерживать нагрузку.

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

Tarantool как ускоритель


Мы в Mail.ru Group для решения таких задач используем Tarantool. На Хабре уже много рассказано, как он устроен «под капотом», не буду повторяться, напомню лишь основные моменты:

Tarantool — это In-memory СУБД и сервер приложений в одном флаконе.

При работе с большим объёмом данных его целесообразно использовать двумя способами:

  1. Как витрину данных для кэширования информации в оперативной памяти ради ускорения доступа.
  2. Как сервер приложений для обработки данных по заданным правилам.

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

Почему Tarantool эффективен для RTM:

  1. Кэширование горячих данных. Профиль клиента кэшируется в памяти, поэтому он всегда актуален.
  2. Сложные вычисления в реальном времени. Персональные предложения клиентам формируются в реальном времени на каждое событие.
  3. Отказоустойчивое и масштабируемое решение:

В нашем проекте два очевидных риска:

  1. Каждый новый подключенный сервис запрашивает информацию из профиля клиента, что в итоге может привести к значительному увеличению нагрузки на чтение для базы данных. В этом случае помогает репликация — создание требуемого количества инстансов Tarantool c копией базы данных, между которыми выполняется балансировка нагрузки на чтение.
  2. У нас огромная клиентская база, которая постоянно растет. При этом на смартфонах разных абонентов могут быть параллельно запущены одни и те же сервисы, каждый из которых обновляет профиль клиента в режиме реального времени. Таким образом, у нас стабильно высокая нагрузка на запись для базы данных. Репликация здесь не поможет, так как изменения профиля клиента необходимо дублировать на всех серверах. В данном случае необходимо выполнить шардирование, т.е. распределить 100 млн записей таблицы профилей клиентов между несколькими шардами, чтобы распараллелить обработку запросов и таким образом снизить нагрузку на запись. Самый простой пример — делим таблицу профилей клиентов по диапазонам значений ID. Для решения этой задачи в Tarantool предусмотрены инструменты горизонтального масштабирования, подробнее о которых можно прочитать, например, в статье «Тarantool Cartridge: шардирование Lua-бекенда в три строчки».

Заключение


Tarantool не заменяет Oracle или другие аналитические хранилища. При этом он эффективен для обработки большого объема данных в режиме реального времени. Мы успешно решили задачу заказчика в рамках согласованных сроков и бюджета проекта, так что рекомендую поэкспериментировать с этим инструментом при создании высоконагруженных сервисов.