引言

为了给客户演示对mysql表结构的监控,在搜了很久之后发现不得不自己写一个脚本了。percona这么牛B的公司竟然没有提供一个这方面的工具,看来客户的要求有点花儿不实啊。。。这个问题一共花费了我两天时间去解决(个人shell脚本一般,能力也一般),所以总结一下。

实现设想

过程中一共有三种想法:
1. 由于mysql的informarion_schema.columns这个表存储这所有表的表结构,因此第一个设想是想对information_schema.columns这个表不停的扫描,保留老数据,将本次扫描的数据与老数据进行比较,如果发现有所不同则肯定发生了 alter table的操作,即表结构发生了变化
2. mysql的表都存在/data目录下,表结构都有一个单独的文件***.frm文件进行存储(innodb表需要设置innodb_file_per_table),所以第二个想法是监控/data目录的frm文件带大小,如果大小发生变化则认为是发生了表结构的变化,这种方法实现起来比第一种简单,但是准确性肯定不是很好,很有可能表结构更改了为frm文件的大小没变。

方法一实现:

一共需要三个临时文件,一个用于存储当前表结构信息,一个用于存储上一次检查的表结构信息,一个用于存储表结构变化的表名。
脚本名为check_mysql_table,代码如下
#!/bin/sh# ########################################################################
# This program is used to check whether mysqld run on this machine
# ######################################################################### ########################################################################
# Redirect STDERR to STDOUT; Nagios doesn't handle STDERR.
# ########################################################################
exec 2>&1# ########################################################################
# Set up constants, etc.
# ########################################################################
STATE_OK=0
STATE_WARNING=1
STATE_CRITICAL=2
STATE_UNKNOWN=3
STATE_DEPENDENT=4TMPFILENEW="/tmp/table_frm.new"
TMPFILEOLD="/tmp/table_frm.old"
TMPFILERESULT="/tmp/alter_table"# ########################################################################
# Run the program.
# ########################################################################
main() {# Get optionsfor a; docase "${a}" in-c)              shift; OPT_CRIT="${1}"; shift; ;;--defaults-file) shift; OPT_DEFT="${1}"; shift; ;;-g)              shift; OPT_UNIX_GROUP="${1}"; shift; ;;-H)              shift; OPT_HOST="${1}"; shift; ;;-l)              shift; OPT_USER="${1}"; shift; ;;-L)              shift; OPT_LOPA="${1}"; shift; ;;-p)              shift; OPT_PASS="${1}"; shift; ;;-P)              shift; OPT_PORT="${1}"; shift; ;;-S)              shift; OPT_SOCK="${1}"; shift; ;;-u)              shift; OPT_UNIX_USER="${1}"; shift; ;;-w)              shift; OPT_WARN="${1}"; shift; ;;-e)              shift; OPT_EMAIL="${1}"; shift; ;;-d)              shift; OPT_DATABASE="${1}"; shift; ;;--version)       grep -A2 '^=head1 VERSION' "$0" | tail -n1; exit 0 ;;--help)          perl -00 -ne 'm/^  Usage:/ && print' "$0"; exit 0 ;;-*)              echo "Unknown option ${o}.  Try --help."; exit 1; ;;esacdoneOPT_UNIX_GROUP="${OPT_UNIX_GROUP:-mysql}"OPT_UNIX_USER="${OPT_UNIX_USER:-mysql}"if [ -e '/etc/smartmonitor/mysql.cnf' ]; thenOPT_DEFT="${OPT_DEFT:-/etc/smartmonitor/mysql.cnf}"fiif is_not_sourced; thenif [ -n "$1" ]; thenecho "WARN spurious command-line options: $@"exit 1fifiif [ "${OPT_DEFT}${OPT_HOST}${OPT_USER}${OPT_PASS}${OPT_PORT}${OPT_SOCK}" ]; thenif [ ! "${OPT_DATABASE}" ]thenOPT_DATABASE=" not in ('mysql','information_schema','performance_schema','test')"TABLE_DATA=`mysql_exec  "SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema not in ('mysql','information_schema','test','performance_schema')"`elseOPT_DATABASE="='"${OPT_DATABASE}"'"TABLE_DATA=`mysql_exec "SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema"${OPT_DATABASE} `fifiif [ ! "${TABLE_DATA}" ]thenecho "WARNING no tables in the databases"exit 1fiecho $TABLE_DATA|awk '{gsub("def","\ndef");print}'>$TMPFILENEWsed -i '1d' $TMPFILENEWif [ -f "$TMPFILEOLD" ]thencat $TMPFILEOLD|while read Linedogrep -q """${Line}""" $TMPFILENEWif [ $? -ne 0 ]thenAlter_table=`echo $Line|awk {'print $2"."$3"."$4'}`echo $TABLE_NAMES |grep -q "$Alter_table"if [ $? -ne 0 ]thenTABLE_NAMES=${TABLE_NAMES}" "${Alter_table}echo $TABLE_NAMES>$TMPFILERESULTfifidoneficp $TMPFILENEW $TMPFILEOLDif [ ! -f $TMPFILERESULT  ]thenNOTE="OK,no table alter"elseTABLE_NAMES=`cat $TMPFILERESULT`NOTE="WARNING, alter table:"${TABLE_NAMES}if [ "${OPT_EMAIL}" ]thenecho $NOTE | /bin/mail -s "SERVICE NOTIFITATION:ALTER TABLE" $OPT_EMAILfifirm -f $TMPFILERESULTecho $NOTE
}# ########################################################################
# Execute a SmartSQL command.
# ########################################################################
mysql_exec() {mysql ${OPT_DEFT:+--defaults-file="${OPT_DEFT}"} ${OPT_HOST:+-h"${OPT_HOST}"} ${OPT_USER:+-u"${OPT_USER}"} \${OPT_PASS:+-p"${OPT_PASS}"} ${OPT_SOCK:+-S"${OPT_SOCK}"} ${OPT_PORT:+-P"${OPT_PORT}"} \${OPT_LOPA:+--login-path="${OPT_LOPA}"} -ss -e "$1"
}# ########################################################################
# Determine whether this program is being executed directly, or sourced/included
# from another file.
# ########################################################################
is_not_sourced() {[ "${0##*/}" = "check_mysql_table" ] || [ "${0##*/}" = "bash" -a "$_" = "$0" ]
}# ########################################################################
# Execute the program if it was not included from another file.
# This makes it possible to include without executing, and thus test.
# ########################################################################
if is_not_sourced; thenOUTPUT=$(main "$@")EXITSTATUS=$STATE_UNKNOWNcase "${OUTPUT}" inUNK*)  EXITSTATUS=$STATE_UNKNOWN;  ;;OK*)   EXITSTATUS=$STATE_OK;       ;;WARN*) EXITSTATUS=$STATE_WARNING;  ;;CRIT*) EXITSTATUS=$STATE_CRITICAL; ;;esacecho "${OUTPUT}"exit $EXITSTATUS
fi# ############################################################################
# Documentation
# ############################################################################
: <<'DOCUMENTATION'
=pod=head1 NAMEcheck-mysql-table - Alert when MySQL table alter happen.=head1 SYNOPSISUsage: check-mysql-table [OPTIONS]Options:-c CRIT         ignore now--defaults-file FILE Only read mysql options from the given file.Defaults to /etc/nagios/mysql.cnf if it exists.-g GROUP        MySQL groupusername-H HOST         MySQL hostname.-l USER         MySQL username.-L LOGIN-PATH   Use login-path to access MySQL (with MySQL client 5.6).-p PASS         MySQL password.-P PORT         MySQL port.-S SOCKET       MySQL socket file.-w WARN         When table alter happen return Warning.default value-e EMAIL        Once Alter send a email to this address-d DATABASE     The tables of this databases will be monitored.Defaults to all databases except mysql information_scheme test and performance_schema--help          Print help and exit.--version       Print version and exit.Options must be given as --option value, not --option=value or -Ovalue.Use perldoc to read embedded documentation with more details.=backExamples:# /usr/local/nagios/libexec/check-mysql-table -H 127.0.0.1 -P 3306 -l root -d weibo OK no alter table=head1 PRIVILEGESThis plugin executes the following commands against MySQL:=over=item *C<SELECT * FROM  INFORMATION_SCHMEMA.COLUMNS;>=backThis plugin executes no UNIX commands that may need special privileges. =head1 VERSIONGreatOpenSource Monitoring Plugins check_mysql_table 1.0=cutcheck_mysql_table - Return WARNING if table alter happenDOCUMENTATION

程序的框架参考了percona的mysql监控脚本格式。

虽然代码较多,但是思想很简单。

遇到的问题

1 临时文件路径问题,一开始程序中的临时文件用的是相对路径,但是nagios运行时,会将所有的临时文件都在temp_path=/tmp ,这个配置选项指出了临时文件的位置。
2.管道问题,在处理文件时候,也就是下面这段代码
  cat $TMPFILEOLD|while read Linedogrep -q """${Line}""" $TMPFILENEWif [ $? -ne 0 ]thenAlter_table=`echo $Line|awk {'print $2"."$3"."$4'}`echo $TABLE_NAMES |grep -q "$Alter_table"if [ $? -ne 0 ]thenTABLE_NAMES=${TABLE_NAMES}" "${Alter_table}echo $TABLE_NAMES>$TMPFILERESULTfifidone

这里的变量TABLE_NAME保存着表结构发生变化的表名字,但是由于是在一个管道中进行的,这个变量的值传不出来,出了这个while循环后就不能用了,所以把这个变量的值写入了一个临时文件中。

方法二的实现

思想简单,代码如下
#!/bin/sh# ########################################################################
# This program is used to check whether mysqld run on this machine
# ######################################################################### ########################################################################
# Redirect STDERR to STDOUT; Nagios doesn't handle STDERR.
# ########################################################################
exec 2>&1# ########################################################################
# Set up constants, etc.
# ########################################################################
STATE_OK=0
STATE_WARNING=1
STATE_CRITICAL=2
STATE_UNKNOWN=3
STATE_DEPENDENT=4TMPFILE="/tmp/table_frm_size"# ########################################################################
# Run the program.
# ########################################################################
main() {# Get optionsfor o; docase "${o}" in-c)              shift; OPT_CRIT="${1}"; shift; ;;--defaults-file) shift; OPT_DEFT="${1}"; shift; ;;-g)              shift; OPT_UNIX_GROUP="${1}"; shift; ;;-H)              shift; OPT_HOST="${1}"; shift; ;;-l)              shift; OPT_USER="${1}"; shift; ;;-L)              shift; OPT_LOPA="${1}"; shift; ;;-p)              shift; OPT_PASS="${1}"; shift; ;;-P)              shift; OPT_PORT="${1}"; shift; ;;-S)              shift; OPT_SOCK="${1}"; shift; ;;-u)              shift; OPT_UNIX_USER="${1}"; shift; ;;-w)              shift; OPT_WARN="${1}"; shift; ;;-e)              shift; OPT_EMAIL="${1}"; shift; ;;-d)              shift; OPT_DATABASE="${1}"; shift; ;;--version)       grep -A2 '^=head1 VERSION' "$0" | tail -n1; exit 0 ;;--help)          perl -00 -ne 'm/^  Usage:/ && print' "$0"; exit 0 ;;-*)              echo "Unknown option ${o}.  Try --help."; exit 1; ;;esacdoneOPT_UNIX_GROUP="${OPT_UNIX_GROUP:-smartsql}"OPT_UNIX_USER="${OPT_UNIX_USER:-smartsql}"OPT_EMAIL="${OPT_EMAIL:-}"if [ -e '/etc/smartmonitor/smartsql.cnf' ]; thenOPT_DEFT="${OPT_DEFT:-/etc/smartmonitor/smartsql.cnf}"fiif is_not_sourced; thenif [ -n "$1" ]; thenecho "WARN spurious command-line options: $@"exit 1fifi#NOTE="UNK could not determine the datadir location."if [ ! "${OPT_DATABASE}" ]thenecho "CRITICAL,no database use"exit 2fiDATADIR=NOTE="UNKOWN can not get the data dir "TABLENAMES=""if [ "${OPT_DEFT}${OPT_HOST}${OPT_USER}${OPT_PASS}${OPT_PORT}${OPT_SOCK}" ]; thenDATADIR=`smartsql_exec "SELECT IF(@@datadir LIKE '/%', @@datadir, CONCAT(@@basedir, @@datadir))" `fiif [ ! $? ]thenecho "UNKOWN error"exit 3  fiFindDir=${DATADIR}${OPT_DATABASE}"/" if [ ! -f "$TMPFILE" ]thentouch $TMPFILEfor File in `find $FindDir -name "*.frm"`dotmp=${File##*/}filename=${tmp%.*}set `ls -il $File`echo ${filename}":"$6>>$TMPFILEdoneelsefor File in `find $FindDir -name "*.frm"`dotmp=${File##*/}filename=${tmp%.*}set `ls -il $File`size=$6searchstr=${filename}result=`grep  "$searchstr" $TMPFILE`if [ $? -eq 0 ]thenoldsize=${result##*:}if [ $size -ne $oldsize ]thenTABLE_NAMES=${TABLE_NAMES}" "${filename}fifidonefiif [ x"$TABLE_NAMES" = x ]thenNOTE="OK,no table alter"elseNOTE="WARNING, alter table:"${TABLE_NAMES}if [ "${OPT_EMAIL}" ]thenecho $NOTE | /bin/mail -s "SERVICE NOTIFITATION:ALTER TABLE" $OPT_EMAILfirm -rf $TMPFILEtouch $TMPFILEfor File in `find $FindDir -name "*.frm"`dotmp=${File##*/}filename=${tmp%.*}set `ls -il $File`echo ${filename}":"$6>>$TMPFILEdonefiecho $NOTE
}
# ########################################################################
# update $TMPFILE.
# ######################################################################### ########################################################################
# Execute a SmartSQL command.
# ########################################################################
smartsql_exec() {smartsql ${OPT_DEFT:+--defaults-file="${OPT_DEFT}"} ${OPT_HOST:+-h"${OPT_HOST}"} ${OPT_USER:+-u"${OPT_USER}"} \${OPT_PASS:+-p"${OPT_PASS}"} ${OPT_SOCK:+-S"${OPT_SOCK}"} ${OPT_PORT:+-P"${OPT_PORT}"} \${OPT_LOPA:+--login-path="${OPT_LOPA}"} -ss -e "$1"
}# ########################################################################
# A wrapper around pidof, which might not exist. The first argument is the
# command name to match.
# ########################################################################
_pidof() {if ! pidof "${1}" 2>/dev/null; thenps axo pid,ucomm | awk -v comm="${1}" '$2 == comm { print $1 }'fi
}# ########################################################################
# Determine whether this program is being executed directly, or sourced/included
# from another file.
# ########################################################################
is_not_sourced() {[ "${0##*/}" = "check_smartsql_table" ] || [ "${0##*/}" = "bash" -a "$_" = "$0" ]
}# ########################################################################
# Execute the program if it was not included from another file.
# This makes it possible to include without executing, and thus test.
# ########################################################################
if is_not_sourced; thenOUTPUT=$(main "$@")EXITSTATUS=$STATE_UNKNOWNcase "${OUTPUT}" inUNK*)  EXITSTATUS=$STATE_UNKNOWN;  ;;OK*)   EXITSTATUS=$STATE_OK;       ;;WARN*) EXITSTATUS=$STATE_WARNING;  ;;CRIT*) EXITSTATUS=$STATE_CRITICAL; ;;esacecho "${OUTPUT}"exit $EXITSTATUS
fi# ############################################################################
# Documentation
# ############################################################################
: <<'DOCUMENTATION'check_smartsql_table - Return WARNING if table alter happenUsage: check_smartsql_tableDOCUMENTATION

参考

1. http://www.percona.com/blog/2014/02/26/monitor-alter-table-progress-innodb_file_per_table/

nagios监控 mysql 表结构相关推荐

  1. mysql 表空间监控shell_一种通过zabbix监控mysql表空间的方法

    一种通过zabbix监控mysql表空间的方法[ 技术领域: ][0001]本发明涉及计算机自动化运维与监控领域,具体地说是一种通过ZABBIX监控MYSQL表空间的方法.[ 背景技术: ][0002 ...

  2. 修改mysql表结构语句

    昨天在执行碰到几个报错,总提示缺少mysql表结构里的字段什么的,当时有点没头绪不知道从哪里着手,再次记录一下修改表结构的语句,保证下次不会在出现此类问题; mysql 修改表结构语句 ALTER T ...

  3. nagios监控mysql(check_mysql)及内存使用率(check_mem)

    一.监控本地(localhost)内存 1.上传监控脚本 check_mem 到/usr/local/nagios/libexec # chown -R nagios.nagios check_mem ...

  4. nagios监控mysql服务_nagios监控mysql及邮件报警

    1.使用默认监控命令check_http命令+相关的参数来实现,如下: 在command.cfg添加如下关键词监控命令:check_http_word,参数解析:-I指定IP或者主机名,-u指定URL ...

  5. mysql schema 同步_GitHub - naryn/mysql-schema-sync: mysql表结构自动同步工具

    mysql-schema-sync mysql表结构自动同步工具 用于将 线上 数据库结构变化同步到 本地环境! 支持功能: 同步新表 同步字段 变动:新增.修改 同步索引 变动:新增.修改 支持预览 ...

  6. nagios监控mysql主从

    为什么80%的码农都做不了架构师?>>>    nagios监控mysql的主从,我这里介绍两种方法,一种是用nagios自带监控mysql 的插件实现,另一种是自己写脚本,下面是两 ...

  7. nagios监控mysql服务_nagios监控mysql服务

    配置被监控端 1.安装check_mysql插件 nagios 监控 mysql 需要用到 check_mysql 和 check_mysql_query 两个插件. 安装完成 nagios 后,发现 ...

  8. JAVA实现导出mysql表结构到Word详细注解版

    JAVA实现导出mysql表结构到Word详细注解版 转自https://blog.csdn.net/weixin_42041153/article/details/109739073 本文在原文中一 ...

  9. MySQL表结构导出Excel

    MySQL表结构导出Excel 在写设计文档时,需要把MySQL中的表结构按要求导出.MySQL客户端默认的字段不满足需求时,可通过MySQL的information_schema.COLUMNS表, ...

最新文章

  1. php 实现查询百度排名,PHP实现获取百度top50的搜索排行关键字
  2. Java中getMessage()和printStackTrace方法
  3. 冰豹lua驱动设置_通过编写“猜数字”游戏学习 Lua | Linux 中国
  4. arcball原理 旋转视图 关键点总结 及代码
  5. 如何创建一个基于 MSBuild Task 的跨平台的 NuGet 工具包
  6. 网络基础2-2(传输层,端口,详谈UDP)
  7. 常规dll 的接口函数定义+客户端程序接口函数导入
  8. mac 下基于firebreath 开发多浏览器支持的浏览器插件
  9. c/c++排坑(4) -- c/c++中返回局部变量
  10. Q2 Spring Boot自动配置原理(ok)
  11. python 人脸识别活体检测_基于Python+Keras+OpenCV实现实时人脸活体检测
  12. Android 开源项目分类汇总(转)
  13. PACS管理系统源码 PACS源码
  14. 实体关系图 (ERD) 指南
  15. MEncoder的基础用法—6.5. 编码为MPEG格式
  16. 【一起入门NLP】中科院自然语言处理作业一:RNN,DNN,CNN 进行猫狗分类(pytorch入门)【代码+报告】
  17. 从0到1构建一个电商平台 – 开发篇(转)
  18. 源支付3.1版本全开源版+店员监控软件+手机监控APP源码
  19. 2022上半年软考电子证书可以查询拉!
  20. 2020蓝桥杯模拟赛题目解析(上)

热门文章

  1. java eav模式_Magento 2中EAV模型的理解
  2. 仪表板展示|DataEase可视化数据分析工具中的仪表板跳转和联动设置
  3. 使用SPFx一行代码实现Office 365文档库Modern UI中批量签出文档
  4. 复盘 20160629
  5. 2022年线上求职!我建了一个AI算法岗求职群
  6. python turtle画彩虹的代码_python绘制彩虹图
  7. (组合游戏)SG函数与SG定理详解
  8. yarn WEB UI及reserved memory、spark WEB UI
  9. vue中el-table翻页序号连续
  10. 十、【高级篇】RTC--实时时钟