Archery SQL审核与工单执行故障排查指南
简介:《archery使用手册》是一份面向DBA、研发与测试人员的Archery平台实操文档,围绕SQL审核查询与MySQL日常运维展开,帮助读者理解工单提交、审核执行、优化分析和实例排障的完整用法。文档系统梳理SQL语法与规范审核、高危语句拦截、立即或定时执行及回滚SQL生成,并介绍慢SQL统计、执行计划查看与优化建议获取;同时给出开发、测试环境的SQL审核流程示例。实例管理部分覆盖binlog清理、会话终止、事务与锁信息排查、账号授权和动态参数配置,插件部分说明PTArchiver数据归档、Binlog2SQL解析回滚及SchemaSync表结构同步的适用边界。压缩包共1个doc文件,约1.2MB,以单一文档集中呈现功能说明与实践案例,便于按章节查阅。已有1479人学习,适合需要快速上手Archery、规范SQL上线流程或补足MySQL运维排错思路的读者参考。
1. SQL 检测一片红:工单提交按钮点不动的那个下午
上周有个开发同学发来一张截图,Archery 的 SQL 检测结果里十几条 error 排成一列,工单提交按钮显示为灰色,他问我是不是平台出了问题。这类求助在 SQL 审核平台上几乎每天都有:SQL 在本地明明跑得好好的,一进 Archery 就被拦住,提示还只有一行“表必须包含主键”或者“高危语句已驳回”。Archery 使用手册里把 SQL 审核、SQL 优化、实例管理、Binlog2SQL、SchemaSync、PTArchiver 这些模块都过了一遍,可真正让人卡住的往往不是功能不会用,而是某条报错背后的审核规则、执行账号和连接状态对不上。下面按故障出现的顺序拆:从检测报错,到执行失败、回滚拿不到、实例连不上、锁杀不掉,每一段都给出能直接复现的命令和判断依据。
2. SQL 审核检测不通过:语法错、规范错、高危驳回怎么分清
SQL 检测报 error 是 Archery 里最高频的一类故障。很多人把三种完全不同的失败混在一起看:解析器连语法都过不去、解析通过但违反规范、以及被高危规则直接驳回。三者的处理路径不一样,混着看就会在错误的页面上改半天,改完重新检测,报错换了一条,人更懵。
2.1 三类报错的处理顺序
第一类是语法错,SQL 解析器直接失败,通常连审核规则都没走到。第二类是规范错,SQL 能解析,但撞上了建表必须有主键、表和列必须有注释、字段类型不能用 text 之类的自定义规则。第三类是高危拦截,比如没有 WHERE 的 UPDATE、DROP TABLE,平台按规则直接驳回,连人工审核的机会都不给。
-- 第一类:语法层面就过不去,FORM 拼错,解析器直接失败 SELECT id, name FORM t_user WHERE id = 1;-- 第二类:能解析,但撞规范规则——无主键、无表注释、列无注释 CREATE TABLE t_order ( id BIGINT, order_no VARCHAR(64), created_at DATETIME );-- 修正后:主键、注释、索引补齐,规范类报错一次清掉 CREATE TABLE t_order ( id BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键', order_no VARCHAR(64) NOT NULL COMMENT '订单号', created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', PRIMARY KEY (id), KEY idx_order_no (order_no) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订单表';第一段代码里FORM是拼写错误,任何解析器都过不了,改 SQL 即可,跟平台配置无关。第二段代码能解析,但缺PRIMARY KEY、缺表注释、三个列都没有COMMENT,这三点正好对应三条规范规则,检测结果会一次性全列出来。第三段是修正版,每条COMMENT、PRIMARY KEY、KEY都是为了消掉一条具体规则,不是随手加的。判断方法很简单:检测结果里如果提示里带“解析失败/语法错误”,先改 SQL;如果提示是“必须/不允许/建议”这类措辞,就是规则命中,改 SQL 或者调规则都能解决。
第三类高危拦截最容易被误判成平台故障。开发同学看到“高危语句自动驳回”,第一反应是找管理员关规则,这是最危险的做法。常见做法是保留高危规则,确实需要执行的语句走人工执行通道,并在工单里写清楚影响行数、回滚方式和执行窗口。规则可以调,但不能为了过一条 UPDATE 把整条拦截线拆掉。
2.2 规则不是越严越好:实例绑定的审核规则怎么调
同一个平台上,测试库和生产库经常绑不同的规则集。测试库要的是快,生产库要的是稳。有人在新实例上提交 SQL,发现本地测试时能过的语句到了新实例全报错,原因往往不是 SQL 变了,而是这个实例绑了另一套更严格的规则模板。
常见做法是先在规则管理里复制一份模板,按环境改三处:是否强制主键、是否强制注释、高危语句的拦截级别。改完之后把模板绑到对应实例上,再重新检测。这里有个容易忽略的点:规则调整通常只对之后提交的工单生效,已经提交的工单不会自动重新检测,得撤回重提。
| 规则项 | 测试环境常见配置 | 生产环境常见配置 | 说明 |
|---|---|---|---|
| 建表必须有主键 | 建议 | 强制 | 无主键表在归档和复制上都是隐患 |
| 表和列注释 | 建议 | 强制 | 后续排查字段含义全靠它 |
| 无 WHERE 的 UPDATE/DELETE | 警告 | 驳回 | 生产环境直接拦截,避免全表误更新 |
| 单次影响行数上限 | 不限制 | 按表规模设置 | 超过阈值转人工执行 |
| DDL 是否允许直接执行 | 允许 | 转人工或定时低峰执行 | 大表 DDL 单独评估 |
调规则之前,最好在测试实例上把同一条 SQL 跑一遍,确认是规则问题而不是 SQL 本身问题。规则调完要留记录:谁改的、为什么改、影响哪些实例。否则过两周再来一条同样的报错,没人记得当初为什么放开。
2.3 检测通过、点提交却失败:状态卡住的几种原因
SQL 检测全绿,点“SQL 提交”却弹出一行提示,这是第二高频的卡点。常见原因有三类:同一实例同一库下已经有未结束的工单,平台不允许并发提交;工单流程里某个审批节点没配人,提交时流程走不下去;实例没绑资源组,当前账号看不到这个实例的审批链。
先看工单列表,按实例和状态过滤,把“待审核”“待执行”“执行中”的工单翻一遍。如果确实有未结束的工单,等它结束或者撤回,别硬提。如果是流程配置问题,用管理员账号检查审批流节点,把人为空的节点补上。
# 在 Archery 部署机器上抓提交阶段的异常堆栈,定位是流程配置还是并发限制 tail -n 300 /opt/archery/logs/archery.log \ | grep -iE "submit|workflow|traceback|error"日志路径按实际部署方式调整,容器部署换成docker logs <容器名> --tail 300。重点看traceback后面的第一行异常类型:如果是空指针一类,多半是审批流节点没配全;如果是唯一约束冲突,就是并发工单限制。这一步的价值在于把“平台坏了”这种模糊判断,压缩到具体某一行配置上。
提示:检测通过不等于一定能提交,提交通过也不等于一定能执行。这三道关卡分别校验规则、流程和权限,排错时不要跳步。
3. 工单执行失败与回滚:立即执行报错、定时没跑、回滚 SQL 是空的
审核通过只是拿到入场券,真正让人半夜被叫起来的是执行阶段。立即执行报错、定时执行到点没动静、出事后想回滚却发现回滚 SQL 是空白的,这三类问题在 Archery 的工单详情页里都能看到蛛丝马迹,关键是知道先看哪一处。
3.1 立即执行失败:先把平台因素排除掉
执行失败的报错文本通常很短,比如“执行失败,请查看日志”。我的习惯是先用 Archery 里配置的执行账号,在 Archery 所在机器上手动跑一遍同一条 SQL。这一步能把问题切成两半:手动也失败,问题在账号、网络或 SQL 本身;手动成功,才回头查平台配置。
# 用工单里配置的执行账号,在 Archery 服务器上复现同一条变更 mysql -h 10.0.0.12 -P 3306 -u app_rw -p baidd \ -e "ALTER TABLE t_order ADD COLUMN remark VARCHAR(255) COMMENT '备注';"-h和-P填实例地址和端口,-u填 Archery 里该实例绑定的执行账号,baidd是目标库。密码走交互输入,不要直接写在命令里,避免留在 shell 历史。如果这一步报Access denied,说明执行账号权限或密码有问题;报Lock wait timeout,说明目标表上有未提交事务;报语法或字段不存在,说明测试库和生产库结构不一致。三种情况处理方式完全不同,先分清再动手。
| 报错关键词 | 常见根因 | 先做什么 |
|---|---|---|
| Access denied | 执行账号无权限或密码错误 | 用该账号手动连库执行 |
| Unknown column / syntax | 目标库结构与测试库不一致 | 对比两边表结构 |
| Lock wait timeout | 行锁冲突,有长事务未提交 | 查锁等待,别急着重试 |
| 执行超时 | 大表 DDL 或大事务 | 拆批次或改用在线变更工具 |
3.2 定时执行到点没跑:时区、调度、执行人三处看
选了定时执行,到了时间工单状态还停在“待执行”,这种问题排查起来有固定顺序。先看应用服务器和数据库的时区是否一致,Archery 展示的时间和你以为的时间可能差几个小时;再看调度任务是否正常,定时执行依赖后台调度进程,进程没起或者被重启打断,任务就悬着;最后看执行人账号是否被禁用或调岗,执行人为空的工单到点也跑不动。
# 对比 Archery 应用所在机器与数据库实例的当前时间及时区 date mysql -h 10.0.0.12 -P 3306 -u app_rw -p \ -e "SELECT NOW(), @@global.time_zone, @@session.time_zone;"两条命令输出的时间如果差整小时,基本可以确定是时区问题,把应用容器和数据库的时区统一即可。时间一致但任务没跑,就去看调度进程状态和工单的执行人字段。这里有个血泪经验:定时任务排在上线窗口前十分钟,结果审批人临时改了下拉框里的执行时间,页面显示的是本地时间,后台按另一个时区算,任务直接跨到了第二天。定时执行这种“看不见的执行”,时区一定要在第一次接入实例时就对齐。
3.3 回滚 SQL 拿不到:先分清 DML 和 DDL
工单执行完发现数据不对,第一反应是找回滚。Archery 的工单详情里有“查看回滚 SQL”和“下载回滚 SQL”,但点开是空白的情况很常见。原因分两类:一是这条工单执行的是 DDL,结构变更本身不可回滚,平台自然不会凭空生成回滚语句;二是 DML 工单的回滚依赖执行前记录或 binlog 解析,解析范围没覆盖到,回滚就是空的。
DDL 的回滚只能靠上线前自己备份结构,执行前把SHOW CREATE TABLE的结果存一份,出问题时按备份反向改回去。DML 的回滚可以走 Binlog2SQL 的 flashback,把指定 binlog 文件和位点之间的操作反转成回滚语句。
# 解析指定 binlog 区间,-B 表示生成回滚 SQL python binlog2sql.py \ -h 10.0.0.12 -P 3306 -u repl -p '******' \ -d baidd -t t2 \ --start-file='master-bin.000009' \ --start-pos=857 --stop-pos=1183 \ -B > rollback.sql-d和-t限定库和表,--start-file、--start-pos、--stop-pos定位要回滚的那段操作,-B是关键参数,加上它输出的是反向 SQL,不加则输出原始 SQL。输出重定向到文件后,先人工核对一遍再执行,别直接灌回生产库。需要明确的是,Binlog2SQL 只能回滚 DML,DDL 语句解析出来也回滚不了,这条边界在出事之前就要记住,别等回滚脚本跑完才发现结构变更没回来。
注意:回滚窗口和 binlog 保留时长直接相关。binlog 被清理掉之后,再想按位点回滚就没有原料了,清理前先确认保留天数覆盖得上故障发现周期。
4. 实例连不上、账号授权不生效、会话杀不掉
实例管理是 Archery 里最像“运维控制台”的部分,也是故障最集中的地方。连不上、授权不生效、会话杀不掉,这三类问题看起来都跟权限有关,实际排查路径完全不同,混着查会浪费很多时间。
4.1 实例连不上:按网络、账号、配置的顺序查
实例列表里点“测试连接”失败,先别改 Archery 的配置。正确的顺序是:从 Archery 所在机器验证到实例端口的连通性,再用配置的账号手动登录,最后才怀疑平台里的实例参数填错。这个顺序能把范围从大缩到小,避免在配置页面反复改端口号。
# 第一步:验证 Archery 服务器到实例 3306 端口的连通性 nc -vz 10.0.0.12 3306 # 第二步:用实例里配置的账号密码手动登录 mysql -h 10.0.0.12 -P 3306 -u app_rw -p -e "SELECT 1;"nc不通,问题在网络层:安全组、白名单、实例是否只监听了内网地址。nc通但mysql报Access denied,问题在账号层:账号不存在、host 不匹配、密码错。两步都通过,测试连接仍然失败,再回头检查 Archery 实例配置里的端口、库名、字符集这些字段,尤其是从别的实例复制过来改了地址却没改端口的场景。
还有一种反直觉的情况:Archery 所在机器能连,你本地连不上,于是怀疑平台把网络搞坏了。实际是实例白名单只加了 Archery 服务器,没加你的办公网段。判断方法就是上面两条命令各跑一遍,谁通谁不通一目了然。
4.2 账号建了但登录被拒:host、授权、密码策略
图形界面里把账号建出来了,应用连上去还是Access denied,十有八九是授权没做全或者 host 不匹配。Archery 的账号管理页面能看到账号列表,但排查时直接查系统表更快,能同时确认账号是否存在、host 是什么、有没有被锁定。
-- 确认账号是否存在、host 是否匹配、是否被锁定 SELECT user, host, account_locked FROM mysql.user WHERE user = 'app_rw'; -- 查看这个账号实际拿到了哪些权限 SHOW GRANTS FOR 'app_rw'@'%';第一条语句重点看host:%表示任意来源,10.0.0.%表示只允许这个网段,localhost只允许本机。应用服务器不在这个范围里,账号建得再对也连不上。第二条语句看权限是否覆盖了目标库,只有USAGE说明只建了用户没授权。
-- 读写权限和结构变更权限分开授,按需给 GRANT SELECT, INSERT, UPDATE, DELETE ON baidd.* TO 'app_rw'@'%'; GRANT ALTER, CREATE, INDEX ON baidd.* TO 'app_rw'@'%'; FLUSH PRIVILEGES;第一条给的是数据读写,第二条给的是改表结构,两条分开写是为了后续收权时能精确回收。FLUSH PRIVILEGES在通过GRANT语句授权时通常不是必须的,但图形化工具改完权限后执行一次,能避免缓存导致的“授权了但不生效”。密码里带特殊字符时,还要注意应用侧连接串的转义,很多“密码错误”其实是连接串把#或@截断了。
4.3 会话与锁:INFO 显示不全、trx 对不上、终止无效
排查阻塞时,进程状态页面是主战场,但直接看很容易踩三个坑。第一个坑是 SQL 显示不全,因为默认没勾“完整 INFO”,长 SQL 被截断,看起来像另一条语句。第二个坑是事务信息里的trx_mysql_thread_id在进程列表里搜不到,因为事务和会话的对应关系在刷新之间会变化。第三个坑是终止了会话,阻塞还在,因为杀的是等待方而不是阻塞方。
-- 找出等待方和阻塞方(MySQL 8.0) SELECT w.requesting_engine_transaction_id AS waiting_trx, w.blocking_engine_transaction_id AS blocking_trx, r.trx_mysql_thread_id AS waiting_thread, b.trx_mysql_thread_id AS blocking_thread, r.trx_query AS waiting_sql, b.trx_query AS blocking_sql FROM performance_schema.data_lock_waits w JOIN information_schema.innodb_trx r ON r.trx_id = w.requesting_engine_transaction_id JOIN information_schema.innodb_trx b ON b.trx_id = w.blocking_engine_transaction_id;这条语句直接给出waiting_thread和blocking_thread两个线程号,拿blocking_thread回进程状态里搜,终止它才有效。MySQL 5.7 没有performance_schema.data_lock_waits,换成information_schema.innodb_lock_waits,字段名也不同,排查前先确认版本。这一步的意义在于把“锁信息”页面里抽象的 trx id 翻译成可以直接操作的线程号,不然看到一堆十六进制事务号根本无从下手。
复现锁等待也有个固定套路:一个会话开事务更新某行但不提交,另一个会话更新同一行就会被阻塞。用上面的语句能清楚看到谁在等、谁在挡,再到进程状态里终止阻塞方。
4.4 binlog 清理:选中一个文件,删掉的是它之前的全部
磁盘告警时清理 binlog 是常规操作,但 Archery 的清理逻辑是按位点截断:你选中某个 binlog,它之前的文件会全部被删除。很多人以为只删选中的那一个,结果把还没备份的文件一起清掉了,主从复制直接断。
-- 先看现有 binlog 列表和大小,确认哪些已经备份、从库消费到哪 SHOW BINARY LOGS; -- 只保留 master-bin.000012 及之后的文件,之前的全部删除 PURGE BINARY LOGS TO 'master-bin.000012';第一条语句确认要保留的起点文件,第二条按文件名截断,正在写的文件不能作为删除目标。执行前必须确认两件事:从库已经消费到起点之前,备份系统已经拿到这些 binlog。图形界面清理和手动执行PURGE的效果一样,区别只是前者少打一条命令,风险并不会因为点了按钮就变小。
5. 避坑:四个高频翻车现场
前面几章讲的是单点故障,这一章记录四个反复出现的翻车场景。它们的共同点是:操作看起来都成功了,问题在几小时甚至几天后才暴露,排查时又很难联想到当初那一步。
5.1 PTArchiver 归档跑到一半停了
现象:归档任务执行一段时间后失败,源表数据没减少,目标表却已经写进去一部分,两边对不上。原因通常有三个:单批数据量太大导致事务超时、归档条件没走索引导致全表扫描、目标表主键冲突。解决方式是先把批量压小,再确认归档条件命中了索引。
# 小批量归档:每批 500 行,每 500 行提交一次事务,先不删源数据 pt-archiver \ --source h=10.0.0.12,P=3306,u=arch,p=******,D=baidd,t=t_order \ --dest h=10.0.0.13,P=3306,u=arch,p=******,D=baidd,t=t_order \ --where "created_at < DATE_SUB(NOW(), INTERVAL 3 MONTH)" \ --limit 500 --txn-size 500 --commit-each --no-delete--limit控制每批取多少行,--txn-size控制多久提交一次,--commit-each保证每批独立提交,中途失败不会留下半个大事务。--no-delete是验证阶段的后悔药,先只往目标表写、不删源表,核对行数无误后再去掉这个参数正式归档。--where里的时间字段必须有索引,否则每批都是一次全表扫描,归档任务会把线上拖慢。
5.2 SchemaSync 比对结果为空或生成的 SQL 对不上
现象:两个库明显结构不同,比对结果却是空的;或者生成了同步 SQL,但少了索引和注释。原因通常是连接串写错库、表名大小写敏感导致匹配不上、账号权限看不到部分表。SchemaSync 只比对表结构,不比对数据,这一点在结果异常时要先确认,别拿它当数据校验工具用。
# 源库与目标库结构比对,生成同步 SQL 和对应的回滚 SQL schemasync \ mysql://user:pass@10.0.0.12:3306/baidd \ mysql://user:pass@10.0.0.13:3306/baidd \ --output-dir ./schema_diff两个连接串分别对应源和目标,--output-dir下会生成 patch 和 revert 两个文件,前者是同步语句,后者是反向语句。比对结果为空时,先手动在两个库各执行一次SHOW TABLES,确认连的确实是目标库;再看表名大小写,Linux 上的实例默认区分大小写,从别处导出的脚本可能大小写不一致。
5.3 慢日志页面空白,以为平台没采集
现象:实例接入了,慢日志列表一直是空的,怀疑采集功能坏了。原因多半在数据库侧:slow_query_log没开、long_query_time设得太大、log_output是 FILE 而平台读不到文件、或者查询的时间范围里确实没有慢查询。
-- 确认慢日志开关、阈值和输出方式 SHOW VARIABLES LIKE 'slow_query_log'; SHOW VARIABLES LIKE 'long_query_time'; SHOW VARIABLES LIKE 'log_output';log_output是 TABLE 时慢日志写进mysql.slow_log表,平台通过 SQL 读取;是 FILE 时写到磁盘文件,平台需要有文件读取权限。开关没开就先开,阈值太大就调小,输出方式是 FILE 但平台读不到文件,就改成 TABLE 或者把文件路径挂进容器。这三个参数确认完,再看平台侧的时间范围筛选,很多“空白”其实是查询条件选错了日期。
5.4 以为有回滚就万事大吉
现象:工单执行前看到详情页有“回滚 SQL”入口,心里踏实了,出事时点开发现是空的。原因是这条工单执行的是 DDL,结构变更是不可回滚的,平台不会生成不存在的回滚语句。另一个版本是定时工单被重复触发,同一条变更执行了两次,第二次直接报字段已存在。
解决方式分两头:DDL 上线前手动把SHOW CREATE TABLE的结果存档,回滚靠这份结构备份;定时工单执行前确认状态,避免同一工单被重复提交。回滚入口存在不代表回滚一定可用,执行前花十秒点开看一眼,比出事后再找 binlog 位点便宜得多。
6. 快速定位:一张顺序表和两个习惯
被 Archery 的报错卡住时,最耗时间的不是解决,而是判断该从哪里看。我的做法是先按现象归到一张固定顺序表里,再往下钻,避免在平台页面和数据库之间来回跳。
| 现象 | 第一现场 | 下一步 |
|---|---|---|
| SQL 检测报 error | 检测结果提示措辞 | 带“解析失败”改 SQL,带“必须/不允许”改规则或 SQL |
| 检测通过提交失败 | 同实例未结束工单、审批流节点 | 清工单、补审批人 |
| 立即执行失败 | 手动用执行账号复现 | 报错落在账号、锁还是结构不一致 |
| 定时执行没跑 | 应用与数据库时区、调度进程 | 统一时区,检查执行人状态 |
| 回滚 SQL 为空 | 工单是 DDL 还是 DML | DDL 走结构备份,DML 走 Binlog2SQL |
| 实例测试连接失败 | nc端口连通性 | 不通查网络,通查账号 |
| 阻塞杀不掉 | 锁等待里的阻塞线程号 | 终止阻塞方而不是等待方 |
| 慢日志空白 | slow_query_log、log_output | 先改数据库参数再看平台 |
两个习惯值得固定下来。第一个是“先复现再改配置”:任何执行类报错,先用执行账号手动跑一遍,手动能复现就说明问题在数据库侧,改平台配置只会把水搅浑。第二个是“变更前留三样东西”:表结构备份、binlog 位点、回滚 SQL 是否可用的确认。这三样在平时看着多余,出事时能省掉一晚上的猜测。
从那以后我每次提交工单前,都会先点开回滚入口确认一眼,DDL 工单额外存一份SHOW CREATE TABLE的结果,定时工单执行前再扫一遍状态。这些动作加起来不到一分钟,但把“回滚不了”和“重复执行”这两类最难查的故障挡在了门外。希望帮到你。
本文还有配套的精品资源,点击获取