多异步任务执行场景下的序号追踪方案咨询
解决方案建议
针对异步多触发源下的全局唯一递增序号需求,以下是几种低延迟且能避免重复的方案:
1. 数据库原子递增操作(推荐)
利用数据库原生的原子性操作保证序号不重复,无需额外锁逻辑:
- MySQL:可以用高效的原子更新+读取方式:
UPDATE sequence_table SET seq = LAST_INSERT_ID(seq + 1); SELECT 132054;132054仅返回当前连接的更新结果,完全规避并发读取冲突。 - PostgreSQL:直接使用内置序列对象,调用
SELECT nextval('seq_name');即可,序列本身就是原子递增的,性能极佳。 - 优势:依赖数据库原生能力,无需额外组件,延迟低,100%保证序号唯一无重复。
- 注意:序号表仅保留一行记录,操作时仅针对该行,避免行锁范围过大。
2. 乐观锁+重试机制
如果无法直接使用原子递增,可通过版本号实现乐观锁:
- 给序号表添加
version字段,每次获取序号时:- 读取当前
seq和version值 - 执行更新语句:
UPDATE sequence_table SET seq = seq + 1, version = version + 1 WHERE id = 1 AND version = [读取到的version]; - 检查更新影响行数,若为0说明并发冲突,重试3-5次即可
- 读取当前
- 优势:无行锁阻塞,常规并发场景下性能较好,几乎无延迟。
- 缺点:高并发下冲突概率上升,重试次数过多会增加少量延迟。
3. Redis原子递增(高性能场景首选)
借助Redis的单线程特性实现原子递增,完全避免重复:
- 直接调用
INCR seq_key命令,Redis会返回递增后的序号值 - 开启Redis的RDB或AOF持久化,避免服务重启后丢失序号
- 优势:性能远超数据库,延迟极低,完美支持高并发场景。
- 注意:若使用Redis集群,需确保
seq_key落在同一hash slot上,保证操作原子性。
4. 本地批量预取序号(减少数据库交互)
如果业务允许序号存在间隙(仅要求不重复),可批量预取序号到本地缓存:
- 服务实例启动或本地序号耗尽时,从数据库一次性获取一段序号范围:
UPDATE sequence_table SET seq = seq + 100 WHERE id = 1; SELECT seq - 99, seq; -- 获取100个序号的起始和结束值 - 本地维护当前可用的序号池,每次请求直接从本地取,用完再去数据库拉取新段
- 优势:大幅减少数据库请求次数,延迟极低。
- 缺点:服务宕机时未使用的序号会丢失,产生间隙;若业务要求序号连续则不适用。
内容的提问来源于stack exchange,提问作者yunus emre kaya
相关产品推荐
相关产品推荐

