数据库安全与运维管控(一):MySQL、PG与Oracle原生审计机制

0 阅读1分钟

在满足等保2.0、SOC2 或金融合规审查时,“开启数据库审计”是硬性指标。合规要求企业必须记录“谁、在什么时间、执行了什么SQL、结果如何”。

面对这个需求,开发和运维通常首先想到的是利用数据库引擎自带的原生审计功能。但在海量并发(高 QPS)的生产环境中,原生审计往往会成为拖垮数据库性能的元凶。

本文将拆解 MySQL、PostgreSQL 和 Oracle 三大主流关系型数据库的原生审计机制,并客观分析它们在高并发下的性能损耗。

一、 MySQL 的原生审计方案

MySQL 官方及开源分支主要提供两种层级的审计方式:

1. General Query Log(通用查询日志)

这是最简单粗暴的方案。通过执行 SET GLOBAL general_log = 'ON';,MySQL 会将接收到的每一条 SQL 语句(无论执行成功与否)直接追加写入到磁盘日志文件中。

  • 技术机制: 在 Server 层接收到 SQL 文本后立刻记录,同步写盘。
  • 性能损耗:极高。 在 QPS 超过 1000 的业务库上开启 General Log,会引发极其严重的磁盘 I/O 瓶颈。因为每一次查询都被强加了一次磁盘写操作,且日志文件膨胀速度惊人,通常只用于非生产环境的短时间 Debug。

2. Audit Plugin(审计插件)

为了解决 General Log 无法过滤且性能极差的问题,MySQL 企业版、Percona Server 和 MariaDB 提供了基于 Plugin API 的审计插件(如 audit_log 插件)。

  • 技术机制: 审计插件通过 Hook 机制挂载在 MySQL Server 层的特定事件点(如 MYSQL_AUDIT_GENERAL_CLASS)。当 SQL 经过解析器(Parser)和执行器(Executor)时,触发 Hook 拦截。插件会根据预设的过滤规则(如只记录某些特定用户的操作,或只记录 DROP/DELETE 语句),决定是否将事件写入审计文件(通常是 JSON 或 XML 格式)。

  • 性能损耗:中到高。 * CPU 损耗: 每一条 SQL 都需要经过正则匹配或规则校验,增加 CPU 负载。

  • I/O 损耗: 尽管 Percona 等插件支持异步刷盘(Asynchronous logging),但在大批量 DML 写入或高频查询时,插件的 Buffer 极易被打满,依然会阻塞工作线程(Worker Thread),导致查询 RT(响应时间)出现毛刺。

二、 PostgreSQL 的原生审计方案

PG 的审计思路与 MySQL 类似,也分为日志级和插件级。

1. 标准日志参数(log_statement)

在 postgresql.conf 中配置 log_statement = 'all'(或 'mod' / 'ddl')。

  • 性能损耗: 与 MySQL 的 General Log 一样,开启 all 会导致海量写盘,严重占用 IOPS,绝对不建议在高并发生产库使用。

2. pgAudit 扩展插件

pgAudit 是目前 PG 生态中最标准的审计解决方案,AWS RDS 等云数据库也内置了该扩展。

  • 技术机制: pgAudit 利用了 PG 内核提供的 ProcessUtility_hook 和 ExecutorCheckPerms_hook。相比于标准日志只记录原始 SQL 字符串,pgAudit 能够在执行阶段捕获 SQL 的抽象语法树(AST)。这意味着它能展开视图(View),精确记录底层实际被访问的物理表。
  • 性能损耗:中。 pgAudit 生成的日志最终是通过 PG 默认的日志系统(syslog 或 stderr)落盘。它的瓶颈主要在日志收集与写盘上。在重度读写的业务中,频繁的 Hook 拦截和字符串格式化输出,通常会导致 5% - 15% 的性能衰减。

三、 Oracle 的原生审计机制

Oracle 作为商业数据库的老大哥,其审计机制的设计远比 MySQL 和 PG 复杂且成熟。从 Oracle 12c 开始,全面推行了 Unified Auditing(统一审计)。

1. 传统审计(Pre-12c)

早期 Oracle 审计将记录写入 SYS.AUD$ 表或系统文件中。如果是对表数据变更(谁改了特定字段)的细粒度审计(FGA),甚至依赖底层触发器(Trigger)。这会导致严重的锁竞争和 UNDO 表空间消耗。

2. 统一审计(Unified Auditing)

  • 技术机制: 12c 引入了基于策略(Policy)的审计。它的核心架构改进在于,审计数据的生成与持久化被彻底解耦。审计记录首先被写入 SGA(系统全局区)的内存队列中(类似 Buffer),然后由专门的后台进程(GEN0)采用批量化、异步的方式刷入到只读的 AUDSYS 内部分区表中。
  • 性能损耗:低。 由于采用了基于内存队列的异步批处理写入,统一审计在开启全量规则时,对正常 SQL 执行线程的阻塞极小。在同等 QPS 下,Oracle 统一审计的性能损耗是三大数据库中控制得最好的(通常在 5% 以内)。

四、 核心矛盾:为什么原生审计在生产环境“不好用”?

纵观上述原生方案,除了 Oracle 架构相对优秀外,MySQL 和 PG 的原生审计在面对高并发业务时,都会暴露以下物理局限性:

  1. 宿主机资源争抢: 审计日志的过滤(耗 CPU)和落盘(耗 I/O)与数据库引擎的查询计算运行在同一台物理机上。在双十一、大促等高负载场景下,审计组件直接抢占业务 SQL 的算力。
  2. 动态扩缩容困难: 如果因为审计日志写入过慢导致数据库连接堆积,除了修改参数并重启插件(风险极高),DBA 没有其他隔离手段。
  3. 日志提取与分析成本高: 原生审计落地的通常是杂乱的 JSON 或文本文件。安全团队如果需要查询“张三在昨晚执行了哪些 SELECT”,需要通过 Logstash/Filebeat 等工具将这些日志采集到 Elasticsearch 中再去建索引。整条日志采集链路复杂,且极易丢数据。

五、 总结

数据库的原生审计机制非常适合 QPS 较低的内部管理系统,或者仅用于记录极少数高危 DDL 操作的场景。

但对于互联网业务、高并发核心交易库,如果要实现面向所有用户的全量 SQL 审计,依赖底层数据库引擎自己“边执行边记录”是违反工程规律的。这也是为什么业界在处理海量审计时,逐渐摒弃原生机制,转向网络层流量镜像(旁路审计)或应用层网关代理的根本原因。