本文將介紹對PENDING任務進行適當處理的實踐方法。
背景資訊
新的DDL任務引擎啟用時,當DDL執行失敗或者被意外中斷後,對應的DDL任務會處於PENDING待處理的狀態。此時必須對該PENDING狀態進行合適的任務處理,才能解除PENDING狀態並恢複正常訪問,否則後續的DDL將會被禁止執行並報錯。
處理原則
- 您可以通過
SHOW [FULL] DDL語句查看DDL任務的資訊和失敗原因(即REMARK欄位記錄的異常資訊)。 - 您也可以參考如下常用的處理方式(僅供參考,請根據實際情況選擇最適合的方式):
- 分析失敗原因,修複或排除導致失敗的因素(例如是由於資料問題導致的任務失敗,則您可以通過去重等方式訂正資料。如果是由於其它約束導致的失敗,請確認是否能夠去掉約束等)。修複完成後,使用
RECOVER DDL恢複該PENDING任務。 - 如果導致失敗的因素無法解除,並且DDL因失敗而不能真正執行,您可以使用REMOVE DDL刪除任務(務必確認DDL沒有真正執行才可刪除,否則可能會造成狀態不一致),刪除後恢複可訪問狀態。
- 如果您想直接刪除DDL任務失敗的表(比如表中無資料,可以直接刪除重建),您可以使用
REMOVE DDL刪除任務,然後再執行DROP TABLE IF EXISTS刪除表(務必確認表中無資料,或者資料可以丟棄,並且DROP TABLE一定要指定IF EXISTS文法,確保強制移除)。
- 分析失敗原因,修複或排除導致失敗的因素(例如是由於資料問題導致的任務失敗,則您可以通過去重等方式訂正資料。如果是由於其它約束導致的失敗,請確認是否能夠去掉約束等)。修複完成後,使用
樣本
如下樣本展示了對處於PENDING狀態的DDL任務進行處理的過程。
- 建表時沒有指定主鍵,並且插入了帶有重複值的資料行(ID=1有兩行資料):
mysql> create table test_pending (id int not null, age int) dbpartition by hash(id); Query OK, 0 rows affected (0.33 sec) mysql> insert into test_pending values(1,10),(1,20),(2,20),(3,30); Query OK, 4 rows affected (0.10 sec) mysql> select * from test_pending order by id; +------+------+ | id | age | +------+------+ | 1 | 10 | | 1 | 20 | | 2 | 20 | | 3 | 30 | +------+------+ 4 rows in set (0.10 sec) - 之後想為上述ID加上主鍵約束,但由於表中已有資料違反了唯一性限制式,因此DDL執行失敗:
mysql> alter table test_pending add primary key (id); ERROR 4636 (HY000): [f5be83373466000][10.81.69.55:3306][ddltest]ERR-CODE: [TDDL-4636][ERR_DDL_JOB_ERROR] Not all physical operations have been done successfully: expected 9, but done 8. Caused by: 1062:DDLTEST_1562056402230OYMK_7WW7_0001:Duplicate entry '1' for key 'PRIMARY' on `test_pending`;. - 通過
SHOW FULL DDL語句查看任務狀態和失敗原因,發現其中一個物理表中的資料有重複值導致了物理DDL執行失敗:mysql> show full ddl\G *************************** 1. row *************************** JOB_ID: 1106733441212637184 PARENT_JOB_ID: 0 SERVER: 1:102:10.81.69.55 OBJECT_SCHEMA: ddltest OBJECT_NAME: test_pending NEW_OBJECT_NAME: JOB_TYPE: ALTER_TABLE PHASE: EXECUTE STATE: PENDING PROGRESS: 77% START_TIME: 2019-09-06 17:17:55.002 END_TIME: 2019-09-06 17:17:55.273 ELAPSED_TIME(MS): 271 DDL_STMT: alter table test_pending add primary key (id) REMARK: ERR-CODE: [TDDL-4636][ERR_DDL_JOB_ERROR] Not all physical operations have been done successfully: expected 9, but done 8. Caused by: 1062:DDLTEST_1562056402 230OYMK_7WW7_0001:Duplicate entry '1' for key 'PRIMARY' on `test_pending`;.REMARK欄位中的詳細資料解釋如下:Not all physical operations have been done successfully: expected 9, but done 8.:該邏輯表的DDL涉及到9個物理DDL的執行,完成了8個,有1個失敗了,這個失敗的物理DDL導致整個邏輯DDL失敗,任務被置於 PENDING狀態。Caused by: 1062:DDLTEST_1562056402 230OYMK_7WW7_0001:Duplicate entry '1' for key 'PRIMARY' on 'test_pending';:失敗的根源在於DDLTEST_1562056402 230OYMK_7WW7_0001物理庫的test_pending物理表中有ID欄位的重複資料1,導致無法添加主鍵約束。
- 此時邏輯表處於不一致的狀態:
mysql> check table test_pending; +----------------------------------------+-------+----------+-------------------------------------------------------------------------------------------------------------+ | TABLE | OP | MSG_TYPE | MSG_TEXT | +----------------------------------------+-------+----------+-------------------------------------------------------------------------------------------------------------+ | ddltest_1562056402230oymk.test_pending | check | Error | Table 'DDLTEST_1562056402230OYMK_7WW7_0001.test_pending' find incorrect columns 'id', please recreate table | +----------------------------------------+-------+----------+-------------------------------------------------------------------------------------------------------------+ 1 row in set (0.04 sec) - 執行其它DDL也會被禁止,返回錯誤資訊:
mysql> drop table test_pending; ERROR 4644 (HY000): [f5beae39d466000][10.81.69.55:3306][ddltest]ERR-CODE: [TDDL-4644][ERR_PENDING_DDL_JOB_EXISTS] Another DDL job '1106733441212637184' with operation 'ALTER_ TABLE' is pending on ddltest.test_pending in ddltest. Please use SHOW DDL to check it, and then recover or rollback it using RECOVER DDL or ROLLBACK DDL, or just remove it us ing REMOVE DDL if you confirm that the pending job can be discarded. - 接下來,根據前面所述的常見的處理方式,您可以選擇以下幾種方式繼續進行處理(分別展示它們的效果):
- 去重(重複資料刪除的資料)後,恢複DDL任務,繼續完成添加主鍵約束的操作。
- 重複資料刪除資料(根據業務需要,僅保留一條資料),刪除資料操作可以通過PolarDB-X 1.0執行,也可以根據報錯資訊,直接連接到PolarDB-X 1.0後端的RDS物理庫中操作:
mysql> delete from test_pending where id=1 and age=20; Query OK, 1 row affected (0.07 sec) mysql> select * from test_pending order by id; +------+------+ | id | age | +------+------+ | 1 | 10 | | 2 | 20 | | 3 | 30 | +------+------+ 3 rows in set (0.02 sec) - 確認表中已經沒有重複資料後,恢複之前PENDING的DDL任務的執行(恢複成功,完成的任務被自動清理,主鍵添加成功):
mysql> recover ddl 1106733441212637184; Query OK, 0 rows affected (1.28 sec) mysql> show full ddl\G Empty set (0.00 sec) mysql> show create table test_pending\G *************************** 1. row *************************** Table: test_pending Create Table: CREATE TABLE `test_pending` ( `id` int(11) NOT NULL, `age` int(11) DEFAULT NULL, PRIMARY KEY (`id`), KEY `auto_shard_key_id` (`id`) USING BTREE ) ENGINE=InnoDB DEFAULT CHARSET=utf8 dbpartition by hash(`id`) 1 row in set (0.02 sec) mysql> check table test_pending; +----------------------------------------+-------+----------+----------+ | TABLE | OP | MSG_TYPE | MSG_TEXT | +----------------------------------------+-------+----------+----------+ | ddltest_1562056402230oymk.test_pending | check | status | OK | +----------------------------------------+-------+----------+----------+ 1 row in set (0.10 sec)
- 直接刪除任務,然後刪除表(測試資料可以丟棄),後續再根據需要重新建立該表。
mysql> remove ddl 1106733441212637184; Query OK, 1 row affected (0.02 sec) mysql> drop table if exists test_pending; Query OK, 0 rows affected (0.44 sec) mysql> show tables like 'test_pending'; Empty set (0.01 sec)
- 去重(重複資料刪除的資料)後,恢複DDL任務,繼續完成添加主鍵約束的操作。