对同一张表并发swap两次
会出现查询报错表不存在
元数据内部缓存的表是一张已经被删除tabletId,只能重启fe解决
问题总结:
- 对同一张表并发执行两次
SWAP WITH操作。 - 导致查询时报错表不存在(
table not exist)。 - 根本原因是 FE 内部缓存的表元数据中包含了已经被删除的 Tablet ID。
- 目前只能通过重启 FE 节点来解决。
分析和建议:
-
并发操作限制: 尽管
SWAP WITH是一个原子操作,但对同一张表并发执行任何ALTER TABLE操作(包括SWAP WITH)通常是不推荐的,因为这可能导致元数据更新的竞争条件或不一致状态。
- 根据搜索结果,StarRocks 支持多个
ALTER TABLE并行,但 同一个表只能存在一个 进行中的ALTER TABLE任务。并发执行两次SWAP WITH可能会违反这个限制,或者在内部处理流程中引发竞态条件。
-
元数据缓存问题: 报错“表不存在”以及“FE 内部缓存的表是一张已经被删除 tabletId”指向了一个典型的 FE 元数据缓存不一致 问题。
SWAP WITH操作会交换两张表的 Table ID 和 Tablet ID 列表,这是一个涉及大量元数据修改的操作。如果在并发执行时,FE Leader 上的元数据(存储在 BDBJE 中)已经更新,但 FE Follower 或 FE Leader 自身的某些内部缓存(例如 Tablet 缓存、Schema 缓存等)未能正确同步或失效,就可能出现查询时拿到旧的或错误(已删除)的 Tablet ID,从而导致查询失败。 - 解决办法(重启 FE): 重启 FE 节点能够解决问题,是因为重启会强制 FE 重新从 BDBJE 中加载最新的、正确的元数据,从而清除所有不一致的内存缓存。
下一步操作建议:
-
避免并发: 在业务层面, 严格避免对同一张表并发执行
SWAP WITH或其他ALTER TABLE语句 。在执行第二次SWAP WITH之前,请确保第一次操作已经完成。 -
收集日志: 如果问题再次出现,请立即收集所有 FE 节点的日志(特别是 Leader 节点的
fe.log和fe.out),特别是包含SWAP WITH执行时间点和查询报错时间点的日志。 - 报告 Bug: 这是一个潜在的 StarRocks Bug。您应该向 StarRocks 社区或您的技术支持团队报告此问题,并提供详细的复现步骤、StarRocks 版本信息和日志文件,以便他们可以定位并发操作中元数据同步或缓存失效的缺陷。
为了进一步确认这是代码中的已知问题或需要修复的 Bug,我可以尝试搜索 StarRocks 源代码中关于 SWAP WITH 和元数据缓存相关的代码逻辑。
代码搜索建议: 搜索 SWAP WITH 相关的元数据操作,特别是关于 Tablet 切换和缓存更新的逻辑。
Code Search Results (1)
•
query: “SWAP WITH table metadata cache update”, regex: “swap with”• 0.26s
从代码搜索结果来看, ALTER TABLE ... SWAP WITH ... 的执行流程在 AlterJobExecutor.visitSwapTableClause 中:
-
加锁机制: 它使用了
Locker来对数据库(db.getId())和涉及的表(table.getId())加 写锁 (LockType.WRITE) :
locker.lockTablesWithIntensiveDbLock(db.getId(), Lists.newArrayList(table.getId()), LockType.WRITE);
这个写锁的目的是确保在执行 SWAP WITH 的整个过程中,没有其他 DDL 或 DML 操作来修改或访问这些表的元数据。
2. 并发问题推测:
-
如果 StarRocks 的 DDL 锁机制(
Locker)是正确的 ,并且能够阻止对同一张表并发执行两个SWAP WITH操作,那么第一个操作应该会阻塞第二个操作,直到第一个操作完成。如果两个操作确实是并发执行并都成功了,那么可能是锁粒度、锁的释放时机或锁的实现存在缺陷。 - 如果两个操作并发执行,并且都进入了临界区 ,它们可能相互覆盖了元数据更新,导致最终状态混乱。
-
即使锁机制正确,问题也可能出现在 Follower FE 的日志重放或缓存同步上。
SWAP WITH操作最终是通过GlobalStateMgr.getCurrentState().getEditLog().logSwapTable(log)记录到 BDBJE 日志并同步给所有 Follower FE 的。如果 Follower FE 在重放日志或更新内部缓存时存在竞态条件或错误,也可能导致不一致。
-
核心操作: 实际的交换逻辑在
GlobalStateMgr.getCurrentState().getAlterJobMgr().swapTableInternal(log)和GlobalStateMgr.getCurrentState().getEditLog().logSwapTable(log)中。
结论:
您遇到的问题(并发 SWAP WITH 导致元数据不一致,查询报错表不存在,需要重启 FE) 极有可能是一个 StarRocks 的 Bug ,涉及到并发 DDL 操作下的元数据锁机制或 FE 内部缓存的正确失效和同步。
建议:
-
临时规避: 确保在业务侧严格串行执行对同一张表的
SWAP WITH操作。 - 联系支持: 收集详细的日志和版本信息,向 StarRocks 官方社区或技术支持报告此问题,这是一个需要通过代码修复的元数据管理缺陷。
这个 Bug 影响了 FE 的稳定性,因为查询依赖于 FE 缓存的正确性。重启 FE 是目前最直接的解决方法,因为它强制重新加载元数据。
