消息推送是一种常见的监控手段,使用短信成本太高,低成本的消息推送手段是方案首选。
钉钉的群机器人可实现日常的监控管理,普通群的消息推送官方也支持。可以快速组建各种系统状态监控群,让相关负责人入群接收消息即可。
钉钉消息推送的集成方案,设置简单操作方便,可以快速部署。最终效果如下图所示:
群机器人的设置就不再赘述,基本上设置好token,即可测试消息推送,官方文档写得非常清楚。
钉钉消息推送文档地址为:
https://open.dingtalk.com/document/robots/custom-robot-access
下面介绍使用 python 查询 Oracle 数据字典推送消息的细节。文本消息都有字数限制,太长的消息会被截短。我测试的结果文本字数至少支持500字,比短信长多了。消息推送是在Linux系统上运行,我列一下需要安装的依赖。
$ pip install cx-Oracle
$ pip list
Package Version
----------- -------
cx-Oracle 8.3.0
使用 python 连接 Oracle,除了需要安装 cx-Oracle 库,还需要安装 Oracle instantclient。根据连接的数据库版本在Oracle官网下载相应版本的 oracle client,这里下载的是 11.2.0.4 的客户端。
Oracle client 下载地址为:
# instantclient-basic-linux.x64-11.2.0.4.0.zip
https://download.oracle.com/otn/linux/instantclient/11204/instantclient-basic-linux.x64-11.2.0.4.0.zip
# Linux download page 其它版本下载地址
https://www.oracle.com/database/technologies/instant-client/linux-x86-64-downloads.html
instantclient 的安装过程官方也有介绍,我在这里简单把命令列一下:
# 官方文档
# https://docs.oracle.com/en/database/oracle/oracle-database/21/lacli/install-instant-client-using-zip.html
mkdir -p /opt/oracle
cd /opt/oracle/
# copy instatclient*.zip to current folder
unzip instantclient-basic-linux.x64-11.2.0.4.0.zip
echo /opt/oracle/instantclient_11_2 > /etc/ld.so.conf.d/oracle-instantclient.conf
ldconfig
vim ~/.bashrc
export LD_LIBERARY_PATH=/opt/oracle/instantclient_11_2:$LD_LIBERARY_PATH
export PATH=/opt/oracle/instantclient_11_2:$PATH
当 oracle client 安装完毕就可以测试能否正常连接数据库了。连接数据库的测试脚本为:
#! python3
import cx_Oracle
connection = cx_Oracle.connect(user="user", password="password",
dsn="192.168.1.1/testdb")
cursor = connection.cursor()
cursor.execute("""
select sysdate from dual""",
)
for i in cursor:
print("Values: ", i)
当数据库连接正常后就可以插入正式的表空间监控脚本了。表空间的空间使用率有两种统计口径,一种是按当前占用率来算,另一种是按扩容可达到的最大空间算。一般在数据文件设置为可扩容后,单文件最大可扩至32G。数据文件只要可以自动扩容,就不会出现SQL插入失败的风险。所以紧迫程度应该按第二种统计口径来计算。
因为对表空间使用率做了排序,所以只用取占用最多的进行告警即可。推送消息只是为了在特殊情况进行提醒,当表空间使用率达到阈值后dba自然会进行全面的统计,所以只用给出一条告警数据即可。
Oracle 推荐的表空间阈值是 85%,当超出默认值就会在 dba_outstanding_alerts 数据字典中告警。而表空间的阈值的设置可以在 dba_tablespace_thresholds 数据字典中查询。
#! python3
import os
import sys
import cx_Oracle
connection = cx_Oracle.connect(user="usertest", password="passtest",
dsn="192.168.1.1/testdb")
cursor = connection.cursor()
cursor.execute("""
select t.* from (
select UPPER(F.TABLESPACE_NAME) as "表空间名称",
ROUND(D.AVAILB_BYTES, 2) as "表空间大小(G)",
ROUND(D.MAX_BYTES, 2) as "最终表空间大小(G)",
ROUND((D.AVAILB_BYTES - F.USED_BYTES), 2) as "已使用空间(G)",
TO_CHAR(ROUND((D.AVAILB_BYTES - F.USED_BYTES) / D.AVAILB_BYTES * 100,
2),
'999.99') as "使用比",
TO_CHAR(ROUND((D.AVAILB_BYTES - F.USED_BYTES) / D.MAX_BYTES * 100, 2),
'999.99') as "最终使用比",
ROUND(F.USED_BYTES, 6) as "空闲空间(G)",
ROUND(D.MAX_BYTES - D.AVAILB_BYTES, 2) as "最终空闲可用空间(G)"
from (select TABLESPACE_NAME,
ROUND(sum(BYTES) / (1024 * 1024 * 1024), 6) USED_BYTES,
ROUND(max(BYTES) / (1024 * 1024 * 1024), 6) MAX_BYTES
from SYS.DBA_FREE_SPACE
group by TABLESPACE_NAME) F,
(select DD.TABLESPACE_NAME,
ROUND(sum(DD.BYTES) / (1024 * 1024 * 1024), 6) AVAILB_BYTES,
ROUND(sum(DECODE(DD.MAXBYTES, 0, DD.BYTES, DD.MAXBYTES)) /
(1024 * 1024 * 1024),
6) MAX_BYTES
from SYS.DBA_DATA_FILES DD
group by DD.TABLESPACE_NAME) D
where D.TABLESPACE_NAME = F.TABLESPACE_NAME
order by 6 desc
) t where rownum = 1
""",
)
r = []
for i in cursor:
r.append(i)
if len(r) == 0:
sys.exit()
ts = r[0][0]
usage = r[0][5]
rate = float(usage.strip())
if rate