Постановка задачи
A/B тестирование — один из важнейших инструментов для принятия решений в продуктовых компаниях. Необходимо спроектировать платформу, которая позволит проводить эксперименты на миллионах пользователей с минимальным влиянием на производительность основного продукта.
Функциональные требования
Управление экспериментами
- Создание экспериментов с вариантами (Control/Treatment)
- Определение целевой аудитории (targeting)
- Настройка длительности эксперимента
- Определение метрик для измерения
Распределение вариантов
- Случайное распределение пользователей по вариантам
- Консистентное назначение (один user = один вариант)
- Поддержка traffic splitting (1%, 5%, 50%...)
- Progressive rollout (постепенное увеличение трафика)
Сбор данных
- Логирование действий пользователей
- Привязка событий к варианту эксперимента
- Агрегация метрик (CTR, конверсия, retention)
Анализ результатов
- Расчёт статистической значимости (p-value)
- Доверительные интервалы
- Визуализация результатов в реальном времени
Нефункциональные требования
Низкая латентность
Определение варианта должно занимать <10ms, чтобы не влиять на UX
Консистентность
Пользователь должен видеть один и тот же вариант на протяжении всего эксперимента
Масштабируемость
Обработка миллиардов событий в день без деградации производительности
Высокоуровневая архитектура
Основные компоненты
Experiment Management Service
CRUD операции для экспериментов, targeting rules, конфигурация вариантов
Variant Assignment Service
Быстрое определение варианта для пользователя (критичный путь)
Event Ingestion Pipeline
Сбор и обработка событий с привязкой к экспериментам
Analysis Engine
Статистический анализ, расчёт p-value, confidence intervals
Архитектура строится вокруг двух путей:
Hot Path — назначение варианта
Cold Path — сбор и анализ данных
Визуализация через C4 Model
Ниже система A/B платформы разложена по уровням C4: сначала внешний контекст, затем контейнеры платформы, и в конце детализация критичного контейнера назначения вариантов. Подробнее про сам подход: глава C4 Model.
L1 — System Context
Кто взаимодействует с платформой и какие внешние системы участвуют в контуре.
Алгоритмы рандомизации
Качественный алгоритм рандомизации должен обеспечивать: отсутствие bias, консистентность и независимость между экспериментами.
Hash and Partition (HP)
variant = Hash(UserID + ExperimentID) % 100if variant < 50: return "Control"else: return "Treatment"- Не требует хранения состояния
- Детерминистичен — один input = один output
- Независимость между экспериментами благодаря ExperimentID
- Легко масштабируется
Pseudorandom with Caching (PwC)
Генерация случайного числа с последующим кэшированием результата для пользователя.
- Server-side: хранение в базе данных
- Client-side: хранение в cookie
- Требует дополнительного хранилища
- Потенциальные проблемы с консистентностью при очистке cookies
Методы назначения вариантов
Server-side Assignment
- ✓ Более безопасно (логика скрыта)
- ✓ Возможность тестировать backend-логику
- △ Требует быстрого сервиса или embedded library
- ✗ Дополнительный network hop
Client-side Assignment
- ✓ Быстрее для UI-изменений
- ✓ Легковесный SDK
- △ Конфигурация загружается при старте
- ✗ Логика видна пользователям
Оптимизация: Configuration Push
Конфигурации экспериментов пушатся на edge nodes или в Redis кэш для минимизации latency. SDK на клиенте получает конфигурацию через CDN и выполняет hash-based assignment локально.
Data Pipeline
Client Events
Kafka
Flink/Spark
ClickHouse
Dashboard
Ingestion
События отправляются в Kafka для high-throughput обработки. Каждое событие содержит user_id, experiment_id, variant, timestamp и payload.
Processing
Stream processing (Flink) для real-time метрик или batch (Spark) для сложных агрегаций и статистического анализа.
Storage & Reporting
OLAP база (ClickHouse, Pinot) для быстрых аналитических запросов. Dashboard с real-time обновлением результатов.
Параллельные эксперименты (Layers)
Как запускать несколько экспериментов одновременно без взаимного влияния? Решение — концепция слоёв (layers).
Проблема
Эксперимент A тестирует алгоритм поиска, эксперимент B — цвет кнопки. Если пользователь попадает в Treatment обоих, как понять, что повлияло на конверсию?
Решение: Domains/Layers
Эксперименты группируются по доменам (UI, Backend, Algorithm). Внутри домена — mutually exclusive, между доменами — независимы.
Пример Layer Architecture
Типичные ошибки
Sample Ratio Mismatch (SRM)
Распределение 50/50 даёт 52/48 в реальности. Причины: bot traffic, redirect issues, client-side bugs. Всегда проверяйте SRM перед анализом результатов.
Peeking Problem
Преждевременный анализ результатов до достижения statistical significance. Решение: sequential testing или фиксированный sample size.
Network Effects
В социальных продуктах пользователи влияют друг на друга. Cluster-based randomization вместо user-based может помочь.
Multiple Testing
Анализ множества метрик увеличивает вероятность false positives. Используйте Bonferroni correction или выделяйте primary metric.
Ключевые выводы
Hash-based assignment — предпочтительный метод для консистентного и stateless распределения вариантов
Configuration push — конфигурации на edge nodes или в Redis для минимальной latency
Layer architecture — изоляция экспериментов по доменам для параллельного запуска
Event streaming — Kafka + Flink/Spark для обработки миллиардов событий
Statistical rigor — SRM checks, proper sample size, sequential testing
OLAP для аналитики — ClickHouse/Pinot для real-time dashboards и сложных запросов
Материал подготовлен на основе публичного интервью «System Design Interview: A/B Testing Platform» и статьи Ron Kohavi «Trustworthy Online Controlled Experiments»
