基于Archery的SQL审核查询平台:规则引擎、工单流转与运维实践
简介:《archery使用手册》面向数据库开发人员、测试工程师与DBA,聚焦SQL审核查询平台Archery的落地使用,帮助读者理解平台能力并应用于日常数据库运维场景。资源包共1个文件,为doc格式文档,压缩包约1.2MB,内容围绕功能讲解与实践案例展开。手册系统梳理了SQL审核的语法解析与自定义规则校验、高危语句驳回、定时或立即执行及钉钉通知,SQL优化中的执行计划分析与慢SQL统计,实例管理里的binlog清理、会话与事务查看、锁信息排查、账号授权和动态参数配置,以及PTArchiver归档、Binlog2SQL解析回滚、SchemaSync结构同步等插件用法。实践部分结合开发与测试环境的审核流程、回滚SQL获取、优化建议示例和锁等待排查,给出可对照的操作思路。目前已有1478人学习,适合需要快速上手Archery、完善SQL管控流程的读者参考。
1. 从一条被驳回的建表语句说起:SQL 审核平台到底要解决什么
一条CREATE TABLE语句在评审会上被驳回三次,理由分别是没主键、表没注释、字段类型选得离谱——这种事在中小团队里几乎每周都在发生。Archery 这套 SQL 审核查询平台要解决的正是这个:把「人盯人」的 SQL 评审变成规则驱动的自动检测,顺带把 MySQL 日常运维里那些零散操作(清 binlog、杀会话、看锁、建账号、归档数据)收进一个 Web 界面。它适合两类人:需要交一份数据库运维平台课程设计或毕设的学生,以及要给团队搭一套 SQL 上线流程的从业者。下面按「需求 → 设计 → 实现 → 验收」把整套方案拆开,能照着改、照着交。
2. 需求拆解与总体设计:四个能力域与两条审核链路
先把 Archery 的能力盘清楚,再谈怎么落到自己的方案里。从功能面看,它其实是四个能力域拼起来的:SQL 审核(语法解析 + 自定义规则 + 回滚语句生成)、SQL 优化(执行计划 + 慢日志统计)、实例管理(binlog、会话、事务、锁、账号、参数)、工具插件(pt-archiver 归档、binlog2sql 解析、schema 同步)。这四个域共享同一套实例元数据和权限模型,这是设计上最值得抄的一点——不要为每个功能单独建一套连接配置。
2.1 能力域划分与职责边界
| 能力域 | 核心职责 | 依赖组件 | 典型使用者 |
|---|---|---|---|
| SQL 审核 | 语法解析、规则校验、生成回滚 SQL、工单流转 | 解析引擎 + 规则库 | 研发、项目经理 |
| SQL 优化 | 执行计划展示、优化建议、慢日志统计 | 实例连接 + 慢日志表 | 研发、DBA |
| 实例管理 | binlog 清理、会话/事务/锁排查、账号与参数 | 实例连接池 | DBA、管理员 |
| 工具插件 | 数据归档、binlog 解析、schema 比对 | 外部命令行工具 | DBA |
职责边界要写进设计文档:审核域只负责「判断能不能执行」和「生成怎么撤回」,不负责真正执行;执行动作由工单状态机驱动,落到具体实例上。这样拆分的好处是,审核规则可以独立迭代,不会牵动执行链路。
2.2 两条审核链路的流程设计
原料里给了两条真实链路,这是方案里最该保留的部分。开发环境是「研发工程师 → 项目经理」两级审核,测试环境是「测试从 git 取研发提交的 SQL → 测试环境发起审核 → 测试自己审核并执行」。两条链路的差别不在界面,而在审批节点数量和执行权限归属。
开发环境:研发提交 → SQL检测(error则打回) → 提交工单 → 项目经理审批 → 立即/定时执行 → 可下载回滚SQL 测试环境:测试取git上的SQL → 测试发起 → SQL检测 → 提交工单 → 测试自审 → 立即/定时执行 → 可下载回滚SQL设计说明:工单状态建议至少五态——待检测、待审批、已通过待执行、执行中、已执行/已回滚。状态迁移必须单向,回滚是新增一条反向工单而不是把原工单改回去,这样审计日志才干净。定时执行要单独存一个计划执行时间字段,别塞进备注里,否则后面做「待执行队列」时全是坑。
2.3 技术选型与部署形态
Archery 本身是 Web 形态,前端页面 + 后端服务 + 一个存工单和配置的库,再对接若干被管理的 MySQL 实例。选型上通常的做法是:工单库和被管实例库物理分开,工单库存审核记录、规则配置、用户权限;被管实例只读元信息(库表结构、慢日志、进程列表),写操作一律走工单。部署时把「审核服务」和「执行服务」拆成两个进程或两个容器,执行侧单独控权限,这是血泪经验——审核侧被误操作的概率远低于执行侧,混在一起出事就是大事。
3. SQL 审核模块实现:规则引擎、工单流转与回滚生成
这一章是整套方案的重心。审核模块做不好,后面所有运维功能都是摆设。实现上分三层:解析层把 SQL 文本变成语法树,规则层对语法树逐条判定,工单层负责状态流转和结果落库。
3.1 规则引擎:从语法解析到自定义规则
审核的核心不是「SQL 能不能跑」,而是「跑之前是否合规」。原料里明确了几条硬规则:建表必须有主键、表和列必须有注释、高危语句自动驳回。把这些规则写成可配置的判定函数,比硬编码在流程里强得多。
# 规则定义示例:每条规则是一个函数,输入解析后的表结构,返回 (是否通过, 提示) def rule_require_primary_key(table_meta): if not table_meta.get("primary_key"): return False, "建表语句缺少主键,请补充 PRIMARY KEY" return True, "" def rule_require_table_comment(table_meta): if not table_meta.get("comment"): return False, "表缺少注释,请补充 COMMENT" return True, "" def rule_require_column_comment(table_meta): missing = [c["name"] for c in table_meta["columns"] if not c.get("comment")] if missing: return False, f"以下列缺少注释:{','.join(missing)}" return True, "" # 高危语句直接驳回,不进入人工审批 HIGH_RISK_PATTERNS = ["DROP TABLE", "TRUNCATE", "DELETE FROM"] def rule_block_high_risk(sql_text): upper = sql_text.upper() for p in HIGH_RISK_PATTERNS: if p in upper and "WHERE" not in upper: return False, f"检测到高危语句 {p},已自动驳回" return True, ""参数说明:table_meta是解析层输出的结构化结果,至少包含表名、主键列表、表注释、列名与列注释;HIGH_RISK_PATTERNS建议做成配置表而不是常量,不同团队对高危的定义不一样。判定顺序上先跑高危规则再跑规范规则,高危命中直接短路,省得给用户一堆无关提示。规则结果要落库,字段至少存规则 ID、是否通过、提示文案,后面做「审核通过率统计」时直接聚合。
3.2 工单状态机与审批节点
工单是审核模块的骨架。提交时先做 SQL 检测,检测有 error 就不允许提交——原料里写得很清楚,「如果是 error,则无法通过 sql 审核,需要根据提示完善 sql 后再次提交」。检测通过才生成工单,进入审批队列。
-- 工单主表核心字段设计 CREATE TABLE sql_workflow ( id BIGINT PRIMARY KEY AUTO_INCREMENT, instance_id BIGINT NOT NULL COMMENT '目标实例', db_name VARCHAR(64) NOT NULL COMMENT '目标库', sql_content TEXT NOT NULL COMMENT '待执行SQL', rollback_sql TEXT COMMENT '回滚SQL,执行前生成', status TINYINT NOT NULL DEFAULT 0 COMMENT '0待审批 1已通过 2执行中 3已执行 4已回滚 5已驳回', exec_mode TINYINT COMMENT '1立即执行 2定时执行', plan_time DATETIME COMMENT '定时执行时间', creator VARCHAR(64) NOT NULL, approver VARCHAR(64) COMMENT '当前审批人', create_time DATETIME DEFAULT CURRENT_TIMESTAMP ) COMMENT 'SQL工单主表';设计说明:rollback_sql在执行前生成并落库,这是后悔药的来源——原料里「下载回滚 sql」「查看回滚 sql」两个动作都依赖它。approver存当前节点审批人而不是审批历史,历史另开一张sql_workflow_audit表,每次审批插一条,答辩时展示审计链会加分。status用数字枚举,前端映射成中文,别在库里直接存中文,改文案时你会哭。
3.3 回滚 SQL 生成与执行方式选择
回滚语句的生成逻辑按语句类型分:INSERT生成对应DELETE(按主键),UPDATE生成反向UPDATE(用执行前的旧值),DELETE生成反向INSERT(需要执行前把被删行查出来存好)。DDL类语句的回滚要单独处理,比如ADD COLUMN对应DROP COLUMN,但DROP COLUMN本身不可逆,这类工单在审批时要额外提示。
执行方式上,最后一级审核通过后给两个按钮:立即执行、定时执行。定时执行不是简单 sleep,而是把工单丢进待执行队列,由执行服务按plan_time轮询拉起。这里有个容易翻车的点:定时任务要加分布式锁或单实例执行标记,否则多副本部署时同一条工单会被执行两次。通知走钉钉,审批待办和执结果各推一次,消息体里带上工单 ID 和跳转链接,别只推一句「你有新的待办」。
4. 实例管理与工具插件落地:会话排查、数据归档与结构同步
审核解决「上线前」,实例管理解决「上线后出事怎么办」。这一块功能多但逻辑相对独立,实现上共用实例连接配置,每个子功能一个页面 + 一组后端接口即可。
4.1 会话、事务与锁的排查链路
排查阻塞的标准动作是:先看进程状态,勾选「完整 INFO」否则 SQL 显示不全,按 command 类型过滤(默认 query,要看全部选 All);定位到阻塞 SQL 后点「终止会话」。事务信息里的trx_mysql_thread_id对应进程状态里的 THREAD ID,想杀事务就按这个 ID 去进程页搜。锁信息页展示等待事务的 SQL 和阻塞方线程 ID,顺着线程 ID 回去杀进程。
-- 进程状态查询(对应页面上的会话列表) SELECT id, user, host, db, command, time, state, info FROM information_schema.processlist WHERE command = 'Query' OR command = 'Sleep'; -- 当前运行事务 SELECT trx_id, trx_state, trx_started, trx_mysql_thread_id, trx_query FROM information_schema.innodb_trx; -- 锁等待关系 SELECT waiting_trx_id, waiting_thread, blocking_trx_id, blocking_thread FROM information_schema.innodb_lock_waits;参数说明:processlist的info字段默认截断,页面上必须提供「完整 INFO」开关,后端对应把information_schema.processlist换成SHOW FULL PROCESSLIST或调大group_concat_max_len。锁等待查询在 MySQL 8 里字段名有变化,做兼容时按版本分支,别一套 SQL 打天下。模拟锁等待的验证方法原料里给了:两个会话对同一行做UPDATE,第二个被阻塞,此时锁信息页应能看到等待关系——这个用例直接写进验收清单。
4.2 binlog 清理与账号参数管理
磁盘告警时最直接的动作是清 binlog。实例列表里选中某个 binlog,该文件之前的所有 binlog 都会被删除,这个语义要在界面上写清楚,最好二次确认弹窗里列出将被删除的文件名和总大小。账号管理提供图形化的建号、授权、改密、删号,授权语句本质是拼GRANT,但权限项要做成勾选而不是让用户手写,减少拼错。
-- 账号授权示例:赋予增删改查与改表结构权限 GRANT SELECT, INSERT, UPDATE, DELETE, ALTER, CREATE, INDEX ON `baidd`.* TO 'app_user'@'%'; -- 查看 binlog 列表,供清理页展示 SHOW BINARY LOGS;设计说明:GRANT的库名和用户名必须做白名单校验,防止拼接注入;改密操作要记录操作人和时间,参数配置页同理——原料里提到「可修改实例动态参数并记录修改历史」,历史表至少存参数名、旧值、新值、操作人、时间。binlog 清理前建议先做一次全量备份校验,这条不是 Archery 原生功能,但作为方案里的「负责做法」值得补上。
4.3 三个插件的接入方式
pt-archiver 用于历史数据归档,典型场景是流水表只保留最近三个月,更早的数据归档到历史库,可配成自动任务。接入方式是把命令行参数做成表单:源库、目标库、归档条件、批量大小、是否只归档不删除。binlog2sql 做可视化,输入 binlog 文件名和起止位置,输出原始 SQL 或回滚 SQL,注意它只能回滚 DML,DDL 回滚不了,这个限制要写在页面提示里。schema 同步工具比对源库和目标库的表结构,生成更新 SQL 和回滚 SQL,只比对结构不比数据。
# pt-archiver 归档示例:把 3 个月前的流水归档到历史库 pt-archiver \ --source h=source_host,D=baidd,t=flow_log \ --dest h=archive_host,D=baidd_archive,t=flow_log \ --where "create_time < DATE_SUB(NOW(), INTERVAL 3 MONTH)" \ --limit 1000 --commit-each --purge参数说明:--limit 1000控制每批行数,太大容易长事务,太小归档慢;--purge表示归档后删除源表数据,不加则只复制不删;--where条件必须走索引,否则归档任务会把线上库拖垮。binlog2sql 的起止位置从SHOW BINLOG EVENTS里取,页面上让用户填文件名和 pos 区间即可,异步执行、结果通知,别做成同步阻塞请求。
5. 避坑与常见问题:上线前必须过的五道坎
5.1 审核规则误报导致工单全被驳回
现象:正常业务 SQL 提交后一堆 error,研发直接放弃使用平台。原因:规则库一刀切,比如强制所有表必须有自增主键,但关联表用的是联合主键。解决:规则按库或按业务线分组配置,支持单条规则临时豁免并记录豁免人和原因,豁免记录进审计表。
5.2 回滚 SQL 生成失败或不可用
现象:工单执行完想回滚,发现回滚语句是空的或执行报错。原因:UPDATE/DELETE没带主键条件,生成器拿不到定位行;或者执行前没把旧值查出来。解决:审核阶段就拦截「无主键条件的 DML」,回滚生成放在执行前一步,生成失败则禁止执行,宁可卡住也不留无法撤回的工单。
5.3 定时执行重复触发
现象:同一条工单被执行了两次,数据重复。原因:执行服务多副本,轮询时没有互斥。解决:工单状态迁移用乐观锁(UPDATE ... WHERE status = 1),影响行数为 0 就跳过;或者引入分布式锁,锁粒度到工单 ID。
5.4 会话排查时 SQL 显示不全
现象:进程列表里info只有半截,定位不到问题 SQL。原因:默认没开完整 INFO,或者group_concat_max_len太小。解决:页面默认勾选完整 INFO,后端用SHOW FULL PROCESSLIST,并在部署文档里把group_concat_max_len调到足够大。
5.5 binlog 清理误删还在用的文件
现象:清理后从库同步中断。原因:从库还没消费到的 binlog 被删了。解决:清理前查各从库的Relay_Master_Log_File,只删所有从库都已消费的文件;界面上展示每个 binlog 的大小和最早从库位点,二次确认。
6. 验收与答辩:用一条工单跑通全链路
验收不要按功能列表逐项点,那样既慢又容易漏。我一般会设计一条贯穿全链路的用例,从提交到回滚走一遍,中间故意制造一次失败,看平台能不能正确拦截。具体步骤:准备一条缺主键的建表 SQL,提交后应被规则引擎驳回并给出明确提示;补上主键和注释后重新提交,工单进入待审批;审批通过选定时执行,到点后确认数据落库;然后下载回滚 SQL 并执行,确认表结构恢复。再补一条 DML 工单,执行后回滚,验证数据恢复。最后模拟一次锁等待,在会话页定位阻塞方并终止,确认阻塞解除。
答辩时评委最爱问三个问题:规则怎么扩展、回滚为什么可靠、权限怎么隔离。第一个答「规则是函数 + 配置表,新增规则不改流程代码」;第二个答「回滚 SQL 执行前生成并落库,生成失败禁止执行」;第三个答「审核与执行分进程,执行侧单独授权,所有写操作走工单」。把这三个答案和上面的验收用例对应起来,基本就稳了。
| 验收项 | 通过标准 | 失败时看什么 |
|---|---|---|
| 规则拦截 | 缺主键/缺注释被驳回且提示准确 | 规则是否启用、解析结果字段是否为空 |
| 工单流转 | 状态单向迁移,审批记录完整 | 状态机是否有回退分支、审计表是否落库 |
| 定时执行 | 只执行一次,时间准确 | 乐观锁条件、执行服务副本数 |
| 回滚可用 | 回滚 SQL 能执行且结果正确 | 是否带主键条件、旧值是否留存 |
| 锁排查 | 能定位阻塞方并终止 | 完整 INFO 是否开启、版本字段兼容 |
血泪经验是:验收时一定要用真实业务量的表跑一次归档和 schema 比对,小表上一切正常,几百万行的表上--limit和索引没配好,归档任务能把线上库拖到报警。从那以后我每次交付这类平台,都强制先用一张大表跑一遍归档和回滚,再签字。希望帮到你。
本文还有配套的精品资源,点击获取