SQL Server存储过程与触发器实战:构建高可用数据审计系统
|
去年3月接了个审计系统的活儿,客户要求用SQL Server的存储过程和触发器搞高可用,我当时心里就咯噔一下——这俩玩意儿组合起来,说是“高可用”,不如说是“高维护”。但甲方爸爸要的是“实时审计+数据追溯”,除了触发器抓变更、存储过程做逻辑,还真没别的轻量级方案。结果项目做到一半,运维组的老王冲进会议室拍桌子:“你们这触发器把主库CPU顶到98%了!”当时外面正下暴雨,雨水顺着窗户缝往桌上淌,他手机还震个不停,全是告警短信。 存储过程和触发器这玩意儿,用好了是“优胜劣汰”的典范——淘汰掉那些靠应用层拼SQL的野路子,留下的是数据库原生能力。但“优胜”的前提是“能用好”。我原以为触发器只要别写太复杂的逻辑,比如只抓INSERT/UPDATE/DELETE的变更字段,再塞进审计表,应该没问题。结果客户非要“全字段审计”,连CREATE TABLE这种DDL操作也要抓。SQL Server的DDL触发器倒是能干这事儿,但问题是,DDL触发器是同步执行的,每次建表、改字段,主库都得等它写完审计记录才返回,生产环境里,这直接导致业务超时。 后来改方案,DDL审计改用事件通知(Event Notification),通过Service Broker异步处理。但存储过程那边又出幺蛾子——审计规则要能动态配置,比如“今天只审订单金额大于1000的变更,明天改成审所有订单状态变更”。我原以为用参数化存储过程就能解决,结果发现参数一多,执行计划就乱套,查询性能直接掉坑里。最后没办法,把审计规则拆成多个存储过程,用动态SQL拼,结果运维又跳出来:“你们这动态SQL,SQL注入风险太高!”当时茶水间的咖啡机正咕嘟咕嘟响,老王端着杯子过来,指着屏幕说:“看,这存储过程执行计划,每次参数不同,缓存都失效,CPU不炸才怪。” 高可用这块更坑。客户要求审计数据不能丢,主库挂了,备库得能无缝接管审计。我们用Always On可用性组,审计表放在主库,触发器写主库,存储过程也跑主库。结果测试时发现,主库故障切换到备库后,触发器不触发!原来SQL Server的触发器是数据库级别的,故障切换后,备库的数据库虽然在线,但触发器对应的会话上下文丢了,得重新建立连接才能生效。这导致故障切换后的头几分钟,审计数据全漏。最后解决方案是,在备库起个SQL Agent作业,每5秒查一次主库的变更日志(CDC),补录到备库审计表——这哪是高可用,分明是“高补丁”。 不过话说回来,这项目也不是全无亮点。存储过程和触发器在“数据一致性”上确实能打。比如订单表更新时,触发器能同时更新审计表,保证两边数据时间戳完全一致,应用层再怎么乱搞,审计记录也不会错。而如果用应用层写审计,万一网络抖动或者事务回滚,审计数据和业务数据就可能对不上——这事儿我见过太多次,某电商系统就是因为应用层审计没写成功,业务数据改了但审计没记录,被监管罚了五十万。 但“一致性”的代价是“性能”。触发器是同步执行的,存储过程是编译执行的,这俩凑一块儿,主库压力直接拉满。我们后来做了个优化:把触发器改成“轻量级触发器”,只抓变更ID和操作类型,具体审计内容(比如变更前后的字段值)由存储过程异步处理。存储过程用SSIS包跑,每小时拉一次触发器记录,再从业务表捞数据补全审计信息。这样主库触发器执行时间从200ms降到10ms,CPU占用从98%掉到30%。老王看了监控,终于没再拍桌子——不过他后来偷偷跟我说:“这方案其实是用空间换时间,审计表大了十倍,备份时间从半小时变成两小时。” 现在回头看,用存储过程和触发器搞高可用审计,就像用螺丝刀修汽车——能修,但得看车况。如果业务量小、数据变更频率低,这方案没问题;但要是高并发、大数据量,触发器分分钟把数据库拖垮。我后来跟客户说:“要不咱们改用变更数据捕获(CDC)+流处理?比如Kafka+Flink,审计延迟能控制在秒级,还不用改业务代码。”客户摇头:“监管要求审计必须用数据库原生功能,不能依赖外部组件。”我叹了口气——这要求就像让厨师用筷子炒菜,能炒,但肯定不如锅铲顺手。
文章配图,仅供参考 最近在V2EX上看到有人问“SQL Server触发器性能优化”,我回了句:“别优化触发器,优化业务设计,减少触发器触发频率才是正道。”结果被喷“不懂技术”——得,我又成键盘侠了。不过话说回来,这项目做完,我抽屉里多了三盒润喉糖——跟客户、运维、测试吵架吵的。(编辑:站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |


站长学院:SQL Server存储过程与触发器深度实战