- sportsbook
- bet settlement
- wallet
- live betting
Архитектура букмекерской платформы: ставки, кошелёк и расчёты

Архитектура с отдельными состояниями ставки, средств и расчёта: потерянный ответ провайдера, надёжное списание резерва и восстановление финансовых исправлений.
Букмекерская архитектура заслуживает доверия, когда позволяет объяснить ставку после неудобного сбоя. Провайдер её принял, но ответ потерялся. Средства зарезервированы, но подтверждение кошелька запоздало. Выигрыш зачислен, а затем результат исправлен. Ни одну из этих ситуаций нельзя надёжно разрешить, глядя только на одно поле статуса.
Основная задача проектирования — сохранять согласованность трёх записей во времени: что принял оператор, что произошло с деньгами клиента и какой результат применён. В этом материале разрабатываем модель состояний и разбираем конкретную ставку для продуктовой, инженерной и операционной команд. Предполагаются ставки с фиксированными коэффициентами и кошелёк учётной записи; биржам ставок, тотализаторам и кредитным схемам нужны другие денежные правила.
Распределите полномочия до разделения сервисов
Сначала разделите логические обязанности. Компонент предложения отвечает за текущую доступность рынков и исходов. Компонент приёма — за решение по ставке и принятые условия. Кошелёк — за резервы и проведённые денежные операции. Управление коэффициентами и риском — за лимиты приёма и модель обязательств. Компонент расчёта — за применение подтверждённых результатов по соответствующим правилам. Поддержка может просматривать общую историю, но не должна становиться альтернативным источником изменений финансового состояния.
Для всех этих компонентов не обязательно нужны отдельные развёртывания или базы. Модульное приложение может изменять тесно связанные записи ставки и кошелька в одной локальной транзакции. Отдельные сервисы полезны, когда ответственность, независимое масштабирование или изоляция сбоев оправдывают дополнительные протоколы. Стрелка между двумя сервисами на схеме не делает их записи атомарными.
При внешнем поставщике управления коэффициентами или приёма явно назовите решение, за которое он действительно отвечает. Сообщение о коэффициентах не доказывает, что поставщик принял ставку. Через адаптер сохраняйте идентификатор его запроса, окончательный идентификатор ставки и подтверждение решения. Продуктовые границы определяются в объёме букмекерского продукта; инженерную работу на границах поставщиков рассматриваем в материале об услугах интеграции платформ.
Разделите состояния ставки, её средств и результата
Используйте отдельные группы состояний, выбрав названия для своей реализации:
- Размещение: запрос получен, ожидает решения, ставка принята или отклонена. Тайм-аут связи означает неопределённость решения, а не подтверждает отказ.
- Средства: не зарезервированы, зарезервированы, списаны в оплату ставки или освобождены из резерва. Резерв уменьшает доступную для расходования сумму. Его списание учитывает ставку как оплаченную и не должно списывать её сумму второй раз. Снятие ещё не списанного резерва отличается от возврата оплаченной ставки: для возврата нужна отдельная денежная операция.
- Расчёт: ожидает подтверждающих данных, готов к применению, применён или ожидает исправления. Запись расчёта ссылается на данные, правила и денежную операцию, на основании которых он выполнен.
Определите допустимые сочетания вместе с переходами. Задайте срок разрешения ожидающей работы, но не превращайте его в автоматический отказ или снятие резерва, если контракт авторитетной системы не подтверждает отсутствие принятой ставки. Принятая ставка с зарезервированными средствами может быть промежуточным состоянием, из которого можно восстановиться: решение внешнего провайдера уже известно, но списание резерва кошельком ещё не подтверждено. Принятая ставка со снятым резервом — исключение, требующее расследования, а не штатно завершённый сценарий. Помечайте расчёт применённым только после подтверждения его денежной операции; до этого показывайте предполагаемый результат и ожидающую операцию. Запись должна ссылаться на оплаченную сумму ставки и конкретное применение результата.
Сохраняйте исходные параметры выбора, принятый коэффициент, сумму, валюту и ссылку на правила. Текущий рынок может закрыться или исчезнуть без изменения этих условий. Используйте локальную версию ставки для защищённых проверкой обновлений и отдельные идентификаторы запросов, сообщений провайдера и денежных операций. Один общий идентификатор не позволяет выразить несколько обоснованных исправлений одной ставки.
Проведите одну ставку через допустимые переходы
Рассмотрим условную ставку B71: у клиента сначала 100 денежных единиц, он делает ординар на 20 с десятичным коэффициентом 3,00. Предполагаем отсутствие налогов, комиссий, бонусов и досрочного выкупа. Вот рабочая модель проверки, выраженная переходами, а не перечнем функций:
- Получение запроса: сохраните идентификатор запроса отправителя и неизменяемые параметры размещения. Ограничьте проверку повторов соответствующим клиентом и областью оператора. Изменение суммы с тем же идентификатором — конфликт; намеренной второй ставке нужен новый идентификатор.
- Резервирование: обеспечьте 20 через механизмы кошелька для одновременных операций и зарезервируйте необходимую часть лимита риска. В модели, где резерв не меняет учётный баланс, баланс по проведённым операциям остаётся 100, а доступные средства становятся 80. До отправки сохраните ожидающую исполнения команду поставщику.
- Приём: сохраните окончательное подтверждение приёма и точные принятые условия. Списание существующего резерва делает учётный баланс равным 80: резерва больше нет, доступные средства по-прежнему составляют 80. В одной базе это можно выполнить атомарно; между системами сохраняйте известное подтверждение приёма и повторяйте ту же операцию списания резерва, пока её статус не будет выяснен.
- Отказ как альтернативная ветвь: окончательный отказ до приёма освобождает резерв средств и ожидающих обязательств по риску. Учётный и доступный балансы возвращаются к 100. Потерянного ответа недостаточно для такого перехода.
- Расчёт: после приёма примените разрешённый выигрышный результат к оплаченной ставке. Общая выплата составляет 20 × 3,00 = 60, включая сумму ставки, поэтому учётный баланс становится 140. Применяйте эту денежную операцию однократно, даже при повторной доставке результата.
- Исправление: если подтверждённые уполномоченным источником данные меняют победу на проигрыш по применимым правилам, сторнируйте зачисление 60 связанной операцией. Учётный баланс становится 80. Не списывайте ещё 20: исходная ставка уже оплачена.
Отказ — альтернативная ветвь, а не шаг после приёма. Числа показывают модель резерва, а не универсальный API кошелька. Другой кошелёк может представлять резерв иначе; доступная сумма и итоговый денежный эффект всё равно должны совпадать. Каждому переходу нужны условие допуска, уполномоченный на изменение компонент, сохранённая запись и определённое действие при отсутствии подтверждения.
Устраните разрыв между коммитом базы и отправкой события
Проверить баланс и позже обновить его — недостаточная защита от одновременных операций. Документация MySQL по чтению с блокировкой объясняет, почему обычное чтение не защищает связанные записи. В локальной транзакции используйте подходящие обновления с проверкой условий или блокировки и ограничения уникальности, чтобы защищать реальные инварианты денег и ставок. Делайте транзакции короткими: сетевой вызов провайдера не должен неопределённо долго удерживать блокировку записи кошелька.
Следующий разрыв — отправка события: ставка записана коммитом, затем процесс прекращается, не уведомив зависимые сервисы. Записывайте изменение ставки и исходящее событие в одной локальной транзакции, а отправляйте сохранённые коммитом события отдельно. Паттерн транзакционного outbox описывает этот подход и необходимость устойчивых к повторам получателей.
Для B71 исходящий факт должен быть конкретным: ставка принята, указаны её версия и принятые условия. Перезапуск отправителя может привести к повторной доставке. Если кошелёк — отдельная система, такое событие или надёжно сохранённая команда могут запрашивать списание существующего резерва с устойчивым идентификатором денежной операции. Кошелёк должен учитывать обработку повторов вместе с денежным эффектом: пометка «обработано» до эффекта или после него в несвязанной транзакции оставляет ещё один разрыв при сбое.
Outbox не превращает удалённый кошелёк и базу ставок в одну транзакцию. Показывайте незавершённые передачи, повторяйте операции по согласованному контракту и сверяйте результаты. Приложение должно уметь ответить, принята и оплачена ли B71, даже если письмо с уведомлением или представление для отчётности ещё не обновилось.
Представьте расчёт как последовательность учтённых операций
Отделите получение спортивных результатов от расчёта ставок. Провайдер сообщает факты о событии, рынке или исходе; компонент расчёта сопоставляет их с принятыми ставками и применяет соответствующие правила. Ему нужны исходные параметры рынка, а не только отображаемое название. Результаты, пришедшие до запоздалого подтверждения приёма, нужно сохранять и сопоставлять, а не отбрасывать из-за того, что локальная ставка всё ещё ожидает решения.
Используйте достаточно точный идентификатор операции, чтобы отличать применение результата от его исправления. Он может включать локальную ставку и версию расчёта, отдельно сохраняя подтверждающие данные и идентификаторы поставщика. Точная схема зависит от контракта провайдера. Не считайте временную метку сообщения универсальным номером версии с глобальным порядком.
Исправления входят в модель. Например, документация Sportradar по отмене расчётов UOF описывает отмену ошибочного расчёта, в том числе на уровне исхода. Сохраняйте первоначальное применение, разрешённое сторнирование и возможную замену; текущий отображаемый статус должен быть представлением этой истории. Для B71 повторная доставка того же сторнирования не должна снимать ещё 60.
Если зачисленные средства клиент потратил или вывел до исправления, простой пример уже не описывает его текущий баланс. Разрешите расхождение по утверждённой политике оператора для счетов и порядку разбора случаев. Не удаляйте первоначальную запись и не скрывайте дефицит изменением отображаемого баланса.
Инженерная команда не может придумывать правила ставок. В Великобритании рекомендации Gambling Commission об опубликованных правилах охватывают приём и расчёт, включая отмены, ошибки и определение результата. Используйте их в пределах этой юрисдикции; согласуйте фактически применимые требования с оператором и квалифицированными консультантами. Более широкая модель учёта рассматривается в материале о проектировании кошелька и реестра транзакций.
Масштабируйте предложение, сохраняя надёжность денежных операций
Просмотр предложений и окончательный приём имеют разные требования к согласованности. Каталог коэффициентов может использовать кешированные представления для большого числа посетителей. Приём должен проверять соответствующее текущее состояние предложения, право клиента делать ставки, средства и контроль риска в точке окончательного решения. Быстрый, но устаревший каталог не даёт оснований принимать ставку на приостановленный исход.
Разделяйте обработку по реальным областям конкуренции: деньги клиента, переходы ставки или группа обязательств, ограничивающая конкретный риск. Ключ очереди может помогать сохранять порядок обработки в пределах области, но корректность всё равно зависит от защищённых проверками записей и реальных правил порядка сообщений провайдера. Избегайте одной глобальной очереди, в которой активный матч задерживает несвязанную работу. Не считайте все события разных источников сопоставимыми только потому, что у них есть временные метки.
Для восстановления фида и ставки нужны разные подтверждения. Документация по восстановлению UOF объясняет, что при восстановлении могут приходить текущие коэффициенты вместо всех промежуточных изменений и могут объединяться сообщения о расчёте. Пересборка каталога не восстанавливает принятый коэффициент B71 или её денежную историю.
Во время инцидента на событии остановите новый приём в затронутой области, если данные или контроль не позволяют принять допустимое решение. Сохраняйте обработку принятых ставок, проверку статуса и финансовую сверку, где это позволяют зависимости. Повторное открытие требует выполнения условий восстановления и локального применения данных для этой интеграции. Нагрузочные проверки должны включать активное событие, медленного провайдера и массовое поступление результатов, а не только анонимные просмотры страниц. Вопросы мощности разбираем в материале о масштабировании при пиковом трафике и событиях в реальном времени.
Проверьте архитектуру на сценариях сбоев и восстановления
Проверяйте архитектуру, намеренно прерывая B71 между сохранёнными шагами. Остановите процесс после резерва, внешнего приёма, коммита ставки и зачисления кошельком. Для каждого прерывания определите оставшиеся записи и компонент, которому разрешено продолжить. Если ответ — «поддержка меняет статус, пока всё не выглядит правильно», проектирование восстановления не закончено.
Контракт повтора должен определять, какой идентификатор сохраняется, что происходит при изменении параметров и как распознаются запоздалые запросы. Материал Amazon Builders' Library об идемпотентных API рассматривает идентификаторы от отправителя, конфликты параметров и запоздалые запросы. Для букмекерской платформы задавайте срок хранения по реальным потребностям провайдера и восстановления; истечение срока краткоживущего кеша не должно создавать рассчитанную ставку заново.
Создайте операционное представление, связывающее ставку, резерв, оплату суммы, данные результата, операции расчёта и последний подтверждённый статус провайдера. Выделяйте невозможные сочетания и работу, превысившую согласованный срок разрешения. Действие оператора должно вызывать разрешённую команду с записью полномочий и причины, а не вручную обновлять несколько столбцов статуса.
До выделения новых сервисов подтвердите четыре проверки ниже и измерьте выявленную ими незавершённую работу. Небольшая система с надёжным восстановлением — более прочная основа, чем множество сервисов, частичные сбои которых нельзя объяснить. Реализацию на стороне интеграций поставщиков рассматриваем в материале о границах интеграционного слоя и адаптерах.
Двум расширениям нужны собственные границы. В платформе с несколькими брендами явно укажите область оператора и кошелька в ставках, конфигурации и идентификаторах запросов: управляющее действие одного бренда не должно случайно влиять на другой. Если продукт включает виртуальную экономику, отдельно определите правила её валют и вознаграждений. Общий интерфейс учётной записи не даёт оснований считать виртуальные награды взаимозаменяемыми со средствами букмекерского кошелька.
- Прервите приём после решения провайдера, но до сохранения локального ответа. Восстановите тот же запрос и подтвердите согласованность известной ставки, её резерва и последующей оплаты без создания второй ставки.
- Выполните коммит ставки и остановите отправителя событий до публикации; затем снова остановите его после публикации, но до подтверждения. Подтвердите последующую доставку без повторной оплаты ставки или другого денежного эффекта.
- Примените результат, повторите его обработку, затем разрешите исправление и повторите обработку исправления. Сверьте точное итоговое движение и сохраните все связанные операции; покажите контролируемый порядок действий, если средства уже потрачены.
- Пересоберите представления для чтения и восстановите сообщения фида, пока ставки ожидают решения и приходят результаты. Подтвердите сохранность принятых условий и денежной истории, сохранение ещё не применённых обоснованных результатов и открытие только допустимых предложений.
Требует ли такая архитектура микросервисов?
Нет. Обязанности и переходы состояний важнее расположения развёртываний. Модульное приложение может изменять ставку и кошелёк в одной транзакции. Выделяйте сервис, когда этого требуют независимая ответственность, нагрузка или изоляция, и учитывайте затраты на надёжную передачу операций, обработку повторов и сверку.
Может ли у принятой ставки ещё оставаться резерв в кошельке?
Да, временно: внешний провайдер подтвердил приём, а результат списания зарезервированных средств ещё уточняется. Сохраняйте подтверждение приёма и повторяйте или проверяйте ту же денежную операцию. Это незавершённая работа, которую можно восстановить, а не разрешение освободить средства или принять необеспеченную ставку.
Нужна ли защита от повторных денежных операций при однократной обработке сообщений?
Не выводите гарантию однократного изменения средств только из функции системы сообщений. Получатель может отказать до или после записи в базу, провайдер — повторно доставить результат, а обоснованное исправление может выглядеть как повтор. Защищайте каждую денежную операцию и запись о её повторной обработке в соответствующей атомарной границе.
Что должна дать архитектурная проверка?
Карту полномочий, отдельные состояния размещения, средств и расчёта, допустимые переходы с условиями, примеры денежного эффекта и проверенные пути восстановления. Она также должна указать нерешённые вопросы и ответственных. Используйте эти материалы для реализации и эксплуатации: количество схем не подтверждает корректность.
Подготовьте один реальный цикл ставки, контракты кошелька и провайдера приёма, а также сбой, который команда пока не умеет уверенно разрешать. На этой основе согласуйте источники окончательных состояний, идентификаторы денежных операций и проверяемый путь восстановления до изменения состава сервисов.



