Tarantool: взгляд аналитика
Всем привет! Меня зовут Андрей Капустин. Я работаю системным аналитиком в Mail.ru Group. Наши продукты формируют единую экосистему для пользователя, в которой данные генерируют множество независимых инфраструктур: службы заказов такси и еды, почтовые сервисы, соцсети. Сегодня чем быстрее и точнее мы можем спрогнозировать потребность клиента, тем быстрее и вернее мы можем предложить ему наши продукты.
Многие системные аналитики и инженеры сейчас задаются вопросами:
- Как спроектировать архитектуру триггерной платформы для real-time маркетинга?
- Как организовать структуру данных, соответствующую требованиям маркетинговой стратегии взаимодействия с клиентами?
- Как обеспечить стабильную работу подобной системы в условиях очень высоких нагрузок?
В основе таких систем лежат технологии высоконагруженной обработки и анализа больших данных. Мы накопили немалый опыт в этих сферах. И на примере одной реальной истории расскажу о нашем подходе к аналитике и разработке решений в сфере Real-time Marketing с использованием Tarantool.
Однажды к нам за помощью обратился крупный телеком-оператор.
Задача была такая:
У нас больше 100 млн абонентов. Мы о них знаем очень много: текущий баланс, объём трафика, подключенные услуги, поездки, любимые места. Используем информацию, как умеем: собираем данные в течение дня, кладем в хранилище (DataLake) огромные объемы информации. Ночью запускаем обработчики, к утру формируем рекламные кампании и рассылаем предложения.А хотим делать всё то же самое в реальном времени!
Почему? Потому что чем быстрее телеком-оператор обрабатывает информацию, тем больше денег может заработать. Например, на импульсных покупках: пользователь в обеденное время проходит мимо кафе, и тут ему на телефон приходит скидка, чтобы он выбрал именно это кафе. То есть необходимо «всего-то» предложить нужный товар в правильный момент и помочь сразу откликнуться на предложение удобным способом.
Что нужно для решения бизнес-задачи:
- Определить потребность можно через Профиль клиента.
- Определить момент — по событиям жизни человека.
- Стимулировать отклики — выбрав оптимальный канал коммуникации.
Это называется маркетинг в реальном времени (Real-Time Marketing). Применительно к телеком-сфере — отправка абонентам релевантных персонифицированных сообщений в нужный момент с возможностью СРАЗУ откликнуться на предложение. Предложения могут формироваться как для целевой группы, так и для конкретного пользователя, при этом обработка запроса в любом случае должна выполняться real-time.
С технической точки зрения мы должны решить следующие задачи:
- Поддержание в актуальном состоянии данных более 100 млн абонентов;
- Обработка потока событий в режиме реального времени при нагрузке 30000 RPS;
- Формирование и маршрутизация адресных предложений абонентам с выполнением нефункциональных требований (время отклика, доступность и т.д.);
- Бесшовное подключение новых источников разнородных данных по абонентам.
«Реальное время» в данном случае означает обработку информации за 30 секунд. Дольше — уже бессмысленно, момент упущен, клиент ушел. А самое печальное, что в такой ситуации будет непонятно, почему мы предложили не то или не успели вовремя?
Получить ответ на этот вопрос очень важно для развития продукта:
- Маркетинговое продвижение своих продуктов: проверяем гипотезы, повышаем доход.
- Привлекаем потенциальных клиентов: вкладываемся в рекламу, захватываем рынок.
- Подключаем дополнительные сервисы или услуги: расширяем продуктовую линейку.
На каждом этапе легко ошибиться. И цена ошибки велика. Надо бить быстро и точно! А для этого информация о клиенте должна быть полная и актуальная. В этом случае информация действительно стоит денег!
Ведь чем больше мы знаем о наших клиентах, тем больше мы заработаем. Значит, добавление каждого нового параметра в профиль клиента повышает точность таргетирования. Но это непрерывный процесс, потому что:
- Клиентская база постоянно растет.
- Набор услуг расширяется.
В таких условиях очень эффективно сегментировать клиентскую базу. В данном случае было принято решение использовать механизм стратификации — многофакторной классификации абонентов.
Проще говоря, мы выделяем специфические группы абонентов (страты) по диапазонам значений неограниченного количества атрибутов. При этом абонент должен автоматически менять страту сразу при переходе значения атрибута в соответствующий диапазон.
На рисунке ниже пример трехмерной модели стратификации из детства. Шарик — это абонент.
Для каждого клиента мы можем посчитать, сколько потратили на его привлечение, сколько заработали и как именно. То есть мы знаем, сколько стоит информация, и сколько мы теряем, если не обновляем её.
Посчитали и решили — надо обновлять! И сразу появляются проблемы: всегда чего-то не хватает. В каждом проекте от заказчика приходят новые требования, которые противоречат ТЗ, архитектуре, друг другу и… здравому смыслу. Поддерживать целостность и актуальность данных с каждым днем всё сложнее. Появляются новые источники информации с новыми атрибутами, которые непонятно где хранить и как обрабатывать.
При этом надо учитывать, что чем сильнее нормализованы данные, тем больше в них ограничений, справочников, проверок. Тот, кто пробовал добавить «на ходу» пару полей в таблицу, знает какой это «головняк»: не лезет в текущую модель данных! И как заказчику объяснить, что если добавить новое поле, то придется переписать половину кода проекта?! «Лишние» аналитики на входе мы схлопываем или отбрасываем, и в итоге не можем сформировать релевантные предложения.
Западные коллеги называют этот эффект «Shit in — Shit out».
В результате данные занимают больше места и их сложнее обрабатывать. С увеличением объема информации это становится критичным, потому что скорость обработки транзакций падает. А наша цель — обрабатывать каждый запрос не более минуты при нагрузке в 30 000 запросов в секунду.
Вывод: для маркетинга в реальном времени нормализация не подходит при 100+ млн абонентов.
Мы пришли к решению в виде универсального профиля клиента. Он лежит в key-value-хранилище, поэтому мы можем не фиксировать структуру данных. Каждый столбец — это ключ и значение, которое может быть каким угодно.
У нас получилась комбинация из:
- Статических атрибутов, которые редко обновляются (ФИО, паспорт, адрес). Обязательный блок с ID.
- И динамического «хвоста» произвольной длины — часто обновляющихся данных, которые зависят от источника. Несколько независимых блоков для каждого источника.
Такой подход называется денормализация. Чем это удобно?
- «Хвост» можно не валидировать.
- Сохраняем «сырые» данные как есть без обработки.
- Сохраняем всю входящую информацию, ничего не теряем.
- Для загрузки данных источника достаточно знать ID клиента, по которому привязываем блок.
- Данные хранятся компактно (экономия до 2–3 раз), что особенно важно при больших объемах.
- Упрощается доступ к данным: мы можем обновлять и запрашивать только нужный блок информации.
Большие данные
Теперь нужно выбрать инструмент для реализации. Обычно это делает архитектор по требованиям, которые собрал аналитик. Очень важно выяснить НФТ — ожидаемый объем данных и уровень нагрузки. От этого зависит, какие способы хранения и обработки данных мы будем использовать.
Заголовок этой главы намекает, что наш сервис будет обрабатывать много данных. А много — это сколько? Давайте разберемся.
Данные можно считать большими, если в них невооруженным глазом не видны взаимосвязи.
Мы обрабатываем более 100 млн разных профилей клиентов, которые содержат неструктурированную информацию, часто обновляются и используются — это настоящие большие данные.
Необходимо кэшировать актуальные профили клиентов. Без хранения горячих данных в оперативной памяти не добиться обработки в реальном времени.
Высокая нагрузка
Теперь разберёмся с интенсивностью нагрузки, то есть с количеством запросов. Термин «высокая нагрузка» применяется для описания ситуаций, когда оборудование перестает выдерживать нагрузку.
Мы обрабатываем разные типы событий, которые происходят беспрерывно с интенсивностью от 10 до 30 тысяч запросов в секунду. При этом используется сложная бизнес-логика, а скорость реакции критична. Очевидно, что мы проектируем высоконагруженный сервис, который должен динамически масштабироваться в зависимости от мгновенной нагрузки.
Tarantool как ускоритель
Мы в Mail.ru Group для решения таких задач используем Tarantool. На Хабре уже много рассказано, как он устроен «под капотом», не буду повторяться, напомню лишь основные моменты:
Tarantool — это In-memory СУБД и сервер приложений в одном флаконе.
При работе с большим объёмом данных его целесообразно использовать двумя способами:
- Как витрину данных для кэширования информации в оперативной памяти ради ускорения доступа.
- Как сервер приложений для обработки данных по заданным правилам.
То есть бизнес-логика хранится рядом с данными, что жизненно важно для высоконагруженных сервисов. В нашем проекте мы использовали Tarantool как «умную» витрину данных со встроенной бизнес-логикой, по которой «на лету» происходит обработка входящего потока событий и информации.
Почему Tarantool эффективен для RTM:
- Кэширование горячих данных. Профиль клиента кэшируется в памяти, поэтому он всегда актуален.
- Сложные вычисления в реальном времени. Персональные предложения клиентам формируются в реальном времени на каждое событие.
- Отказоустойчивое и масштабируемое решение:
В нашем проекте два очевидных риска:
- Каждый новый подключенный сервис запрашивает информацию из профиля клиента, что в итоге может привести к значительному увеличению нагрузки на чтение для базы данных. В этом случае помогает репликация — создание требуемого количества инстансов Tarantool c копией базы данных, между которыми выполняется балансировка нагрузки на чтение.
- У нас огромная клиентская база, которая постоянно растет. При этом на смартфонах разных абонентов могут быть параллельно запущены одни и те же сервисы, каждый из которых обновляет профиль клиента в режиме реального времени. Таким образом, у нас стабильно высокая нагрузка на запись для базы данных. Репликация здесь не поможет, так как изменения профиля клиента необходимо дублировать на всех серверах. В данном случае необходимо выполнить шардирование, т.е. распределить 100 млн записей таблицы профилей клиентов между несколькими шардами, чтобы распараллелить обработку запросов и таким образом снизить нагрузку на запись. Самый простой пример — делим таблицу профилей клиентов по диапазонам значений ID. Для решения этой задачи в Tarantool предусмотрены инструменты горизонтального масштабирования, подробнее о которых можно прочитать, например, в статье «Тarantool Cartridge: шардирование Lua-бекенда в три строчки».
Заключение
Tarantool не заменяет Oracle или другие аналитические хранилища. При этом он эффективен для обработки большого объема данных в режиме реального времени. Мы успешно решили задачу заказчика в рамках согласованных сроков и бюджета проекта, так что рекомендую поэкспериментировать с этим инструментом при создании высоконагруженных сервисов.