System Design
Leaf 号段模式:用批量分配降低分布式 ID 压力
分布式系统中的唯一 ID 不仅要求不重复,还要考虑性能、可用性、趋势递增和扩容。Leaf 号段模式的核心思想,是用一次数据库操作批量申请一段 ID,之后在服务内存中高速发放。
基本流程
假设数据库保存 max_id 和 step:
初始 max_id = 0,step = 1000
实例 A 获得 [0, 1000)
实例 B 获得 [1000, 2000)
每个实例在本地使用 AtomicLong 递增,不必为每个 ID 访问数据库,数据库压力从“每次请求一次”降低为“每个号段一次”。
为什么需要原子分配
危险的实现是先 UPDATE,再用另一次普通 SELECT 读取 max_id。多实例交错执行时,读取到的可能不是自己刚刚更新后的结果。
安全方案需要让“锁定记录、计算新区间、更新上界、返回区间”位于清晰的事务边界中,可以使用行锁或数据库支持的原子更新方式,并通过真实 MySQL 并发测试验证不同实例不会获得重叠号段。
双缓冲与预取
当前号段快耗尽时,后台提前加载下一个号段;耗尽后交换 current 与 buffer,避免请求线程同步等待数据库。
这里常涉及:
- AtomicLong:安全发放单个 ID;
- volatile:让线程及时看见号段状态;
- ReentrantLock:保护号段切换和预取;
- 线程池:执行后台加载任务。
号段大小的权衡
step 太小会频繁访问数据库;太大则在服务重启时浪费更多 ID,并可能让各实例负载不均。ID 不连续通常是可以接受的,因为系统真正要求的是唯一性,而不是每个数字都被使用。
号段模式提供的是“数据库短暂不可用时仍能发放剩余 ID”的缓冲能力,不代表彻底摆脱数据库。监控剩余量、预取失败次数和分配延迟,才能让这个方案真正可运维。