作者: Jasper


问题背景

集群版本 :v5.4.3

问题现象:集群 cpu 资源使用率飙高,集群整体 duration 上升,造成部分业务收到影响



问题处理



1. sql 定位

根据 dashboard top sql ,以及慢查询 定位到相关 sql ,为 120亿 表全表扫描



2. 临时解决

sql 相关查询条件在表中是有索引的,临时通过 sql binding 的方式 绑定走索引的执行计划,集群资源使用率恢复正常。



3. 查询条件有对应索引为什么要走全表?

注: 查看时间点 7 月 8日 11 时左右

  1. 查看表元信息,可以看到表是一直在更新的,最后更新时间是 2024-07-08 row count 120亿左右

【故障处理】 统计信息收集失败, enconding failed_lightning

  1. 查看索引统计信息,发现索引统计信息缺失,最后更新时间为 6月13日。 经询问此集群为迁移升级的目标集群,6月13日 为数据导入时间,也就是从数据进到集群之后统计信息就没有正常收集过。

【故障处理】 统计信息收集失败, enconding failed_https_02

到这里其实 执行计划 错误的原因已经找到 : 相关表统计信息缺失导致优化器无法正确预估 cost ,进而导致执行计划选择错误,走到了全表扫描,但是正常情况下集群是有自动统计信息收集的,为什么索引的统计信息一直没有收集成功呢?

那么尝试手动收集统计信息呢试试呢?手动收集没有成功,报错如下:

mysql> analyze table content_xxx_xxx index content_index;
ERROR 1105 (HY000): other error: encoding failed

根据如上报错基本可以判断 统计信息收集失败的原因是表中存在非法字符导致。

此时最直接的解决办法是重新将数据重新导出导入,并指定字符集,但是这张表数据量有 120 亿,这个操作动作太大。且业务没有反馈数据查询存在问题,说明有异常数据的部分占比较小,那下一步就是通过日志信息尝试定位具体异常数据范围。



4. 查看 tikv 、 tidb 日志 定位 analyze 异常信息:

07/08 11:07:37 tidb 日志显示 content 表统计信息收集失败

【故障处理】 统计信息收集失败, enconding failed_tidb_03

查看对应时间点 tikv 日志,定位到报错的表的 region 信息,报错 region id 为 799953

【故障处理】 统计信息收集失败, enconding failed_https_04



5. 通过 region id 799953 查询 region 详细信息

得到 startkey : 7480000000000000FF715F72800000003CFF6835E20000000000FA

   endkey: 7480000000000000FF715F72800000003CFFA61F7F0000000000FA

region 799953
{
  "id": 799953,
  "start_key": "7480000000000000FF715F72800000003CFF6835E20000000000FA",
  "end_key": "7480000000000000FF715F72800000003CFFA61F7F0000000000FA",
  "epoch": {
    "conf_ver": 155,
    "version": 104105
  },
  "peers": [
    {
      "id": 800344,
      "store_id": 11,
      "role_name": "Voter"
    },
    {
      "id": 800343,
      "store_id": 20,
      "role_name": "Voter"
    },
    {
      "id": 1465083,
      "store_id": 6,
      "role_name": "Voter"
    },
    {
      "id": 1960146,
      "store_id": 1148820,
      "role_name": "Voter"
    },
    {
      "id": 3532222,
      "store_id": 1147431,
      "role_name": "Voter"
    }
  ],
  "leader": {
    "id": 800344,
    "store_id": 11,
    "role_name": "Voter"
  },
  "written_bytes": 0,
  "read_bytes": 135,
  "written_keys": 0,
  "read_keys": 3,
  "approximate_size": 86,
  "approximate_keys": 107417
}
/ # ./tikv-ctl  --host 127.0.0.1:20160 raft region -r 799953
{
  "region_infos": {
    "799953": {
      "raft_apply_state": {
        "applied_index": 24971,
        "commit_index": 24971,
        "commit_term": 7,
        "truncated_state": {
          "index": 24969,
          "term": 7
        }
      },
      "raft_local_state": {
        "hard_state": {
          "commit": 24971,
          "term": 7,
          "vote": 800344
        },
        "last_index": 24971
      },
      "region_id": 799953,
      "region_local_state": {
        "region": {
          "end_key": "7480000000000000FF715F72800000003CFFA61F7F0000000000FA",
          "id": 799953,
          "peers": [
            {
              "id": 800344,
              "role": "Voter",
              "store_id": 11
            },
            {
              "id": 800343,
              "role": "Voter",
              "store_id": 20
            },
            {
              "id": 1465083,
              "role": "Voter",
              "store_id": 6
            },
            {
              "id": 1960146,
              "role": "Voter",
              "store_id": 1148820
            },
            {
              "id": 3532222,
              "role": "Voter",
              "store_id": 1147431
            }
          ],
          "region_epoch": {
            "conf_ver": 155,
            "version": 104105
          },
          "start_key": "7480000000000000FF715F72800000003CFF6835E20000000000FA"
        }
      }
    }
  }
}



6. 根据 startkey 、 endkey 定位表中存在问题的数据范围

解析出来的数据范围为 1013462498 ~ 1017519999

MySQL [(none)]> SELECT TIDB_DECODE_KEY('7480000000000000FF715F72800000003CFF6835E20000000000FA');
+---------------------------------------------------------------------------+
| TIDB_DECODE_KEY('7480000000000000FF715F72800000003CFF6835E20000000000FA') |
+---------------------------------------------------------------------------+
| {"_tidb_rowid":1013462498,"table_id":"113"}                               |
+---------------------------------------------------------------------------+


MySQL [(none)]> SELECT TIDB_DECODE_KEY('7480000000000000FF715F72800000003CFFA61F7F0000000000FA');
+---------------------------------------------------------------------------+
| TIDB_DECODE_KEY('7480000000000000FF715F72800000003CFFA61F7F0000000000FA') |
+---------------------------------------------------------------------------+
| {"_tidb_rowid":1017519999,"table_id":"113"}                               |
+---------------------------------------------------------------------------+



7. 根据上文解析出的 数据范围查询表中相关数据

  1. 可能存在异常的数据量为 109574 条
mysql> select count(*) from content_xxxx_xxxx t where id>=1013462498 and id<=1017519999;
+----------+
| count(*) |
+----------+
|   109574 |
+----------+
1 row in set (0.07 sec)
  1. 尝试通过 char_length() 函数定位异常数据,异常数据通过函数处理时会报错,以此来确定异常数据范围。
mysql> select count(*) from content_xxxx_xxxxxx t where id>=1013462498 and id<=1017519999 and char_length(content_id) > 0;
+----------+
| count(*) |
+----------+
|   109574 |
+----------+
1 row in set (0.33 sec)


mysql> select count(*) from content_xxxxxx_xxxxxx t where id>=1013462498 and id<=1017519999 and char_length(msg) > 0;
+----------+
| count(*) |
+----------+
|    66262 |
+----------+
1 row in set (0.52 sec)


mysql> select count(*) from content_xxxxxxx_xxxxxx t where id>=1013462498 and id<=1017519999 and char_length(error_msg) > 0;
ERROR 1105 (HY000): invalid input value: Utf8Error { valid_up_to: 183, error_len: Some(1) }

  经确认, 只有 char_length(error_msg) 作为筛选条件的时候会报错,说明异常数据存在于 error_msg 字段。

  1. 确认异常字段后,在通过对 id 1013462498 ~ 1017519999 的范围进行二分法查找,定位具体出错的行,进一步通过业务手段处理,或者针对性地对该段数据进行重新导入。



总结与建议:

  1. 此次故障版本为 v5.4.3 ,新版本对非法数据的校验和检查制度更为完善,升级到 v6.5+ 以上的新版本可以获得更好的使用体验。
  2. 数据迁移如何避免非法数据。
  1. 参数: tidb_skip_utf8_check 建议关闭此参数,避免跳过集群本身的 utf8-check
  2. 如使用 lightning 工具导入,注意 character-set 可手动指定为需要的字符集,避免自动识别。更多请参考链接:https://docs.pingcap.com/zh/tidb/stable/tidb-lightning-configuration
  3. 数据迁移之后检查恢复日志是否存在异常。
  4. 数据迁移到新集群后,第一时间收集统计信息,并检查统计信息收集状态。