Firestore并发执行Transactions时出现长时间冻结问题如何解决
问题根源
- 脏读引发高频冲突:当前你将「查询时间最早的文档」的逻辑放在事务外部,多个并发请求会同时拿到同一批最早文档的引用,各自开启事务操作时必然触发资源争用。
- SDK内置重试导致冻结:Firestore事务遇到冲突时会由SDK自动静默重试,旧版本Firebase本地模拟器存在已知问题,每次事务重试会产生30秒的固定延迟,这段延迟发生在SDK底层,不会触发你业务代码的断点,符合你观察到的冻结现象。
- 多事务叠加放大开销:你采用逐笔扣减、递归开启事务的实现,单次大额扣减可能需要数十次独立事务,每次事务都有概率触发冲突重试,叠加后总耗时被大幅拉长,同时每次重试都会产生额外的读写请求,最终出现读写数远超预期的情况。
修复方案
最优方案:合并为单事务处理
将完整扣减逻辑放到同一个事务中,从根本上避免多事务争用问题:
- 在事务内部执行
orderBy("expirationTime", "asc")的集合查询,获取按时间排序的文档列表 - 遍历列表逐笔计算扣减金额,在同一个事务内累计执行更新/删除操作,直到扣满指定金额为止
- 整个事务仅提交一次,没有递归多事务的额外开销,并发场景下冲突概率极低
提示:Firestore单个事务最多支持500次写操作,如果单次扣减需要处理的文档数超过500,可按每批次不超过450笔拆分事务处理即可。
临时修复方案:不重构架构的优化项
如果暂时不想调整整体逻辑,可先做以下修改缓解问题:
- 将查询最早文档的逻辑移到
releaseItem的事务内部,禁止在事务外查询文档引用,避免脏读导致的不必要冲突 - 升级本地Firebase模拟器到最新版本,即可解决事务重试30秒延迟的问题
额外优化建议
当前的嵌套Promise递归逻辑可读性较差,建议改用async/await语法改写,后续排查问题会更方便。
内容的提问来源于stack exchange,提问作者Redneys
相关产品推荐
相关产品推荐

