Real-Time Backend
Design: Live Auction
USD 69 млн долларов за JPG-файл - и вся сумма определилась за последние 20 минут торгов. Christie's онлайн аукцион Beeple в 2021 году: система обрабатывала ставки в режиме реального времени при наблюдении миллионов людей. Один баг в bidding engine - и крупнейшая сделка в истории цифрового искусства могла стать скандалом.
- eBay: 1.4 млрд активных листингов, proxy bidding работает с 1995 года - механизм не изменился за 30 лет, только масштаб
- Christie's онлайн аукцион 2021: NFT-работа Beeple продана за USD 69 млн долларов, последние 20 минут - лавина ставок, soft close продлевал таймер многократно
- Sotheby's BidNow: платформа с anti-sniping (продление на 2 мин при ставке в последние 2 мин), обслуживает физические и онлайн торги одновременно
- Дефицитный товар за USD 0.01: когда Amazon или Sony проводят flash-sale, race conditions в naive системе могут привести к тому, что тысячи покупателей 'победят' одновременно
Архитектура аукционной платформы
eBay обслуживает 1.4 млрд активных листингов одновременно. За каждым аукционом стоит система, где задержка в 200 мс может стоить победы - и репутации платформы. Задача архитектора: обеспечить консистентность ставок при пиковых нагрузках без блокировок на горячих лотах.
Ключевые компоненты
Auction State в Redis - это hot spot системы. Все операции со ставками проходят через него. Для исключения race conditions используется Lua-скрипт: атомарная операция compare-and-set (CAS) гарантирует, что ставка принимается только если она выше текущей.
WebSocket - стандарт для live-аукционов. Sotheby's BidNow и Christie's используют постоянные соединения: клиент получает обновления цены мгновенно, без polling. При 50 000 одновременных зрителей одного лота - это критично.
| Компонент | Технология | Почему |
|---|---|---|
| Состояние аукциона | Redis cluster | Sub-ms latency, атомарные Lua-скрипты |
| Соединения клиентов | WebSocket + sticky sessions | Persistent duplex, fan-out уведомлений |
| Аудит ставок | PostgreSQL (append-only) | ACID, история для споров |
| Fan-out уведомлений | Redis Pub/Sub или Kafka | Масштабируемая рассылка всем зрителям |
Почему операция принятия ставки выполняется через Lua-скрипт на Redis, а не через стандартные GET + SET команды?
Bidding Engine: обработка ставок
Proxy bidding - механизм, которым eBay пользуется с 1995 года и который до сих пор формирует доверие к платформе. Участник указывает максимальную сумму, система автоматически перебивает конкурентов минимальным шагом - и раскрывает реальный максимум только если его превысили.
Proxy Bidding: алгоритм
Как работает proxy bidding на практике
Лот начинается с USD 100. Участник A устанавливает максимум USD 500. Система ставит USD 100 от его имени. Участник B ставит USD 200 - система автоматически ставит USD 210 (шаг USD 10) от A. Участник C ставит USD 550 - побеждает, система раскрыла, что максимум A был USD 500. Итог: A проиграл на USD 550, хотя его реальный максимум был USD 500.
Шаг ставки: динамическая сетка
| Диапазон цены | Минимальный шаг |
|---|---|
| USD 0 - USD 99 | USD 1 |
| USD 100 - USD 999 | USD 5 |
| USD 1 000 - USD 9 999 | USD 25 |
| USD 10 000 - USD 99 999 | USD 100 |
| USD 100 000+ | USD 500 |
Christie's онлайн аукцион NFT-работы Beeple установил рекорд: USD 69 млн долларов. Система обрабатывала ставки с интервалом в секунды при одновременном наблюдении миллионов зрителей. Bidding engine должен гарантировать порядок ставок даже при сетевых сбоях - через sequence numbers и idempotency keys.
Idempotency key - защита от двойных ставок при retry. Клиент генерирует UUID для каждой ставки. Если сеть оборвалась и запрос повторился - сервер распознает дубликат по ключу и возвращает результат первоначального запроса.
Участник установил proxy bid USD 300 при текущей цене USD 100. Конкурент ставит USD 250. Какую цену выставит система?
Anti-sniping: защита от последней секунды
Sniping - ставка в последние 2-5 секунд аукциона, когда конкуренты не успевают ответить. Это не баг, это фича системы с жестким дедлайном - и одновременно фундаментальная проблема честности. eBay долгое время не боролся с sniping, считая это частью игры. Сейчас большинство платформ реализуют soft close.
Soft Close: продление таймера
Sotheby's BidNow продлевает аукцион на 2 минуты при каждой ставке в последние 2 минуты, до максимума 10 продлений. Это превращает жесткий дедлайн в скользящее окно - аукцион завершается только когда никто не делает ставок 2 минуты подряд.
Детекция sniping: серверное время
Критичный момент: все временные метки должны генерироваться на сервере. Если клиент может манипулировать timestamp ставки - система сломана. Ставка считается принятой в момент получения на сервере, а не в момент отправки клиентом.
- Клиент отправляет ставку с client-timestamp (только для диагностики сети)
- Сервер фиксирует server-received-at при получении
- Сравнение с auction.endsAt происходит по server-received-at
- Ставки, полученные после endsAt, отклоняются с кодом AUCTION_ENDED
- Граничный случай: ставка in-flight в момент окончания - принимается, если received-at <= endsAt
Аукцион настроен с soft close: продление на 5 минут при ставке в последние 3 минуты, максимум 10 продлений. Участник делает ставку за 90 секунд до конца. Через 4 минуты другой участник делает ставку. Что происходит?
Fairness: честность и консистентность
Fairness в аукционах - не просто этика. Это survival requirement: платформа, где участники чувствуют нечестность, теряет доверие быстрее, чем успевает вырасти. Две главные угрозы: технические (race conditions, clock skew) и поведенческие (bid shielding, shill bidding).
Технические проблемы честности
- Clock Skew — Серверы в кластере имеют разное системное время (±100 мс типично). Ставки с разных узлов могут получить одинаковый timestamp. Решение: Lamport timestamps или централизованный sequence generator - монотонно возрастающий счетчик, не зависящий от реального времени.
- Network Latency Inequality — Участник с low-latency соединением имеет преимущество перед участником с high-latency. Платформы из разных регионов получают ставки с разной задержкой. Частичное решение: geo-distributed узлы приема ставок, но полное равенство недостижимо.
- Last-write-wins конфликты — При одновременных ставках на одну цену побеждает та, что пришла первой на master-node. Алтернатива: tie-breaking правило (меньший userId выигрывает при равной цене и одном timestamp). Это детерминировано и аудируемо.
Bid shielding и shill bidding
Аудит и разрешение споров
- Каждая ставка записывается в append-only лог с server-timestamp и Lamport clock
- История ставок неизменяема: ни администратор, ни система не могут модифицировать запись
- Участник может запросить полный лог ставок по любому лоту (transparency)
- Победная ставка подтверждается криптографической подписью финального состояния
- SLA на разрешение споров: Christie's и Sotheby's гарантируют ответ в течение 24 часов
Immutable audit log - это не только честность, это юридическая защита. В случае судебного спора о результате аукциона (особенно актуально для лотов на USD 1 млн+) платформа должна предоставить полную хронологию ставок с верифицируемыми timestamps.
Fairness в аукционе достигается простым правилом 'первая ставка побеждает' - кто успел, тот и выиграл
При распределенной системе 'первая ставка' неопределима без causal ordering. Clock skew в 100 мс делает физическое времяненадежным критерием. Нужны Lamport timestamps или centralized sequence numbers.
В системах с несколькими узлами нет единого понятия 'одновременно'. Ставки, кажущиеся одновременными для разных клиентов, могут прийти на разные узлы кластера с разным порядком. Без causal ordering честность недостижима технически.
Два участника делают ставку USD 1000 одновременно (разница 50 мс по сети). Какой механизм гарантирует детерминированный и аудируемый выбор победителя?
Итоги
- Атомарность - фундамент: compare-and-set через Redis Lua-скрипты исключает race conditions на hot spots аукциона
- Proxy bidding скрывает реальный максимум участника, автоматически перебивая конкурентов минимальным шагом
- Anti-sniping через soft close превращает жесткий дедлайн в скользящее окно - аукцион завершается только при паузе в активности
- Fairness требует causal ordering (Lamport timestamps) и immutable audit log - честность технически недостижима без них
Связанные темы
Live auction platform строится на фундаментальных паттернах distributed systems:
- Distributed Consensus — Lamport timestamps и causal ordering - прямое применение теории распределенных часов для разрешения конфликтов ставок
- WebSocket и реальное время — Fan-out уведомлений о новых ставках всем зрителям - классический use case persistent duplex соединений
- Redis и атомарные операции — Lua-скрипты в Redis как механизм compare-and-set для hot state аукциона - основа correctness системы
- Rate Limiting — Velocity check для детекции fraud и защиты от DDoS через фиктивные ставки - стандартный слой защиты
Вопросы для размышления
- Аукционная платформа вводит ограничение: не более 5 продлений anti-snipe. Какие trade-offs между честностью и UX это создает? Как изменится поведение участников?
- Proxy bidding скрывает максимум участника - но что если платформа технически имеет доступ к этим данным? Какие архитектурные механизмы не позволяют сотрудникам платформы злоупотреблять этим?
- При разработке Christie's онлайн аукциона: как тестировать anti-sniping логику и fairness механизмы без возможности воспроизвести реальный трафик USD 69 млн долларов лота?