ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

达梦数据库Zabbix监控实战:Agent脚本与ODBC直连落地方案

达梦数据库Zabbix监控实战:Agent脚本与ODBC直连落地方案 给达梦数据库接 Zabbix 监控卡住人的往往不是 Zabbix 那一侧。Zabbix 的搭建、添加主机、关联模板、看最新数据这一整套流程和监控 MySQL、Redis 没有本质区别真正别扭的是达梦DM这边没有官方现成模板、默认端口是 5236、动态视图叫 V$SESSIONS 而不是 information_schema、命令行工具是 disql 而不是 mysql 客户端连输出的格式都带着一堆登录横幅。我前后给几套生产环境做过 Zabbix 监控 DM 数据库第一套是用 Zabbix Agent 挂 shell 脚本采集第二套改成了服务端 ODBC 直连两套都跑在生产上也都踩过坑。这篇就把这两条路都摊开讲清楚达梦有哪些视图值得采、disql 采集脚本怎么写才不会被横幅输出污染、ODBC 驱动怎么和 unixODBC 对接、模板和触发器的阈值怎么定才不吵人、上线之后最常见的几类手工能跑、Zabbix 取不到数到底怎么排查。适合已经有 Zabbix 基础、正在给达梦做监控落地的运维和 DBA 看脚本部分可以直接抄。1. 达梦的监控要单独写一套是因为接口和 MySQL 完全不是一回事1.1 把 MySQL 模板搬过来一行都用不上很多人第一反应是去网上找一个 MySQL by Zabbix agent 的模板改改端口和账号就往上套。这条路走不通原因有三个层次。第一层是采集方式不同。MySQL 模板的核心是mysqladmin或者SHOW GLOBAL STATUS这类原生命令和协议Zabbix Agent 里能直接调用。达梦没有等价的东西它提供的是 disql 这个命令行工具加一套 Oracle 风格的动态视图所以要采集就得自己写脚本包一层。第二层是视图体系不同。达梦的动态视图大量使用$符号比如V$SESSIONS、V$INSTANCE、V$DM_INI这些视图在 shell 里当变量处理时会引发转义问题写脚本时如果不注意SQL 直接被 shell 吃掉一半报个语法错误你还以为是数据库的问题。这一条后面会专门讲。第三层是指标口径不同。连接数在 MySQL 里是Threads_connected在达梦里要自己count(*)会话视图表空间使用率在达梦里要用DBA_DATA_FILES减去DBA_FREE_SPACE手算而且临时表空间、回滚表空间的计算方式还不完全一样。所以这套模板本质上要重做而不是改参数。1.2 先把要监控的指标列清楚再动手写脚本我见过的失败案例里一半以上是没想清楚要采什么就开始写 UserParameter写了十几个 key上线之后发现有一半用不上另一半又漏了关键项。建议先在纸上列清单把指标分成四类可用性、连接与会话、空间容量、性能与阻塞。指标类别数据来源视图/命令建议采集周期备注实例状态V$INSTANCE的STATUS$1 分钟返回 OPEN/MOUNT 等状态字符串异常要立刻告警会话总数V$SESSIONS计数1 分钟更推荐换算成占 MAX_SESSIONS 的百分比活动会话数V$SESSIONS中STATEACTIVE1 分钟突增通常意味着慢 SQL 或应用连接池异常表空间使用率DBA_DATA_FILES/DBA_FREE_SPACE5 分钟注意区分自动扩展与固定大小数据文件锁等待事务数V$TRXWAIT1 分钟短时波动正常持续存在才告警长耗时 SQL 数V$LONG_EXEC_SQLS1 分钟不要用V$SQL_HISTORY做高频全扫参数配置值V$DM_INI1 小时用来做阈值换算和配置漂移比对归档目录占用主机层du5 分钟归档空间满会直接导致实例挂起这里有一个经验点值得单独说会话数不要用绝对值做阈值。一台库配的 MAX_SESSIONS 可能是 100另一台是 1500同一个绝对阈值放之四海皆不准。正确做法是先select para_name, para_value from v$dm_ini where para_nameMAX_SESSIONS;拿到上限再用会话数除以它算百分比阈值统一按 70%、85% 这类比例来定模板可以直接复用。1.3 两条落地路线的取舍Agent 脚本采集与 Server 端 ODBC 直连技术上有两条路可以走我在不同项目里都完整跑过。第一条是Zabbix Agent UserParameter shell 脚本。Agent 装在这台达梦所在的机器上脚本里用 disql 连本机实例把结果输出成纯数字或 JSON 给 Zabbix。优点是实现快、调试直观、不需要服务端装任何驱动缺点是每个数据库节点都要部署脚本脚本本身要维护监控账号的密码落在被监控机器上。第二条是Zabbix Server或 Proxy通过 ODBC 直连达梦。服务端装达梦的 ODBC 驱动配置odbc.conf用db.odbc.select类型的监控项直接发 SQL。优点是配置集中在服务端、SQL 改动不用登录被监控机器、天然支持自动发现缺点是要在服务端装数据库驱动驱动版本和位数不匹配时排查成本高而且服务端必须能直连到 5236 端口。选哪条如果达梦实例数量在两三套以内且已经有批量部署脚本走 Agent 方案更轻如果达梦实例多、且服务端到数据库网络可达走 ODBC 方案长期维护成本更低。下面两条路线我都会给出完整配置。2. 动手写脚本之前必须确认的四件事2.1 disql 能不能被 zabbix 用户跑起来这是第一个高频卡点。你在 root 或者 dmdba 用户下执行disql一切正常但 Zabbix Agent 默认是以zabbix这个系统用户运行的它对达梦安装目录可能没有读权限执行时会报找不到库文件或者直接权限拒绝。先做权限验证别急着写脚本# 先确认 disql 的位置 find / -name disql -type f 2/dev/null # 切换到 zabbix 用户模拟 Agent 的真实执行环境 sudo -u zabbix /opt/dmdbms/bin/disql -h如果这条命令报Permission denied或者error while loading shared libraries就是权限或环境变量问题。达梦安装目录一般是/opt/dmdbms或者/home/dmdba/dmdbms前者大概率是 755后者因为建在用户家目录下家目录往往是 700zabbix 用户连目录都进不去。注意不要图省事把达梦目录整个chmod -R 777这在生产环境是明确的安全问题。正确做法是把达梦安装目录上的执行路径单独开权限或者把disql需要的环境以最小范围授权给 zabbix 用户。2.2 环境变量必须写进脚本别指望配置文件这是最容易被忽略的一条。Zabbix Agent 启动脚本执行时用的是非交互式 shell不会去读.bash_profile、.bashrc所以你在命令行里export的那些变量脚本里一个都没有。达梦的 disql 依赖两个变量缺一个都可能起不来export DM_HOME/opt/dmdbms export PATH$DM_HOME/bin:$PATH export LD_LIBRARY_PATH$DM_HOME/bin:$LD_LIBRARY_PATHLD_LIBRARY_PATH是最容易漏的漏了之后报的错是找不到 libdmdpi.so之类看起来像库损坏实际就是路径没配。我的习惯是把这三行直接写在采集脚本开头而不是依赖任何外部 profile 文件脚本自己闭环换机器也不会出错。顺便把LANG也固定一下否则中英文 locale 混用时disql 的错误提示文本会变后期如果脚本里做了文本匹配就会莫名其妙失败export LANGen_US.UTF-82.3 建一个专用监控账号别用 SYSDBA用 SYSDBA 采集监控数据等于把整个实例的钥匙挂在监控系统上。一旦 Zabbix 被攻破或者脚本被读取数据库就直接沦陷。正确做法是建一个只有查询权限的账号CREATE USER ZBX_MON IDENTIFIED BY Zbx_mon_2024;接下来是权限授予。达梦的系统视图属于 SYS 用户直接GRANT SELECT ON V$SESSIONS TO ZBX_MON;可能报对象不存在需要带上属主前缀GRANT SELECT ON SYS.V$SESSIONS TO ZBX_MON; GRANT SELECT ON SYS.V$INSTANCE TO ZBX_MON; GRANT SELECT ON SYS.V$DM_INI TO ZBX_MON; GRANT SELECT ON SYS.DBA_DATA_FILES TO ZBX_MON; GRANT SELECT ON SYS.DBA_FREE_SPACE TO ZBX_MON;一个更省事但需要评估的做法是给这个账号SELECT ANY TABLE权限或者查看SELECT * FROM DBA_ROLES;找到达梦预定义的只读类角色再评估授予。我个人的建议是逐个授权因为监控用到的视图就那么十来个授完就固定了比开一个大权限要干净得多。授权之后一定要用新账号连一次把每个要用的 SQL 都跑一遍确认没有权限报错。2.4 先把 disql 的登录横幅问题解决掉用 disql 直连查询时输出里除了结果还会有类似服务器[127.0.0.1:5236]:处于普通打开状态和登录使用时间: xxx ms这样的提示行。这些行会混进采集结果里被 Zabbix 当成指标值于是你看到最新数据里全是文本监控项直接变成不支持。解决办法有两层建议叠加使用。第一层是关掉多余的输出格式set echo off set heading off set feedback off set pagesize 0 set linesize 300 set timing off第二层也是更稳的一层在 SQL 里给结果加哨兵前缀。比如本来要查会话数不写select count(*) from v$sessions;而是写成select SESS||count(*) from v$sessions;这样输出就固定成SESS42这一行脚本里用grep ^SESS | cut -d -f2取数无论横幅怎么写都不会误伤。这个技巧我在表空间、锁等待、会话数所有指标上都用了脚本从此再没出现过取值是文本的问题。3. 用 UserParameter 把达梦指标接进 Zabbix Agent3.1 通用采集函数一个壳子跑所有 SQL与其为每个指标写一个独立脚本不如写一个统一入口通过参数区分要采什么。这样脚本只有一份Agent 配置也清爽。#!/bin/bash # /etc/zabbix/scripts/dm_check.sh export DM_HOME/opt/dmdbms export PATH$DM_HOME/bin:$PATH export LD_LIBRARY_PATH$DM_HOME/bin:$LD_LIBRARY_PATH export LANGen_US.UTF-8 DM_HOST127.0.0.1 DM_PORT5236 DM_USERZBX_MON DM_PASSZbx_mon_2024 CONN${DM_USER}/\${DM_PASS}\${DM_HOST}:${DM_PORT} # 执行 SQL 并提取带哨兵前缀的数值结果 dm_query() { local sql$1 local tag$2 local out out$(timeout 6 disql ${CONN} EOF 21 set echo off set heading off set feedback off set pagesize 0 set linesize 300 set timing off ${sql} exit EOF ) echo ${out} | grep ^${tag} | head -1 | cut -d -f2 | tr -d \r }这里面三个细节值得展开。timeout 6是硬性保护。disql 在网络抖动或者实例负载极高时可能长时间不返回如果不加超时脚本会一直挂着Zabbix Agent 那边超时后就把监控项标成不支持恢复之后还要等一轮才能正常。加一层timeout能让脚本主动退出。grep ^${tag}是哨兵过滤配合前面 SQL 里的||拼接前缀使用。密码用双引号包在连接串里是为了兼容含特殊字符的密码。达梦的连接串对特殊字符比较敏感如果密码里带或者$不加引号会被解析成主机名的一部分。我的做法是干脆给监控账号用一个不含特殊字符的密码少一层转义就少一类问题。还有一点这种写法把密码放在了脚本里ps -ef是看不到的因为密码走了标准输入而不是命令行参数但脚本文件本身可读。所以文件权限要收紧chown root:zabbix /etc/zabbix/scripts/dm_check.sh chmod 750 /etc/zabbix/scripts/dm_check.sh3.2 会话、实例状态、锁等待这三个指标先落地脚本主体用 case 分支分发先把最关键的三个做出来case $1 in sessions) dm_query select SESS||count(*) from v\$sessions; SESS ;; sess_pct) dm_query select PCT||round(cnt*100/mx,2) from (select count(*) cnt from v\$sessions), (select para_value mx from v\$dm_ini where para_nameMAX_SESSIONS); PCT ;; active) dm_query select ACT||count(*) from v\$sessions where stateACTIVE; ACT ;; trxwait) dm_query select WAIT||count(*) from v\$trxwait; WAIT ;; longexec) dm_query select LONG||count(*) from v\$long_exec_sqls; LONG ;; esac这段代码里最需要留意的是v\$sessions里的反斜杠。SQL 写在双引号字符串里$s会被 shell 尝试当变量展开结果是 SQL 变成from vessions;然后 disql 报语法错误。加反斜杠转义是最直接的写法每次写完带$的视图名都要在本地bash -x跑一遍确认这是我调试脚本时最常用的手段。实例状态这个指标稍微特殊它返回的是字符串而不是数字所以要单独处理并且不能用纯数字过滤inststat) dm_query select STAT||status\$ from \$instance; STAT ;;脚本里取到的值可能是OPEN、MOUNT等触发器里做字符串比较即可。这里顺便说一个采集之外的检查点如果脚本里所有 SQL 都连不上Zabbix 会看到一堆监控项同时变成不支持这本身就是一个比单指标告警更强烈的信号值得在告警配置里加一条监控项不支持数量超过 N 时通知能大幅缩短故障发现时间。3.3 表空间使用率计算逻辑放在 SQL 里还是脚本里表空间使用率的计算我试过两种写法。一种是把总大小、剩余大小分别查出来在 shell 里做除法另一种是直接在 SQL 里除完只返回一个数字。强烈建议用后一种理由是第一个量级比较容易出精度问题第二是能少一次数据库往返。select TS||t.tablespace_name|| || round((t.total_bytes-nvl(f.free_bytes,0))*100/t.total_bytes,2) from (select tablespace_name, sum(bytes) total_bytes from dba_data_files group by tablespace_name) t left join (select tablespace_name, sum(bytes) free_bytes from dba_free_space group by tablespace_name) f on t.tablespace_name f.tablespace_name;这里有两个必须说的坑。第一个是nvl。某些表空间典型的是部分临时表空间在DBA_FREE_SPACE里可能查不到记录left join 之后 free_bytes 是 NULL不套nvl整个计算就变成 NULL监控项直接没值。这个坑不查数据很难发现等上线第二天才发现某个表空间没数据返工成本更高。第二个是表空间使用率和容量风险不是一回事。使用率 85% 但如果数据文件是自动扩展的、磁盘还剩很多其实风险不大使用率 60% 但数据文件是固定大小、已经不能扩了反而随时会写满。所以除了使用率建议再采一个剩余可扩展空间或者至少采一下数据文件的AUTOEXTENSIBLE属性。我一般会在模板里加一个文本型监控项把每个表空间的自动扩展状态记下来作为告警降级判断的依据。3.4 长耗时 SQL 和慢 SQL别用重视图判断数据库是否有性能问题看长耗时 SQL 是很有效的。但有个前提采这个指标本身不能给数据库带来负担。V$SQL_HISTORY里存的是历史 SQL 记录量很大如果每分钟去全表扫一次并按耗时排序在高并发库上会产生明显的额外开销等于监控把业务拖慢了。相对轻量的做法是查V$LONG_EXEC_SQLS这个视图里通常只保留长时间运行的语句行数很少longexec) dm_query select LONG||count(*) from v\$long_exec_sqls; LONG ;;如果你的版本里这个视图名不一样select * from v$long_exec_sqls;报无效视图的话可以退一步用V$SQL_HISTORY但一定要把时间范围限制住比如只取最近一分钟的记录并且把采集周期放到 5 分钟别放在 1 分钟。顺便提一句视图字段的确认习惯达梦不同小版本之间视图的字段名偶尔会有差异写脚本之前先DESC V$SESSIONS;或者select * from v$trxwait where rownum3;看一眼实际字段比翻文档快也不会因为字段名猜错而在上线后才发现问题。3.5 表空间自动发现一次配置新增表空间不用改脚本表空间是会增加的今天写死三个表空间明天加了两个就得回来改模板这种维护方式迟早会漏。用 Zabbix 的低级别自动发现LLD能一次性解决。脚本里增加一个分支输出 JSONts_discovery) raw$(timeout 8 disql ${CONN} EOF 21 set echo off set heading off set feedback off set pagesize 0 set linesize 300 select TS||t.tablespace_name|| ||round((t.total_bytes-nvl(f.free_bytes,0))*100/t.total_bytes,2) from (select tablespace_name, sum(bytes) total_bytes from dba_data_files group by tablespace_name) t left join (select tablespace_name, sum(bytes) free_bytes from dba_free_space group by tablespace_name) f on t.tablespace_name f.tablespace_name; exit EOF ) echo ${raw} | awk BEGIN { printf {\data\:[ } /^TS/ { split(substr($0,4), a, ); if (n) printf ,; printf {\{#TSNAME}\:\%s\,\{#TSPCT}\:\%s\}, a[1], a[2]; } END { printf ]} } ;;awk 里用n判断是否是第一条记录是第一条就不输出逗号这是生成合法 JSON 最省事的写法。如果表空间名字里带空格切分逻辑要相应调整正常情况下表空间名都是不含空格的标识符。对应的监控项原型 key 是dm.ts.pct[{#TSNAME}]脚本里增加一个按名字查询的分支ts_pct) dm_query select TS||round((t.total_bytes-nvl(f.free_bytes,0))*100/t.total_bytes,2) from (select tablespace_name, sum(bytes) total_bytes from dba_data_files where tablespace_name$2 group by tablespace_name) t left join (select tablespace_name, sum(bytes) free_bytes from dba_free_space where tablespace_name$2 group by tablespace_name) f on t.tablespace_namef.tablespace_name; TS ;;宏{#TSNAME}的值来自数据库本身属于可控输入但仍然建议在 SQL 里对表空间名做一次校验避免极端情况下名字里出现引号把 SQL 拼坏。3.6 Agent 配置、重启与自测采集脚本写完之后Agent 侧只要一个配置文件# /etc/zabbix/zabbix_agentd.d/dm.conf UserParameterdm.sessions,/etc/zabbix/scripts/dm_check.sh sessions UserParameterdm.sess_pct,/etc/zabbix/scripts/dm_check.sh sess_pct UserParameterdm.active,/etc/zabbix/scripts/dm_check.sh active UserParameterdm.inststat,/etc/zabbix/scripts/dm_check.sh inststat UserParameterdm.trxwait,/etc/zabbix/scripts/dm_check.sh trxwait UserParameterdm.longexec,/etc/zabbix/scripts/dm_check.sh longexec UserParameterdm.ts.pct[*],/etc/zabbix/scripts/dm_check.sh ts_pct $1 UserParameterdm.ts.discovery,/etc/zabbix/scripts/dm_check.sh ts_discovery超时参数必须调整。Zabbix Agent 默认的Timeout是 3 秒disql 建立连接本身就要几百毫秒到一秒加上实例繁忙时可能更久3 秒经常不够。在主配置zabbix_agentd.conf里把Timeout调到 10同时脚本内部的timeout要比它小形成两级保护Timeout10配置完重启 Agent然后按顺序做三步自测顺序不要颠倒# 1. 以 zabbix 用户直接跑脚本验证权限和环境 sudo -u zabbix /etc/zabbix/scripts/dm_check.sh sessions # 2. 用 zabbix_get 从本地取值验证 Agent 能拿到脚本输出 zabbix_get -s 127.0.0.1 -k dm.sessions # 3. 用 zabbix_get 测自动发现验证 JSON 格式合法 zabbix_get -s 127.0.0.1 -k dm.ts.discovery第二步是关键分界线。如果第一步成功、第二步失败问题一定在 Agent 配置层面key 名写错、配置文件没被 include、Agent 没重启如果两步都成功那问题就在服务端或者模板定义上。这个分界思路能省掉大量瞎猜时间。4. ODBC 路线让 Zabbix Server 直接连达梦4.1 达梦 ODBC 驱动与 unixODBC 的对接细节ODBC 方案的前提是服务端能加载达梦的 ODBC 驱动。达梦安装包里带了这个驱动名字通常叫libdodbc.so先在数据库机器上确认位置find / -name libdodbc* 2/dev/null一般会在$DM_HOME/bin或者$DM_HOME/drivers/odbc下面。确认之后在 Zabbix 服务端装 unixODBC然后写两个配置文件。第一个是驱动注册文件# /etc/odbcinst.ini [DM8 ODBC DRIVER] Description DM ODBC Driver Driver /opt/dmdbms/bin/libdodbc.so第二个是数据源文件# /etc/odbc.ini [DM] Description DM Database Driver DM8 ODBC DRIVER Server 10.0.0.11 UID ZBX_MON PWD Zbx_mon_2024 Port 5236 TCP_PORT 5236这里的几个细节很重要。驱动Driver这一项必须写完整的绝对路径写驱动名会导致找不到库。有的版本需要同时写Port和TCP_PORT只写一个时连接会失败报错信息还很不直观所以两个都写上比较稳。位数必须匹配。Zabbix 服务端是 64 位的驱动也必须是 64 位如果驱动目录里同时有 32 位和 64 位版本选错了之后出现的现象是驱动能加载但连接不上非常难排查。可以先用odbcinst -j确认当前 unixODBC 读取的是哪个配置文件、是哪个位数。配置完成后用 isql 测一下isql -v DM能进到 SQL 提示符并执行select count(*) from v$sessions;就有值说明驱动这条链通了。这一步不通后面 Zabbix 里怎么配都不会通所以一定先在这里验证。4.2 odbc.conf 与 db.odbc.select 的写法服务端这边还需要给 Zabbix 一个 ODBC 配置入口默认读取的文件一般是/etc/zabbix/odbc.conf格式是段落名 DSN 指向# /etc/zabbix/odbc.conf [DM] DSNDM方括号里的DM是给 Zabbix 用的段落名DSNDM指向/etc/odbc.ini里的数据源名这两个名字可以一样也可以不一样但自己心里要分清哪个是哪个我见过不少人在这里改错一个名字排查了半天。服务端配置里要确认 ODBC 采集进程是打开的StartODBCPollers5然后在 Web 界面创建监控项类型选Database monitorkey 写成db.odbc.select[dm_sessions,DM]第一个参数是这个查询的唯一描述第二个参数是odbc.conf里的段落名。这里有几条硬性限制必须知道只允许 SELECT 语句执行 DML 会被直接拒绝查询必须只返回一个值返回多行或者多列都会导致取值失败。所以像一次性查出所有表空间使用率这种需求不能用db.odbc.select实现要么拆成多个监控项要么用下面讲的自动发现。一个可用的查询示例select round(cnt*100/mx,2) from (select count(*) cnt from v$sessions), (select para_value mx from v$dm_ini where para_nameMAX_SESSIONS)4.3 用 db.odbc.discovery 做表空间自动发现ODBC 方式的自动发现比脚本方式更简洁因为不需要手写 JSONZabbix 会把查询结果的列直接转成宏。select t.tablespace_name as TSNAME, round((t.total_bytes-nvl(f.free_bytes,0))*100/t.total_bytes,2) as TSPCT from (select tablespace_name, sum(bytes) total_bytes from dba_data_files group by tablespace_name) t left join (select tablespace_name, sum(bytes) free_bytes from dba_free_space group by tablespace_name) f on t.tablespace_name f.tablespace_name监控项 keydb.odbc.discovery[dm_ts,DM]生成的宏是{#TSNAME}和{#TSPCT}之后监控项原型里就能用db.odbc.select[ts_{#TSNAME},DM]这样拼出来。这里有个关于大小写的经验点列名的大小写决定了宏名的大小写。达梦默认会把不带引号的列名转成大写返回所以写tablespace_name得到的宏可能是{#TABLESPACE_NAME}而写as TSNAME用双引号强制保留大小写得到的宏就是{#TSNAME}。宏名写错的表现是监控项原型关联不上界面上看着像配置成功实际没有数据。最省事的验证方式是先建好发现规则手工执行一次测试直接看返回的 JSON 里的宏名到底长什么样然后照着抄。4.4 两种方式怎么选看这几个现实条件对比维度Agent 脚本采集ODBC 直连部署位置每台数据库机器都要装 Agent 和脚本只需服务端装驱动驱动依赖无需匹配位数与版本的 ODBC 驱动SQL 修改成本每台机器都要更新脚本改服务端一处即可复杂计算能力强可在 shell 里做逻辑分支弱只允许单值 SELECT凭据存放位置被监控机器上的脚本文件Zabbix 服务端配置文件网络要求Agent 与被监控机本地通信服务端或 Proxy 能直连 5236排查难度直观看输出容易定位驱动层问题排查较绕我的实际选择是达梦实例少、已经有自动化装机能力的用 Agent 脚本实例多、网络规划允许服务端直连的用 ODBC。如果两种都想用也是可以的——用 ODBC 做大批量基础指标用 Agent 脚本做需要复杂计算的特殊指标两者互补。5. 模板、触发器阈值与告警收敛5.1 模板命名与宏设计一开始就要定规矩模板名字建议带上数据库类型和采集方式比如DM DB by Zabbix agent和DM DB by ODBC后面抗压测试库、报表库、生产库都关联同一个模板改动一处全局生效这是模板化最大的价值。宏的使用要克制但必须用。我一般会把所有阈值都抽成模板级宏宏名默认值说明{$DM_TS_WARN}85表空间使用率告警阈值百分比{$DM_TS_HIGH}93表空间使用率严重告警阈值{$DM_SESS_WARN}70会话占上限比例的告警阈值{$DM_SESS_HIGH}85会话占上限比例的严重阈值{$DM_TRXWAIT_TIME}5m锁等待持续时长判定把这些值放在宏里遇到个别库配置特殊比如某个库就是长期高负载运行只在主机层面覆盖宏即可不用去改模板也不会影响其他主机。不要把这些阈值硬编码在触发器表达式里这是后期维护成本最高的做法我接手过的老模板里全是写死的数字改一次要动十几个触发器。5.2 阈值不是拍脑袋几个指标的具体定值思路表空间使用率按 85% 告警基本是行业惯例但有个前提要结合数据文件是否自动扩展一起判断。我的做法是设两级85% 触发一般告警93% 触发严重告警同时把数据文件不可自动扩展且使用率超过 85%作为独立的高优先级告警条件。这样不至于因为一个可以自动扩展的表空间到 86% 就把人半夜叫起来。会话数阈值按占 MAX_SESSIONS 的比例来定70% 告警是比较通用的起点。会话数高的本质原因通常是应用侧连接池配置不合理或者有慢 SQL 导致会话堆积所以这条告警的价值不只是提醒你连接多了而是提醒你去看活动会话的分布。锁等待这个指标要特别注意误报。短事务之间出现少量锁等待是完全正常的如果一看到0就告警告警会响个不停。正确写法是加持续时间条件比如持续 5 分钟以上才触发min(/DM DB by Zabbix agent/dm.trxwait,5m)0实例状态和可用性这块建议单独处理一旦实例状态不是OPEN直接走最高优先级通道并且同时把这条主机的其他指标告警抑制掉否则一次实例故障会给你推几十条关联告警真正重要的那条反而被淹没。5.3 恢复表达式、依赖关系与维护期告警能不能用一半决定在恢复逻辑上。如果只配了触发条件没配恢复表达式默认是条件不再成立就恢复听起来没问题但阈值附近的抖动会导致触发—恢复—触发来回刷屏。解决方式是在触发器里显式写恢复表达式并且留出滞回区间。比如表空间使用率 85% 触发恢复条件设成低于 82%恢复表达式last(/DM DB by Zabbix agent/dm.ts.pct[{#TSNAME}])82这三个点的差值就是滞回带能有效压掉边界抖动实测下来告警量能减少一大截。依赖关系也值得花十分钟配一下。典型依赖是实例状态类触发器作为父会话数、锁等待、长 SQL 这些作为子父触发器触发时子触发器自动静默。数据库都连不上了再去告警会话数没有意义。维护期是另一个必要配置。数据库做版本升级、参数调整、大表重建这些操作时手工建一个维护窗口窗口期内告警不发送但数据照常采集事后做容量分析时数据是完整的。这个习惯我强烈建议养成不然每次变更都会被自己的监控吵一遍。5.4 告警出口Webhook 与钉钉机器人指标采集通了之后告警得有地方去。比较常见的做法是走 Webhook 媒介类型把告警推送到钉钉群机器人。配置路径是告警媒介类型里新建一个 Webhook 类型脚本里处理请求体和签名然后把媒介分配给对应的用户或者用户组。钉钉机器人如果开了加签需要把 secret 放在媒介类型的参数里签名算法用 HMAC-SHA256时间戳和密钥拼在一起算这一步做错了会一直收到sign not match之类的返回但 Zabbix 侧的日志不一定显示得清楚所以配完媒介类型之后一定要点一次测试按钮看到返回成功再分配。消息内容的组织上有个经验是别把所有指标都推。我一般按优先级分通道实例不可用、表空间严重告警推主群并 at 相关负责人一般级别的使用率告警推到一个汇总群每天定时发一次日报就够了。全部走实时推送的结果就是没人看。6. 上线之后最容易踩的几类坑6.1 手工执行成功、Zabbix 取值失败这是出现频率最高的一类问题九成以上的原因就三个。第一个是执行用户不一致。你手工执行用的是 root 或者 dmdbaAgent 用的是 zabbix 用户权限和环境变量都不同。唯一的验证方式就是sudo -u zabbix跑一遍别的都不算数。第二个是环境变量缺失。前面强调过非交互式 shell 不读 profile 文件LD_LIBRARY_PATH一定要写在脚本头部。第三个是超时。Agent 默认 3 秒disql 连接加上查询可能超了表现就是监控项变成不支持日志里能看到 timeout 相关记录。把Timeout调到 10 之后观察一段时间。排查顺序建议固定下来先看sudo -u zabbix 脚本再看zabbix_get最后看服务端日志里的监控项错误信息三层依次排除比凭感觉猜快得多。6.2 返回值不是数字错误信息被当成指标值监控项的最新数据里显示成一段中文或者英文报错而不是数字这在刚开始用的时候非常常见。原因是脚本把 disql 的错误输出也一起返回了比如权限不足、SQL 语法错误、视图不存在这些错误文本会原样返回给 ZabbixZabbix 一看不是数字就标成不支持。除了前面说的哨兵前缀过滤还有一个必须加的兜底脚本里对结果做数字格式校验不符合的直接让脚本以非零状态码退出并往标准错误里写清楚原因val$(dm_query select SESS||count(*) from v\$sessions; SESS) if ! echo ${val} | grep -qE ^[0-9](\.[0-9])?$; then echo dm_check: invalid result for sessions: ${val} 2 exit 1 fi echo ${val}以非零码退出后Zabbix 会把监控项标为不支持而不是记录一个错误的数值。这两种行为的差别很大错误的数值会污染历史数据、触发错误的告警、做趋势分析时给出错误结论而不支持会明确告诉你采集出问题了。顺带说一个同类的坑不要依赖错误信息的文本内容做判断。不同语言环境下 disql 的提示文字不一样用文本匹配判断是不是权限错误这种做法迟早会失效用退出码和固定的哨兵前缀才是稳的。6.3 disql 偶发挂死导致的假告警有这么一类现象告警说会话数取不到值你去机器上手工跑脚本一切正常过几分钟监控又自己恢复了。这多半是 disql 偶发挂死或者响应极慢导致的。原因通常是实例瞬时负载很高、网络抖动、或者数据库在做检查点。处理方式是脚本内加timeout前面示例里的timeout 6同时在 Zabbix 触发器里避免用单次取不到数据就告警改用nodata配合较长时间窗口比如 3 分钟没数据才告警。单次抖动本来就不该惊动人。还有一点值得提醒采集频率不要一味调高。表空间这类慢变化指标的采集周期放到 5 分钟完全够用会话数、锁等待这类放到 1 分钟也够。把十几个指标全部设成 30 秒对数据库和 Zabbix 服务端都是没必要的负担反而增加了抖动概率。6.4 权限与编码类报错的排查顺序上线后如果报错指向权限或者字符集建议按下面这个顺序排查避免乱试。现象优先怀疑验证方法提示视图不存在或对象无效监控账号没被授权该视图用 ZBX_MON 账号手工跑一遍该 SQL提示需要更高权限脚本里用了 SYSDBA 或权限不足的账号检查连接串里的用户名输出里中文全变成问号locale 设置不一致脚本里固定LANGen_US.UTF-8提示找不到库文件LD_LIBRARY_PATH未设置在脚本里打印 env 后对比提示连接被拒绝端口或实例名不对确认实际监听端口是否为 5236返回值时有时无脚本超时或数据库瞬时忙检查 Agent 日志中的 timeout 记录这里面的排查思路是从下往上验证先确认账号和 SQL 本身没问题再看脚本环境最后看 Agent 和模板配置。反过来从模板开始查往往会在服务端折腾半天最后发现问题只是监控账号少了一个视图的查询权限。脚本化监控还有一个容易被忽略的收益脚本本身是一份可执行的文档。半年之后有人问这个库的监控都采了什么直接把脚本打开就能看到所有 SQL比翻模板里的监控项配置快得多。所以我在脚本里习惯给每个指标加一行注释写清楚这个指标对应什么业务含义、阈值大概定在多少这些小注释在交接的时候价值很高。我个人在实际操作中的体会是达梦的 Zabbix 监控真正花时间的部分不是写脚本而是前期搞清楚实例上哪些指标值得采、哪些视图查询代价可以接受。第一版别追求大而全先把实例状态、会话比例、表空间使用率、锁等待这四项做扎实跑上两周看看告警质量再逐步补指标。急着一次配齐几十个监控项的做法通常的结果是告警噪音太大最后大家把整个模板的告警都静音监控就白做了。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进