开头做了部分省略(后补充),以下是完整文章:
在监控体系搭建这件事上,Oracle数据库的接入一直是让我比较头疼的一环。Zabbix本身很强,但面对Oracle这种商业数据库,它默认提供的监控手段并不算友好,要么靠ODBC直连写SQL,要么靠外部脚本采集后主动上报。折腾过几条路之后,我最终选了orabbix 1.2.3这套方案——它用JDBC直连数据库,再把采集结果通过Zabbix的trapper通道送进去,整个链路清晰,部署成本可控,而且对Zabbix版本没有太多挑剔。这篇文章就是把我这次完整搭建的过程、配置思路和踩过的坑都记录下来,给正准备做同类监控的朋友一个可以直接参考的落地版本。
1. 为什么我在众多方案里选了orabbix
先交代一下背景。我这边环境里有一套比较核心的业务系统跑在Oracle上,版本是11g和19c混着来,DBA团队平时要看的指标包括会话数、表空间使用率、等待事件、归档日志增长这些。Zabbix层面的监控架构是现成的,主机已经通过agent纳管,但我需要一种方式把Oracle的深度指标拉进来,又不希望改动应用端和数据库端太多。
1.1 裸监控的痛:Zabbix自带的Oracle监控基本不好用
Zabbix官方从4.0开始就带了一套Oracle by ODBC模板,原理是用unixODBC加上Oracle的ODBC驱动,直接通过SQL查询数据库动态性能视图。听起来不难,但实际用起来有几个让我非常难受的点。
首先是ODBC环境配置繁琐。你得在Zabbix server端装unixODBC、Oracle Instant Client、配置odbc.ini、确认libnnz等库的路径,任何一步对不上,监控项就疯狂报“cannot connect to ODBC DSN”。更麻烦的是,ODBC模板里每条监控项默认的刷新间隔是60秒或者更短,如果你主机比较多,Zabbix server会频繁发起数据库连接,Oracle侧的审计日志会被刷得飞起,DBA看到一堆陌生连接心里肯定不舒服。
其次是SQL模板的覆盖范围太固定。官方ODBC模板对表空间、会话这些基础指标还行,但遇到我们实际关心的归档日志删除策略、RMAN备份状态、特定等待事件趋势,模板里并没有现成的监控项,你只能自己去写SQL。写SQL本身不是问题,问题在于Zabbix ODBC模板的每个监控项都要单独配一条查询语句、一个刷新策略,维护成本直接翻倍。
1.2 orabbix解决的三个核心问题
orabbix给我的第一感受是“它真的懂Oracle”。它本身是一个Java编写的代理程序,部署在可以和Oracle数据库网络互通的机器上,用JDBC驱动连进去,通过配置文件预先定义好一组查询语句,周期性地轮询Oracle视图,然后把结果推给Zabbix server。
这个架构天然解决了三个问题:
第一,不需要在Zabbix server本地配置任何数据库驱动。Zabbix server和orabbix分开,数据库连接的压力全部落在orabbix代理上。我再也不用来回折腾ODBC的依赖,代理挂了也不会影响Zabbix本身。
第二,orabbix自带了很多成熟监控项。表空间使用率、会话数、物理读/逻辑读、硬解析/软解析比例、Buffer Cache命中率、共享池命中率、归档日志生成量、甚至RMAN备份状态都有现成的查询逻辑。导入它的模板后,你能在Zabbix前端直接看到几十个监控项,而不是自己从头写。
第三,orabbix支持自动发现。它通过LLD机制发现数据库里有哪些表空间,然后动态生成监控项,新增表空间后不需要手工加监控,这个对业务频繁变化的库来说非常实用。
1.3 它和ODBC直连方案的差异
我接触过一些团队是直接用ODBC方案强行上线的,结果在数据库扩容或者跨机房场景下,Zabbix server连远程数据库的延迟和稳定性出了不少问题。ODBC方案的特点是“Zabbix直接连库”,适合数据库数量少、网络环境简单的情况;而orabbix是“代理连库后再推给Zabbix”,相当于在数据库和Zabbix之间加了一层缓冲。
这层的意义在于:orabbix可以对数据库连接做复用,一个代理进程维护少量的JDBC连接池,而不是每个监控项都新建会话。同时orabbix的轮询方式是通过trapper端口主动上报,Zabbix server只需要被动接收数据,对server端几乎没有性能压力。从可靠性的角度讲,orabbix是可替代的独立进程,重启、调整配置都不会影响Zabbix本体,运维心态上要稳很多。
2. orabbix 1.2.3的运行架构:它其实是个“翻译官”
用orabbix之前,我建议你先理解它的数据流,不然出了问题你会不知道往哪儿查。它的角色相当于一个翻译官:Oracle只听得懂SQL,Zabbix只认识监控项和值,orabbix把Zabbix要的指标翻译成SQL,再到Oracle里查,最后把结果翻译回Zabbix的监控项值。
2.1 JDBC直连Oracle,数据走Zabbix trapper通道
orabbix的底层连接方式是JDBC。它启动后会读config.props配置文件,里面定义了要监控哪些数据库实例、连接字符串是什么、Zabbix服务器的地址是哪里。对每个数据库实例,orabbix会按照配置的轮询周期,定时执行一组查询。
这些查询结果被分装成一个一个的监控键值对,然后通过Zabbix的trapper协议推送到Zabbix server的10051端口。注意,这里不是Zabbix agent主动拉取,而是orabbix以“主动上报”的方式把数据送到server端,所以Zabbix server不需要通过agent去反向连orabbix。这对网络策略比较友好的环境来说是个优势——你只需要让orabbix所在机器能访问Zabbix server的10051端口就行,不用开放额外的入方向端口。
2.2 一次完整的数据采集链路
我举个例子,假设orabbix要监控某个Oracle实例的当前会话数。整个链路是这样的:
- orabbix根据config.props里配置的连接串,通过JDBC DriverManager创建一个到Oracle实例的连接;
- 执行类似
select count(*) from v$session的查询语句; - 拿到结果后,orabbix内部缓存该值,并为这个指标生成一个和Zabbix模板里完全一致的key,比如
oracle.session_count[{#ORACLE_NAME}]; - orabbix通过socket连接Zabbix server的10051端口,按照trapper协议发送这个监控键和值;
- Zabbix server后续对该key执行trapper类型的item更新,存进数据库。
这套设计里最值得留意的细节是key的命名。orabbix推送的每一个值都对应模板里定义好的item key,如果你的模板没有正确导入,或者item key变了,数据就会显示“Not supported”或没有数据。所以模板导入这一步并不是随便点一下就完事,它决定了item key和orabbix上报的key能不能对上。
3. 部署前的准备工作:JDK、ojdbc和Oracle监控账号
很多人在orabbix上翻车,不是程序本身问题,而是部署前的前置条件没准备好。orabbix本身是一个Java程序,对运行环境有明确要求,逐个说清楚。
3.1 JDK与驱动的版本匹配
orabbix 1.2.3这个版本推出的年代比较早,构建时用的JDK版本不高,但我实测在JDK 8上运行非常稳定,建议直接装JDK 8,不要想着用JDK 11或17挑战兼容性。某些高版本JDK移除了老加密算法,或者模块化之后缺少Java EE相关组件,运行orabbix可能直接报ClassNotFound,完全没必要在这个环节浪费时间。
Oracle JDBC驱动方面,我用的是ojdbc8.jar(一般从Oracle官方JDBC下载页面或者数据库安装目录的jdbc/lib下能找到)。注意要选择和你数据库版本兼容的驱动,如果你的Oracle实例是11g,ojdbc8也能连;如果是Oracle 19c,建议用ojdbc8对应版本。
还要提醒一句:驱动版本不一致时,报错信息往往不是“版本不支持”,而是诡异的空指针、“ORA-01017 invalid username/password”或者连接超时。排查半天才发现是驱动和数据库版本不匹配,这是最常见的第一坑。
3.2 在Oracle端创建最小化权限监控账号
orabbix为了拿到数据库指标,需要登录Oracle查询动态性能视图。建议不要用sys或system这种超级账号,而是单独建一个监控账号,只授必要权限。我一般是这样做的:
CREATE USER ORA_MONITOR IDENTIFIED BY "你的强密码"; GRANT CONNECT, SELECT_CATALOG_ROLE TO ORA_MONITOR; GRANT SELECT ON sys.v_$instance TO ORA_MONITOR; GRANT SELECT ON sys.v_$database TO ORA_MONITOR; GRANT SELECT ON sys.v_$tablespace TO ORA_MONITOR; GRANT SELECT ON sys.v_$datafile TO ORA_MONITOR; GRANT SELECT ON sys.v_$tempfile TO ORA_MONITOR; GRANT SELECT ON sys.v_$session TO ORA_MONITOR; GRANT SELECT ON sys.v_$process TO ORA_MONITOR; GRANT SELECT ON sys.v_$sysstat TO ORA_MONITOR; GRANT SELECT ON sys.v_$statname TO ORA_MONITOR; GRANT SELECT ON sys.v_$log TO ORA_MONITOR; GRANT SELECT ON sys.v_$archived_log TO ORA_MONITOR; GRANT SELECT ON sys.v_$pgastat TO ORA_MONITOR; GRANT SELECT ON sys.v_$parameter TO ORA_MONITOR; GRANT SELECT ON sys.dba_data_files TO ORA_MONITOR; GRANT SELECT ON sys.dba_free_space TO ORA_MONITOR; GRANT SELECT ON sys.dba_temp_files TO ORA_MONITOR;这段SQL我根据orabbix默认查询列表整理出来的,基本覆盖了它需要的所有视图。授权之后,一定要先手动验证一下登录是否正常:
sqlplus ORA_MONITOR/'密码'@//10.0.0.10:1521/ORCLPDB能正常登录并执行select count(*) from v$session;,再往下走。这一步花不了两分钟,但能提前排除掉80%左右的登录故障。
3.3 一个容易忽略的网络检查
orabbix所在主机需要能访问Oracle的1521端口,同时还要能访问Zabbix server的10051端口。很多人在配置后看不到数据,第一反应是orabbix问题,最后才发现是从orabbix主机到Zabbix server的10051端口被防火墙拦了。
我习惯在部署前先用命令验证一下:
# 测试到Oracle的连通性 telnet 10.0.0.10 1521 # 测试到Zabbix server的10051端口 telnet 10.0.1.20 10051注意,如果Zabbix server的10051端口对外限制得很严,你需要确认orabbix所在机器的IP是否在白名单里。另外,orabbix和Zabbix server之间的通信可能还会被某些中间设备干扰,如果发现trapper收到数据但前端一直没更新,抓包看10051端口是最直接的排查方式。
4. 安装配置全记录:从解压到模板导入
前置条件就绪后,就可以开始安装了。我用的环境是一台CentOS 7.6服务器,orabbix就部署在和Zabbix server分开的独立机器上(也可以和Zabbix server同机部署,但独立机器更稳)。
4.1 文件布局与启动方式
orabbix 1.2.3发布包通常是一个zip压缩包,解压后目录结构大致如下:
orabbix/ ├── conf/ │ └── config.props ├── lib/ │ ├── ojdbc8.jar │ └── log4j-1.2.16.jar ├── log/ ├── orabbix.sh └── orabbix-1.2.3.jar把对应版本的ojdbc8.jar复制进lib目录后,最核心的就是修改conf/config.props。修改前先备份原文件,这是经验,免得改出问题连保底的配置都没了。
4.2 config.props逐段配置说明
config.props是orabbix的唯一配置文件,里面标注很清楚,我先给出一份精简后的实际配置:
# Zabbix Server列表,多个用逗号分隔 ZabbixServerList=ZabbixServer1 ZabbixServer1.Address=10.0.1.20 ZabbixServer1.Port=10051 # orabbix代理自身标识 OrabbixDaemon.Address=10.0.1.30 OrabbixDaemon.Port=10052 # 日志级别 OrabbixDaemon.LogLevel=info # 轮询周期(秒) OrabbixDaemon.PollInterval=60 # 实例发现开关 InstanceDiscovery=true # Oracle JDBC连接池大小 OrabbixDaemon.MaxActive=10 # 数据库实例列表 DatabaseList=ORCL,ORCLPDB # 每个实例的连接配置 ORCL.Address=10.0.0.10 ORCL.Port=1521 ORCL.User=ORA_MONITOR ORCL.Password=你的强密码 ORCL.ServiceName=ORCL ORCL.MaxActive=5 ORCL.MaxWait=1000 ORCL.MaxIdle=1 ORCLPDB.Address=10.0.0.10 ORCLPDB.Port=1521 ORCLPDB.User=ORA_MONITOR ORCLPDB.Password=你的强密码 ORCLPDB.ServiceName=ORCLPDB ORCLPDB.MaxActive=5 ORCLPDB.MaxWait=1000 ORCLPDB.MaxIdle=1几个关键参数重点说明:
ZabbixServerList和ZabbixServer1.Address是orabbix上报数据的去向。如果Zabbix server和agent用的都是同一个IP,这里就填server地址,端口固定10051。OrabbixDaemon.Address填本机IP,Port随便指定一个未占用的端口(实际上这更多是身份标识)。OrabbixDaemon.PollInterval=60表示每60秒轮询一次数据库。不要设置得太短,30秒以上已经能满足绝大多数监控场景,太短反而给数据库增加负担。DatabaseList是orabbix要监控的Oracle实例列表,多个实例用逗号分隔。实例可以指向同一个Oracle,也可以指向多个不同的Oracle。- 每个实例的
ServiceName要填写Oracle监听的service name,不是SID,很多人这里填错导致连不上。
4.3 Zabbix前端导入模板并关联主机
orabbix发布包中会自带一个模板文件,常见名称是Oracle_zbx_templates.xml。这个模板需要在Zabbix前端导入。
导入路径:配置 → 模板 → 导入,选择文件后导入。导入后你会看到一个名为Template_Oracle的模板,里面包含几十个监控项,还有若干LLD规则,用来发现表空间。
接下来到配置 → 主机,找到你之前创建好的Oracle主机(关联了Zabbix agent的那种),在模板栏里添加Template_Oracle。注意:orabbix监控并不依赖agent去采集Oracle数据,但主机上还是要先有agent在运行,Zabbix才会认为这个主机是“已监控”状态。
模板关联后,你会在主机的监控项列表里看到大量以oracle.开头的key。这些key的数据来源就是orabbix通过trapper上报的。比如:
oracle.buffer_cache_hit_ratiooracle.session_countoracle.tablespace.usedoracle.archive_log_generated
看到这些key之后,再把模板里的宏填一下。orabbix模板里通常会定义{$ORACLE_USER}、{$ORACLE_PASSWORD}这类宏,你在导入后需要去主机宏或者模板宏里填入实际连接Oracle的账号密码。不同版本模板的宏名略有差异,你导入后看一眼模板里的监控项宏引用就能确定。
4.4 启动验证:看进程、看日志、看最新数据
启动orabbix很简单,执行:
sh orabbix.sh start启动后确认进程存在:
ps -ef | grep orabbixorabbix的日志在log目录下,默认生成orabbix.log和orabbix_error.log。启动成功的情况下,日志中应该能看到connected to database ORCL之类的信息;如果报连接失败,优先排查账号密码和ojdbc驱动问题。
数据是否成功进入Zabbix,可以这样看:登录Zabbix前端,进入该主机的最新数据页面,筛选oracle.的监控项。如果能看到数据并且最近时间为当前时间,说明整条链路已经通了。如果最新数据时间一直停在导入模板前的状态,按下面章节的排查思路逐步查。
5. 高频排错链路:这些坑我基本都踩过
orabbix部署起来不难,但在真实环境里,总有一些问题不是“装好就能跑”的。我整理了几个实际场景中最高频的坑,每个都给出我自己的排查路径。
5.1 ORA-01017/ORA-28001:账号和密码策略的坑
先说登录失败的两个经典报错。ORA-01017 invalid username/password通常不是密码真错了,而是以下几种情况之一:
- ojdbc驱动版本和数据库版本不兼容,导致认证异常,这种情况可以换一个更低版本的ojdbc驱动试试,比如ojdbc6;
- Oracle密码里带了特殊字符,在config.props里没有正确转义或者被解析成配置分隔符;
- 数据库是CDB+PDB架构,你连接的用户和ServiceName不在同一个PDB里,虽然端口和IP都对,但认证就是失败。
ORA-28001 the password has expired是Oracle密码过期策略导致。监控账号一般用得很频繁,但也可能因为数据库密码策略严格而到期。处理方式是先过期重置,并确认账号对应profile的过期时限:
ALTER PROFILE DEFAULT LIMIT PASSWORD_LIFE_TIME UNLIMITED; ALTER USER ORA_MONITOR IDENTIFIED BY "新密码" ACCOUNT UNLOCK;密码改完后,同步修改config.props,并重启orabbix。
5.2 日志里反复出现连接池超时
如果你发现日志里有大量类似pool-3-thread-1 ... wait timeout或者Cannot get connection的报错,基本可以判断是JDBC连接池参数设得太小,或者某条查询语句执行时间太长把连接占满了。
我遇到过一次实际案例:Oracle数据库负载很高时,orabbix默认的监控SQL里有一条查询v$archived_log特别慢,执行要十几秒。orabbix内部一个实例默认连接池上限只有5,结果几条慢查询同时执行,后面的查询全部排队超时。
排查思路是先把日志级别调成debug,找出具体是哪条SQL执行慢,然后到Oracle端用工具分析。如果你的orabbix监控库很多、数据量大,适当调大实例的MaxActive和MaxWait:
ORCL.MaxActive=20 ORCL.MaxWait=3000同时,把OrabbixDaemon.PollInterval拉大到120秒或更长,也能显著降低连接池压力。不要只想着一味增加连接数,先搞清楚是查询慢还是连接不够,再对症下药。
5.3 LLD发现不出表空间
orabbix的表空间自动发现是通过LLD规则实现的。正常情况下,导入模板后,等待一到两个发现周期(和轮询周期有关),配置 → 主机 → 监控项 → 自动发现的规则里,应该能看到表空间列表。
发现不出来的常见原因有两个:
第一,模板里的宏没有正确填写。LLD规则的过滤条件和监控项SQL中会引用{$ORACLE_USER}、{$ORACLE_PASSWORD},如果宏为空,发现查询执行失败,Zabbix前端就会一直显示“Discovery”为空。
第二,数据库账号缺少对相关字典表的查询权限。表空间发现要查询dba_tablespace、dba_data_files这些字典表,如果你只授了基础视图权限,发现可能一半成功一半失败。检查一下有没有那几张dba_*表的权限:
GRANT SELECT ON sys.dba_tablespaces TO ORA_MONITOR; GRANT SELECT ON sys.dba_data_files TO ORA_MONITOR; GRANT SELECT ON sys.dba_temp_files TO ORA_MONITOR;补权限后不需要重启orabbix,等下一个发现周期即可。
5.4 中文乱码与本地字符集的关系
这是比较冷门但很烦人的问题。orabbix采集的监控项里如果包含中文信息(比如表空间名称、文件路径),在Zabbix前端显示为乱码,但数据本身是正常的。
原因在于orabbix进程读取Oracle返回的中文字符时,JVM默认字符集和Oracle客户端字符集、Zabbix前端字符集之间没对齐。解决思路是让orabbix启动时显式指定UTF-8编码。
修改orabbix.sh,在启动命令中加上JVM参数:
JAVA_OPTS="-Dfile.encoding=UTF-8 -Duser.language=zh -Duser.country=CN"同时确保config.props本身保存为UTF-8格式,不要用Windows记事本的ANSI编码保存,否则配置文件里的中文注释和密码都可能变成乱码,进而引发密码错误或路径错误。这个问题我曾经排查了一个下午,最后发现只是编码问题,教训深刻。
5.5 采集间隔和IO压力怎么权衡
orabbix的好处是连接复用,但如果轮询间隔设置不当,还是会增加数据库负担。尤其那些本身业务压力就很大的Oracle实例,orabbix每30秒甚至更短周期轮询一次,大量查询动态性能视图,会对数据库产生新的开销。
我的经验值是:
- 常规监控:轮询周期60秒,连接池MaxActive 5~10;
- 高负载/核心库:轮询周期120秒,连接池MaxActive 3~5;
- 报表型/准实时指标:轮询周期30秒,连接池MaxActive 10,但只保留少量关键监控项。
这个配置需要观察orabbix日志和Oracle的AWR报告,看新增的监控会话是否占用了明显资源。如果AWR中出现orabbix连接相关的SQL消耗较高,就把轮询周期再放大,通常没有必要追求秒级数据。
6. 监控数据拿到手之后:从“能看到”到“能报警”
orabbix把数据采集上来,其实只完成了第一步。如果只是让监控项在页面上有个数字,那和没做监控区别不大。真正有价值的是基于这些数据构建报警策略。
6.1 关键监控项怎么挑
orabbix模板里监控项很多,但每个都设置报警是没有意义的,不仅管理成本高,还会因为误报让团队产生“报警疲劳”。
我自己的习惯是聚焦几类:
- 可用性类:实例是否存活、监听是否正常。对应orabbix的
oracle.alive、oracle.instance_status,阈值设为非正常状态就告警; - 容量类:表空间使用率、归档日志目录剩余空间。表空间使用率建议按90%/95%分两级告警,高水位线再结合日常增长情况调整;
- 性能类:Buffer Cache命中率、共享池命中率、会话数、活跃会话数。命中率不是越低越要告警,要结合基线,一般来说命中率低于90%持续10分钟以上值得关注;
- 异常类:会话数突然飙高、归档日志短时间内大量生成。这类往往关联应用或老问题,值得单独设置触发器。
我在上线后的实际操作中,通常先把这些指标的历史数据跑一周,再按照历史均值加两倍标准差的方式设定动态阈值,比拍脑袋写死90%要可靠得多。
6.2 触发器设计的实际建议
触发器表达式建议用“持续N次才告警”的方式。比如表空间使用率:
last(/Template_Oracle/tablespace.pct.used[{#TABLESPACE}]) > 90单次就告警容易误报,尤其是数据文件自动扩展的场景下,使用率可能瞬时波动。更稳妥的是:
min(/Template_Oracle/tablespace.pct.used[{#TABLESPACE}],5m) > 95表示5分钟窗口内的最小值都超过95%才触发,既避免瞬时波动,又能及时发现问题。
会话数的告警则适合用“速率变化”的思路。比如一个库平时会话稳定在200左右,某天突然涨到600,这种变化往往比具体数值更值得关注。先用触发器计算窗口内平均会话数,再和上一周期对比:
avg(/Template_Oracle/oracle.session_count,10m) - avg(/Template_Oracle/oracle.session_count,1h) > 200这种相对变化类触发器,我在实际使用中比绝对阈值更能提前暴露异常。
6.3 给监控项加趋势留存和容量观察
orabbix上报的数据默认会按照模板中定义的趋势存储策略存历史。我一般会把表空间使用率的历史保留周期设为90天,归档日志生成量保留30天,其他常规指标保留7天就够了。存储周期太长会增加Zabbix数据库磁盘消耗,太短又没法做容量趋势分析。
有了历史数据后,可以通过Zabbix内置趋势图来看表空间增长斜率。比如某个表空间每周增长近10%,按照剩余可用空间估算,大约在一个月后会触达90%阈值,这就是事前规划扩容的窗口。
另外提一个很实用的做法:把orabbix采集到的Oracle实例状态和业务系统的主机监控合并在同一个Dashboard上。Zabbix的聚合图形可以同时展示主机CPU、内存、磁盘和Oracle的会话数、等待事件、表空间使用率。当业务反馈变慢时,先看聚合面板,往往几分钟内能定位到是实例层面的问题还是主机资源问题,排查效率提升非常明显。
我自己在实际使用中还有一个习惯,就是每隔几个月会去检查一次orabbix的版本和社区更新。orabbix 1.2.3本身已经很稳定,功能上也没有太多必要追新,但博主和社区还是会偶尔修正一些细节。把监控项、触发器和Dashboard整理成一套可复用的模板,下次再有新的Oracle实例接入时,配置一个新数据库列表、导入模板,十分钟就能完成接入。这套方式支撑了我这边好几套Oracle环境的日常巡检,比手工写SQL查询省下的时间可不是一点半点。