Построение конвейера аналитики фрода в реальном времени
Разбор архитектуры: приём 50K событий/сек, обогащение смарт-сигналами и оценка риска менее чем за 10 мс на нашем потоковом движке.
Обработка 50 000 событий фингерпринтинга в секунду, обогащение каждого смарт-сигналами и возврат оценки риска менее чем за 10 миллисекунд требуют тщательно спроектированной потоковой архитектуры. В этой статье мы проходим весь наш конвейер — от приёма до принятия решения.
Слой приёма
События приходят в виде HTTPS POST-запросов от нашего JavaScript-агента, работающего в браузерах посетителей. Каждое событие содержит зашифрованную полезную нагрузку сигналов — обычно 8–12 КБ сжатых данных, покрывающих 130+ сигналов браузера. Наши edge-серверы завершают TLS, проверяют подпись запроса и передают полезную нагрузку в конвейер обработки.
Мы используем мультирегиональное развёртывание, при котором edge-серверы размещены рядом с CDN-узлами наших клиентов. Это удерживает сетевой round-trip в пределах 20 мс для 95 % запросов по всему миру. Edge-серверы — это stateless-сервисы на Go, работающие за балансировщиком нагрузки и масштабирующиеся горизонтально в зависимости от объёма запросов.
Извлечение сигналов
Первый этап обработки расшифровывает и парсит полезную нагрузку сигналов. Каждый сигнал извлекается, проверяется и типизируется. Хеши canvas сверяются с известными невозможными значениями (которые указывают на блокировку или подмену canvas). Параметры WebGL перекрёстно проверяются на согласованность. Свойства navigator сопоставляются с известными допустимыми комбинациями.
На этом же этапе выполняется нормализация сигналов. Строки user agent разбираются на структурные компоненты (браузер, версия, ОС, устройство). Размеры экрана нормализуются с учётом DPI-масштабирования. Смещения часовых поясов проверяются относительно данных IP-геолокации.
Обогащение Smart Signals
Извлечённые сигналы затем обогащаются анализом Smart Signals — нашим серверным слоем интеллекта. Сюда входят детекция инкогнито (сравнение паттернов сигналов с известными сигнатурами приватного просмотра), детекция VPN (сопоставление данных IP с сигналами часового пояса и локали), детекция подмены браузера (выявление несоответствий, указывающих на спуфинг сигналов) и детекция виртуальных машин (распознавание аппаратных профилей, связанных с VMware, VirtualBox и облачными ВМ).
Каждый смарт-сигнал вычисляется независимо и выдаёт как булев результат, так и оценку уверенности. Этап обогащения добавляет к каждому событию 24 дополнительных сигнала, обеспечивая комплексную оценку угрозы, выходящую за пределы того, что достижимо одним только сбором на стороне клиента.
Движок скоринга риска
Обогащённое событие передаётся в наш движок скоринга риска — модель на основе дерева решений с градиентным бустингом, обученную на миллионах размеченных событий. Модель учитывает все 130+ сырых сигналов, 24 смарт-сигнала и несколько производных признаков: метрики скорости (сколько событий пришло с этого устройства за последние 5 минут, 1 час и 24 часа), исторические паттерны поведения и оценки репутации сети.
Модель выдаёт оценку риска от 0 до 100 вместе с главными факторами, повлиявшими на неё. Оценке 85, например, могут сопутствовать такие факторы, как «обнаружен VPN», «режим инкогнито» и «высокая скорость — 47 событий за 5 минут». Такая объяснимость критична для аналитиков фрода, которым нужно понимать, почему конкретное событие было помечено.
Слой хранения и запросов
Все события сохраняются в ClickHouse — колоночную базу данных, оптимизированную под аналитические запросы к большим наборам данных. ClickHouse справляется с нашим объёмом записи (50K событий/сек) без напряжения, а колоночное хранение обеспечивает аналитические запросы к миллиардам строк за доли секунды.
Мы применяем многоуровневую стратегию хранения. Горячие данные (последние 7 дней) хранятся на NVMe SSD для отклика запросов менее 100 мс. Тёплые данные (7–90 дней) — на обычных SSD. Холодные данные (90+ дней) сжимаются и переносятся в объектное хранилище: они остаются доступными для запросов, но с более высокой задержкой.
Kafka как основа
Apache Kafka связывает конвейер воедино. Каждый этап читает из топиков Kafka и пишет в них. Слой приёма записывает сырые события. Этап извлечения сигналов читает сырые события и записывает извлечённые. Этап обогащения Smart Signals читает извлечённые события и записывает обогащённые. Движок скоринга риска читает обогащённые события и записывает оценённые.
Такая архитектура даёт несколько преимуществ: этапы можно масштабировать независимо, сбои на одном этапе не затрагивают другие, и мы можем воспроизводить события через любой этап для отладки или повторной обработки. Consumer-группы Kafka обеспечивают параллельную обработку внутри каждого этапа, а семантика exactly-once гарантирует, что ни одно событие не будет обработано дважды или потеряно.
Бюджет задержки
Наша цель по сквозной задержке — 10 мс с момента, когда обогащённая полезная нагрузка сигналов поступает в конвейер обработки, до момента, когда возвращается оценка риска. Вот как распределяется бюджет: извлечение сигналов занимает 1–2 мс, обогащение Smart Signals — 3–4 мс, скоринг риска — 2–3 мс, а сериализация и ответ — 1–2 мс. Переход между этапами через Kafka добавляет менее 1 мс в нашем co-located-развёртывании.
Стабильное соблюдение этого бюджета при 50K событий/сек требует тщательной оптимизации на каждом этапе. Мы используем предварительно выделенные пулы памяти, zero-copy-сериализацию и пакетную запись в ClickHouse. Модель скоринга риска компилируется в нативный код через ONNX Runtime, устраняя накладные расходы интерпретатора Python.
Марк потратил две недели на профилирование конвейера, прежде чем нашёл узкое место в нашем слое распределённого поиска — единственный мьютекс сериализовал поиски по всем горутинам. После перехода на шардированную схему блокировок p99 упала с 48 мс до 9 мс. Иногда, стоит найти проблему, — и исправление оказывается до неловкости простым.