TiDB Bug List=

我们新发现了一个TiDB 的“BR”组件相关 critical bug,详细见下:

产品 TiDB
组件 BR
版本 6.4.0
分类 Troubleshoot
标签 KnowIssue
来源

Issue

BR v6.4.0 的一个优化意外地引入了一个 BUG (https://github.com/pingcap/tidb/issues/40177),这个 BUG 可能导致某些分区表在恢复之后使用有问题的 Partition ID。

“有问题”体现在:那些 Partition ID 在日后还可能会被其他 Table 用作 Table ID。

Root Cause

BR v6.4.0 引入了在恢复的时候尝试保持旧集群的 Table ID 不变的优化,这个优化的基本流程如下:

  1. 在备份档案使用的所有 Table ID 中找到最大的 ID。
  2. 将 TiDB 的 Global ID(可以理解成 Table ID 所使用的的自增 ID)给 rebase 到这个最大的 ID。

在执行了 (2) 之后,理论上我们就可以安全地使用旧集群的 Table ID 了(因为这些 ID 并不会被再度使用)。

但是现有的实现在步骤 (1) 中,意外地忽略了分区表中的 Partition:Partition ID 也来自 Global ID,并且可能大于 Table ID。我们只把 Global ID rebase 到了 Max(TableID) 的话,无法保障这些 Partition ID 也能被安全地使用。

当任意一个 Partition ID 大于最大的 Table ID 的时候,问题就会出现了。

Diagnostic Steps

取决于这些“有问题”的 Partition 日后被如何使用,这个 bug 具体的的表现形式非常多,绝大多数表现形式都是毁灭性的,例如:

  • 分区表的数据被意外 GC。
  • 分区表的数据被意外覆盖。
  • 某些新表出现不该存在的记录。

另一种方法能更精确地判断这个 bug 有没有触发:

首先,在 BR 日志中查询 “registering the table IDs”,你会得到这样的日志:

[INFO] [client.go:244] ["registering the table IDs"] [ids="ID:[79,153)"]

这里,ids 表示了 BR 已经认为可以“安全使用”的 Global ID 区间,接下来,使用这个 SQL 查询。

SELECT T.`TIDB_TABLE_ID`, P.`TIDB_PARTITION_ID`, T.table_schema, T.`table_name`, partition_name FROM 
  INFORMATION_SCHEMA.`PARTITIONS` P INNER JOIN 
    INFORMATION_SCHEMA.`TABLES` T 
      ON (T.TABLE_NAME = P.TABLE_NAME and T.`TABLE_SCHEMA` = P.TABLE_SCHEMA) 
  WHERE T.`TIDB_TABLE_ID` BETWEEN @lower AND @higher;

将上面的 @lower@higher 替换成上面日志中 ids 表示的区间即可。

如果出现了某个 TIDB_PARTITION_ID 不在 ids 的区间内,那么这个 bug 大概率已经被触发,请参考下文 “Workaround”。

Resolution

我们在 v6.5.0 LTS 中发现并修复了这个问题。现在 BR 会将 Global ID 给 rebase 到 Max(TableID ∪ PartitionID)以避免该问题的发生。

Workaround

建议不要使用 v6.4.0 的 BR 进行分区表的恢复,可以使用 v6.5.0 LTS

如果一定要使用 v6.4.0 进行恢复,那么在该 bug 触发之后,可以通过 DROP 掉所有已经恢复的库表,并重新执行恢复来 workaround。