TiDB Lightning 错误处理功能

    • 要导入的数据有少许错误
    • 手动定位错误比较困难
    • 如果遇到错误就重启 TiDB Lightning,代价太大

    本文介绍了类型错误处理功能 () 和重复问题处理功能 (tikv-importer.duplicate-resolution) 的使用方法,以及保存这些错误的数据库 (lightning.task-info-schema-name),并提供了一个示例。

    你可以通过修改配置项 lightning.max-error 来增加数据类型相关的容错数量。如果设置为 N,那么 TiDB Lightning 允许数据源中出现 N 个错误,而且会跳过这些错误,一旦超过这个错误数就会退出。默认值为 0,表示不允许出现错误。

    这些错误会被记录到数据库中。在导入完成后,你可以查看数据库中的数据,手动进行处理。请参见。

    该配置对下列错误有效:

    • 无效值。例如:在 INT 列设置了 'Text'
    • 数字溢出。例如:在 TINYINT 列设置了 500
    • 字符串溢出。例如: 在 VARCHAR(5) 列中设置了'非常长的文字'
    • 零日期时间,如 '0000-00-00''2021-12-00'
    • 在 NOT NULL 列中设置了 NULL
    • 生成的列表达式求值失败
    • 列计数不匹配。行中数值的数量和列的数量不一致
    • on-duplicate = "error" 时,TiDB 后端的唯一键/主键冲突
    • 其他 SQL 错误

    下列错误是致命错误,不能通过配置 max-error 跳过:

    • 原始 CSV、SQL 或者 Parquet 文件中的语法错误,例如未闭合的引号
    • I/O、网络、或系统权限错误

    在 Local 后端模式下,唯一键/主键的冲突是单独处理的。相关内容将在接下来的章节进行介绍。

    Local-backend 模式下,TiDB Lightning 导入数据时先将数据转换成 KV 对数组(KV pairs),然后批量添加到 TiKV 中。与 TiDB-backend 模式不同,TiDB Lightning 在 Local-backend 模式下直到任务结束才会检测重复行。因此,Local-backend 模式下的重复错误不是通过 max-error 进行控制,而是通过 duplicate-resolution 配置项进行控制的。你可以通过配置该参数的行为,来决定如何处理有冲突的数据。

    1. [tikv-importer]
    2. duplicate-resolution = 'none'

    duplicate-resolution 有以下三个选项:

    • ‘none’:不对重复数据进行检测。如果唯一键或主键冲突确实存在,那么导入的表格里会出现不一致的数据和索引,checksum 检查的时候会失败。
    • ‘record’:检测重复数据,但不会对重复数据进行修复。如果唯一键或主键冲突确实存在,那么导入的表格里会出现不一致的数据和索引,checksum 检查的时候会失败。
    • ‘remove’:检测重复数据,并且删除全部重复行。导入的表格会保持一致,但是重复的行会被忽略,只能通过手动方式添加回来。

    TiDB Lightning 只能检测数据源的重复项,不能解决运行 TiDB Lightning 之前的存量数据的冲突问题。

    • 输出在终端的报错统计如下表所示:

      | # | ERROR TYPE | ERROR COUNT | ERROR DATA TABLE | | - | —- | —- | ——— | | 1 | Data Type | 1000 | lightning_task_info.type_error_v1 |

    • 输出在 TiDB Lightning 的 log 文件的结尾如下:

      1. [2022/03/13 05:33:57.736 +08:00] [WARN] [errormanager.go:459] ["Detect 1000 data type errors in total, please refer to table `lightning_task_info`.`type_error_v1` for more details"]

    所有错误都会写入下游 TiDB 集群 lightning_task_info 数据库中的表中。在导入完成后,如果收集到报错的数据,你可以根据数据库中记录的内容,手动进行处理。

    你可以使用 lightning.task-info-schema-name 配置更改数据库名称。

    1. [lightning]
    2. task-info-schema-name = 'lightning_task_info'

    在此数据库中,TiDB Lightning 创建了 3 个表:

    type_error_v1 记录由 max-error 配置项管理的所有类型错误 (Type error)。每个错误一行。

    conflict_error_v1 记录所有。每对冲突有两行。

    在该示例中,我们准备了一个包含一些已知错误的数据源。以下是处理这些错误的具体步骤:

    1. 准备数据库和表结构:

      1. mkdir example && cd example
      2. echo 'CREATE SCHEMA example;' > example-schema-create.sql
    2. 准备数据:

    3. 配置 TiDB Lightning,启用严格 SQL 模式,使用 Local 后端模式进行导入,通过删除解决重复项,并最多跳过 10 个错误:

      1. cat <<EOF > config.toml
      2. [lightning]
      3. [tikv-importer]
      4. backend = 'local'
      5. sorted-kv-dir = '/tmp/lightning-tmp/'
      6. duplicate-resolution = 'remove'
      7. [mydumper]
      8. data-source-dir = '.'
      9. [tidb]
      10. host = '127.0.0.1'
      11. port = 4000
      12. user = 'root'
      13. password = ''
      14. sql-mode = 'STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE'
      15. EOF
    4. 运行 TiDB Lightning。因为已跳过所有错误,该命令执行完会成功退出:

      1. tiup tidb-lightning -c config.toml
    5. 验证导入的表仅包含两个正常行:

      1. $ mysql -u root -h 127.0.0.1 -P 4000 -e 'select * from example.t'
      2. +---+-----+
      3. | a | b |
      4. +---+-----+
      5. | 1 | one |
      6. | 2 | two |
      7. +---+-----+
    6. 检查 conflict_error_v1 表是否捕获了具有唯一键/主键冲突的四行:

      1. $ mysql -u root -h 127.0.0.1 -P 4000 -e 'select * from lightning_task_info.conflict_error_v1;' --binary-as-hex -E
      2. *************************** 1. row ***************************
      3. task_id: 1635888701843303564
      4. create_time: 2021-11-02 21:31:42.669601
      5. table_name: `example`.`t`
      6. index_name: PRIMARY
      7. row_data: (40, "forty")
      8. raw_key: 0x7480000000000000C15F728000000000000028
      9. raw_value: 0x800001000000020500666F727479
      10. raw_row: 0x800001000000020500666F727479
      11. *************************** 2. row ***************************
      12. task_id: 1635888701843303564
      13. create_time: 2021-11-02 21:31:42.674798
      14. table_name: `example`.`t`
      15. index_name: PRIMARY
      16. key_data: 40
      17. row_data: (40, "fourty")
      18. raw_key: 0x7480000000000000C15F728000000000000028
      19. raw_value: 0x800001000000020600666F75727479
      20. raw_handle: 0x7480000000000000C15F728000000000000028
      21. raw_row: 0x800001000000020600666F75727479
      22. *************************** 3. row ***************************
      23. task_id: 1635888701843303564
      24. create_time: 2021-11-02 21:31:42.680332
      25. table_name: `example`.`t`
      26. index_name: b
      27. key_data: 54
      28. row_data: (54, "fifty-four")
      29. raw_key: 0x7480000000000000C15F6980000000000000010166696674792D666FFF7572000000000000F9
      30. raw_value: 0x0000000000000036
      31. raw_handle: 0x7480000000000000C15F728000000000000036
      32. raw_row: 0x800001000000020A0066696674792D666F7572
      33. *************************** 4. row ***************************
      34. task_id: 1635888701843303564
      35. create_time: 2021-11-02 21:31:42.681073
      36. table_name: `example`.`t`
      37. index_name: b
      38. key_data: 42
      39. row_data: (42, "fifty-four")
      40. raw_key: 0x7480000000000000C15F6980000000000000010166696674792D666FFF7572000000000000F9
      41. raw_value: 0x000000000000002A