menuTicketing

Что такое Ticketing?


Зачем нужна распределённая блокировка

Когда один и тот же ресурс (счёт, заказ, склад, пакетное задание и т.п.) одновременно трогают несколько процессов или несколько серверов, возникает состязание. Встроенные в язык мьютексы или семафоры действуют только в пределах одного процесса — если процессов несколько или они распределены по разным серверам, нужен отдельный механизм взаимного исключения, работающий за пределами границ процесса.

Ticketing — это как раз сервер блокировок и набор клиентов для этой задачи: распределённого взаимного исключения за границами процессов и серверов. Клиент подключается к серверу блокировок по TCP, получает (acquire) именованный ключ (key), проходит критическую секцию и затем освобождает (release) его.

Ключевая философия

⚡ Лёгкий и быстрый

Ticketing использует не JSON, а фреймовый протокол на полях фиксированной ширины. После диспетчеризации по 1-байтовому op-коду читается фиксированное для этого op количество байт, и лишь последний ключ читается до перевода строки (\n). Парсинг здесь — по сути просто чтение по смещению, а не парсинг в привычном смысле, поэтому накладные расходы меньше, чем при разборе JSON на каждый запрос.

🔑 Безопасность через fencing-токены

При каждом получении блокировки сервер выдаёт вместе с ней монотонно возрастающий u64 fencing-токен. Если защищаемый ресурс сам проверяет монотонность этого токена, можно отклонить доступ клиента, который проснулся с опозданием после истечения lease и пытается действовать с более старым токеном. В результате безопасность сохраняется, даже если сам сервер блокировок не абсолютно консистентен в каждый момент времени — это особенно важно во время failover.

🔄 Бесперебойный кластер

Сервис работает и с одним сервером (одиночный режим), но для бесперебойной работы нужен кластер минимум из 2 узлов. Кластер выбирает активный узел не через консенсус (кворум), а на основе приоритета, а остальные узлы становятся резервными (standby), получающими репликацию в реальном времени. Если активный узел падает (в том числе при перезапуске) или завершается штатно (graceful shutdown), его роль подхватывает резервный узел. Подробности — на странице Принцип работы.

🌐 Независимость от языка

Поверх одного и того же бинарного протокола предоставляются официальные клиенты для 8 языков: Rust, Java/Kotlin, JavaScript/TypeScript, Python, C#, Go, Ruby, C/C++. Для каждого языка API устроен естественным для его экосистемы образом — например, языки семейства async/await получают асинхронный API, а Go/Ruby/C — блокирующий с фоновым потоком. Протокол при этом побайтово идентичен для всех языков. Способы установки и примеры для каждого языка — на странице Библиотеки.