3.3.21版本, 表锁实现问题, 3.3由库锁改为表锁, 但是两张表在同时swap table时会出现并发问题

对同一张表并发swap两次
会出现查询报错表不存在
元数据内部缓存的表是一张已经被删除tabletId,只能重启fe解决

问题总结:

  1. 对同一张表并发执行两次 SWAP WITH 操作。
  2. 导致查询时报错表不存在( table not exist )。
  3. 根本原因是 FE 内部缓存的表元数据中包含了已经被删除的 Tablet ID。
  4. 目前只能通过重启 FE 节点来解决。

分析和建议:

  1. 并发操作限制: 尽管 SWAP WITH 是一个原子操作,但对同一张表并发执行任何 ALTER TABLE 操作(包括 SWAP WITH )通常是不推荐的,因为这可能导致元数据更新的竞争条件或不一致状态。
  • 根据搜索结果,StarRocks 支持多个 ALTER TABLE 并行,但 同一个表只能存在一个 进行中的 ALTER TABLE 任务。并发执行两次 SWAP WITH 可能会违反这个限制,或者在内部处理流程中引发竞态条件。
  1. 元数据缓存问题: 报错“表不存在”以及“FE 内部缓存的表是一张已经被删除 tabletId”指向了一个典型的 FE 元数据缓存不一致 问题。 SWAP WITH 操作会交换两张表的 Table ID 和 Tablet ID 列表,这是一个涉及大量元数据修改的操作。如果在并发执行时,FE Leader 上的元数据(存储在 BDBJE 中)已经更新,但 FE Follower 或 FE Leader 自身的某些内部缓存(例如 Tablet 缓存、Schema 缓存等)未能正确同步或失效,就可能出现查询时拿到旧的或错误(已删除)的 Tablet ID,从而导致查询失败。
  2. 解决办法(重启 FE): 重启 FE 节点能够解决问题,是因为重启会强制 FE 重新从 BDBJE 中加载最新的、正确的元数据,从而清除所有不一致的内存缓存。

下一步操作建议:

  1. 避免并发: 在业务层面, 严格避免对同一张表并发执行 SWAP WITH 或其他 ALTER TABLE 语句 。在执行第二次 SWAP WITH 之前,请确保第一次操作已经完成。
  2. 收集日志: 如果问题再次出现,请立即收集所有 FE 节点的日志(特别是 Leader 节点的 fe.logfe.out ),特别是包含 SWAP WITH 执行时间点和查询报错时间点的日志。
  3. 报告 Bug: 这是一个潜在的 StarRocks Bug。您应该向 StarRocks 社区或您的技术支持团队报告此问题,并提供详细的复现步骤、StarRocks 版本信息和日志文件,以便他们可以定位并发操作中元数据同步或缓存失效的缺陷。

为了进一步确认这是代码中的已知问题或需要修复的 Bug,我可以尝试搜索 StarRocks 源代码中关于 SWAP WITH 和元数据缓存相关的代码逻辑。

代码搜索建议: 搜索 SWAP WITH 相关的元数据操作,特别是关于 Tablet 切换和缓存更新的逻辑。

Code Search Results (1)

AlterJobExecutor.java:350:arrow_upper_right:

query: “SWAP WITH table metadata cache update”, regex: “swap with”• 0.26s

从代码搜索结果来看, ALTER TABLE ... SWAP WITH ... 的执行流程在 AlterJobExecutor.visitSwapTableClause 中:

  1. 加锁机制: 它使用了 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 在重放日志或更新内部缓存时存在竞态条件或错误,也可能导致不一致。
  1. 核心操作: 实际的交换逻辑在 GlobalStateMgr.getCurrentState().getAlterJobMgr().swapTableInternal(log)GlobalStateMgr.getCurrentState().getEditLog().logSwapTable(log) 中。

结论:

您遇到的问题(并发 SWAP WITH 导致元数据不一致,查询报错表不存在,需要重启 FE) 极有可能是一个 StarRocks 的 Bug ,涉及到并发 DDL 操作下的元数据锁机制或 FE 内部缓存的正确失效和同步。

建议:

  1. 临时规避: 确保在业务侧严格串行执行对同一张表的 SWAP WITH 操作。
  2. 联系支持: 收集详细的日志和版本信息,向 StarRocks 官方社区或技术支持报告此问题,这是一个需要通过代码修复的元数据管理缺陷。

这个 Bug 影响了 FE 的稳定性,因为查询依赖于 FE 缓存的正确性。重启 FE 是目前最直接的解决方法,因为它强制重新加载元数据。