Fraud-скоринг в реальном времени на масштабе
Как tracio.ai обрабатывает 50 тыс. событий/сек со скорингом менее 50 мс за счёт потоковой обработки, предвычисленных векторов сигналов и edge-кеширования.
Fraud-скоринг на масштабе требует принципиально иной архитектуры, чем пакетная обработка. Когда авторизуется платёж или создаётся аккаунт, у вас есть миллисекунды — а не минуты — чтобы выдать оценку риска. В tracio.ai мы обрабатываем более 50 000 событий в секунду с медианной задержкой скоринга 22 мс. В этой статье разбирается архитектура, которая делает это возможным.
Конвейер скоринга
Каждое входящее событие проходит трёхэтапный конвейер: обогащение сигналами, вычисление вектора и оценка риска. Обогащение сигналами добавляет к сырому событию данные device intelligence — отпечаток посетителя, результаты bot detection, IP-аналитику и историю поведения. Вычисление вектора преобразует эти обогащённые сигналы в вектор признаков фиксированной длины, оптимизированный под нашу модель скоринга. Оценка риска прогоняет вектор через обученную модель и возвращает оценку в диапазоне от 0.0 до 1.0.
Ключевое проектное решение в том, что обогащение и вычисление вектора отделены от скоринга. Данные обогащения предвычисляются и кешируются. Когда посетитель загружает страницу, мы вычисляем профиль его устройства и сохраняем в Redis с TTL 60 минут. Когда приходит запрос на скоринг — обычно инициированный платежом или входом в систему — мы извлекаем предвычисленный профиль вместо того, чтобы пересчитывать его. Это снижает задержку скоринга с 200+ мс до менее чем 30 мс.
Потоковая обработка на Go
Наш слой приёма событий написан на Go и использует архитектуру фанаута. Входящие события приходят через HTTP POST и сразу помещаются во внутренний канал. Пул воркеров-горутин читает из этого канала, выполняет обогащение и записывает обогащённые события в ClickHouse для аналитики и в очередь скоринга для обработки в реальном времени. Пул фанаута динамически масштабируется в зависимости от глубины очереди.
Мы выбрали Go для слоя приёма событий из-за его отличных примитивов параллелизма и предсказуемого выделения памяти. Каждая воркер-горутина потребляет примерно 4 КБ стека, что позволяет запускать тысячи одновременных воркеров на одном узле. Паузы сборщика мусора менее миллисекунды критичны для поддержания стабильной задержки при высокой пропускной способности.
Edge-кеширование и векторы сигналов
Для наших клиентов с самым большим объёмом трафика мы разворачиваем модели скоринга на edge, используя кеш предвычисленных векторов сигналов. Когда устройство встречается впервые, мы вычисляем его полный вектор сигналов и сохраняем в edge-кеше (развёрнутом на Cloudflare Workers KV). Последующие запросы на скоринг для того же устройства извлекают кешированный вектор и выполняют скоринг локально на edge, достигая задержки менее 10 мс.
Edge-модель скоринга — это дистиллированная версия нашей полной модели: меньше и быстрее, но оптимизированная под те же целевые показатели точности. Мы переобучаем edge-модель еженедельно и разворачиваем обновления методом rolling deployment, чтобы избежать лавины инвалидации кеша. Полная модель работает на стороне сервера для случаев, когда уверенность edge-модели ниже настраиваемого порога.
ClickHouse для аналитики
Все обогащённые события хранятся в ClickHouse — нашей колоночной аналитической базе данных. Сжатие и производительность запросов ClickHouse позволяют хранить миллиарды событий, поддерживая при этом аналитические запросы в реальном времени. Наши клиенты используют эту аналитику, чтобы понимать паттерны фрода, настраивать пороги скоринга и расследовать отдельные события.
Мы применяем материализованные представления в ClickHouse для поддержания предагрегированных метрик: доля фрода по странам, распределение скоринга по типам устройств и доля ложных срабатываний по порогам. Эти материализованные представления обновляются в реальном времени по мере поступления событий, предоставляя готовые для дашборда метрики без дорогих агрегирующих запросов.
Извлечённые уроки
Построение системы скоринга в реальном времени научило нас нескольким вещам. Во-первых, предвычисление — самая важная оптимизация: любая работа, которую можно выполнить до прихода запроса на скоринг, не расходует ваш бюджет задержки. Во-вторых, модель параллелизма Go хорошо подходит для обработки событий с высокой пропускной способностью, но нужно дисциплинированно относиться к выделению памяти, чтобы избежать давления на GC. В-третьих, развёртывание на edge преображает задержку, но требует аккуратного управления моделями, чтобы избежать устаревших предсказаний.