当多个进程或多台服务器同时操作同一资源(账户、订单、库存、批处理任务等)时,就会产生竞争。 语言内置的互斥锁或信号量只在单个进程内有效 —— 如果进程分散在多个进程或多台 服务器上,就需要另一种能跨越进程边界的互斥手段。
Ticketing 正是为了解决这个问题而生的锁服务器与客户端集合,即跨进程、跨服务器边界的分布式互斥。 客户端通过 TCP 连接到锁服务器,获取(acquire)一个具名的 key,穿过临界区之后 再释放(release)。
Ticketing 使用的不是 JSON,而是由固定宽度二进制字段组成的帧协议。先按 1 字节的 op 分发,再按该 op 对应的固定字节长度读取,只有最后的 key 会一直读到换行符(\n)为止。这与其说是 "解析",不如说更接近直接读取偏移量,因此开销比每次请求都解析 JSON 的方式更小。
每次获取锁时,服务器都会同时下发一个单调递增的 u64 围栏令牌(fencing token)。只要让受保护的 资源验证这个令牌的单调性,就可以拒绝那些在 lease 过期后才姗姗来迟、携带较低令牌访问的客户端。 这样一来,即便锁服务器自身在某一时刻并非完全一致,也能保证安全 —— 这一点在故障切换期间 尤为重要。
单台服务器即可运行(单机模式),但若需要无停机运维,只需最少 2 台即可组成集群。 集群不依赖共识(法定人数),而是基于优先级选出一个主节点,其余节点作为实时接收复制数据的 备用节点。当主节点崩溃(含重启)或优雅退出时,备用节点会接替上位。详细的 运作方式请参阅工作原理页面。
在同一套二进制协议之上,我们提供 8 种语言的官方客户端:Rust、Java/Kotlin、JavaScript/TypeScript、 Python、C#、Go、Ruby、C/C++。每种语言都以其生态自然的方式暴露 API —— 例如 支持 async/await 的语言使用异步方式,Go/Ruby/C 则使用阻塞 + 后台线程方式。协议在所有语言中 都是字节级完全一致的。各语言的安装方法与示例请参阅库页面。