mysql触发器是否适合做审计_mysql日志设计实践

6次阅读

mysql触发器不适合生产级审计,因其无法捕获truncate、load data、ddl、逻辑备份恢复及从库复制等操作,且易导致事务失败和性能瓶颈;官方推荐使用audit_log插件,它在连接层记录全量事件,覆盖登录、sql执行及结果状态。

mysql触发器是否适合做审计_mysql日志设计实践

MySQL 触发器不适合做生产级审计,它只能作为临时补救或低负载场景下的辅助手段。真正可靠的审计必须依赖 MySQL 自身的通用日志(general_log)、审计插件(如 audit_log)或外部代理层(如 ProxySQL + 日志捕获),否则极易漏记录、拖慢性能、甚至导致事务失败。

触发器审计会 silently 丢失哪些操作

触发器只在 INSERT/UPDATE/delete 语句执行时触发,但以下关键行为完全绕过它:

  • TRUNCATE table —— 不走触发器,不记 binlog(在 ROW 格式下也不触发)
  • LOAD DATA INFILE —— 批量导入默认不触发行级触发器(取决于版本和 sql_mode)
  • DDL 操作(ALTER/DROP/CREATE)—— 触发器对结构变更无感知
  • 通过 mysqldump --single-transactionmysqlpump 的逻辑备份恢复 —— 属于客户端重放,可能跳过触发器逻辑
  • 从库上的复制线程写入 —— 即使主库触发了,从库默认不重新触发(除非显式设置 log_bin_trust_function_creators=1 且函数被标记为 DETERMINISTIC,但依然不可靠)

audit_log 插件才是官方推荐的审计路径

MySQL 5.6+ 官方企业版自带 audit_log 插件,社区版可通过 mariadbserver_audit 插件或 Percona Server 的 audit_log 替代。它记录的是连接层事件,覆盖完整:

  • 登录/登出(含用户名、IP、时间戳)
  • 所有 SQL 语句(包括 DDL、SETUSE 等)
  • 执行结果状态(status 字段标识成功/权限拒绝/语法错误等)
  • 支持 jsonxml 格式输出,可直接对接 elk 或 Syslog

启用方式极简:

INSTALL PLUGIN audit_log SONAME 'audit_log.so';

再配置 audit_log_formataudit_log_policy 即可。注意:该插件会轻微增加连接开销,但远低于触发器对 DML 的阻塞影响。

触发器审计的典型性能陷阱

每个触发器都运行在原事务上下文中,意味着:

  • 审计表写入失败(如磁盘满、锁冲突、字段类型不匹配)会导致整个业务事务回滚 —— INSERT INTO orders 失败仅仅因为 INSERT INTO audit_log 报错
  • 并发下审计表成为热点,INSERT ... select ... FROM information_schema.PROCESSLIST 这类常用“取客户端信息”操作会加剧元数据锁争用
  • 触发器中调用 NOW()USER() 是安全的,但调用自定义函数或访问其他表(尤其大表 JOIN)极易引发死锁
  • MySQL 8.0 后虽支持触发器内事务控制(GET DIAGNOSTICS),但无法 rollback 外部事务,只能 abort 当前触发器逻辑 —— 审计失败仍无补救机制

真正的审计设计不是“要不要记”,而是“谁来记、在哪记、记多少、怎么查”。触发器连“谁来记”都答不上来 —— 它依赖业务 SQL 路径,而真实系统里 ORM、中间件、定时任务、离线脚本根本不会走你写的那几个触发器。

text=ZqhQzanResources