需求
有IBM MQ服务器,在做异地灾备切换时,为保证消息不丢失,需要在切换前检查QM中是否有消息。由于单台服务器上QM比较多,里面的QUEUE更多,若需要肉眼登录查看,甚是低效。因而有此需求。
解决方案
#!/bin/bash
#param1: mq_name #param2: qlocal GetQueueDepth() { if [ $# != 2 ] then echo "Usage : FUNCTION QMNAME QLOCAL" return 1 fi QMNAME="$1" QLOCAL="$2" AAA=`runmqsc $QMNAME <<! display qlocal($QLOCAL) end !` echo ${AAA#*CURDEPTH} | awk '{print $1}' | cut -d '(' -f2|cut -d ')' -f1 }
GetQueueContent() { if [ $# != 2 ] then echo "Usage : FUNCTION QMNAME QLOCAL" return 1 fi MSG_DETAIL_PATH=./MSG_DETAIL QMNAME="$1" QLOCAL="$2" if [ ! -d $MSG_DETAIL_PATH ] then mkdir $MSG_DETAIL_PATH fi MSG_FILE=$MSG_DETAIL_PATH/$QMNAME-$QLOCAL > $MSG_FILE amqsbcg $QLOCAL $QMNAME > $MSG_FILE }
GetAllQM() { AAA=`dspmq` for item in $AAA do PREFIX=${item:0:6} if [ "$PREFIX" = "QMNAME" ] then echo ${item#*QMNAME} | cut -d '(' -f2|cut -d ')' -f1 fi done }
GetAllQueue() { if [ $# != 1 ] then echo "Usage : FUNCTION QMNAME" return 1 fi QMNAME="$1" AAA=`runmqsc $QMNAME <<! display qlocal(*) end !` for item in $AAA do PREFIX=${item:0:5} if [ "$PREFIX" = "QUEUE" ] then QUEUENAME=`echo ${item#*QUEUE} | cut -d '(' -f2|cut -d ')' -f1` QUEUE_PREFIX=${QUEUENAME:0:6} if [ "$QUEUE_PREFIX" != "SYSTEM" ] then echo "$QUEUENAME" fi fi done }
setupenv() { IFS_old=$IFS IFS=$':'
BIN1=0 BIN2=0 PATH1="/opt/mqm/bin" PATH2="/opt/mqm/samp/bin" CUR_PATH_ENV=`echo $PATH` for item in $CUR_PATH_ENV do #echo -e "$item \n" if [ "$item" = $PATH1 ] then BIN1=1 fi if [ "$item" = $PATH2 ] then BIN2=1 fi done
[ $BIN1 -ne 1 ] && [ -d $PATH1 ] && export PATH=$PATH1:$PATH [ $BIN2 -ne 1 ] && [ -d $PATH2 ] && export PATH=$PATH2:$PATH
IFS=$IFS_old }
###############main function#################### #QMNAME="QM_T24HK_EXT" #QLOCAL="Q.DTS.REQU"
LOGFILE=./CHECK_QM.log > $LOGFILE
setupenv #echo $PATH
ALLQM=$(GetAllQM) for QMNAME in $ALLQM do echo -e "------------------------------" | tee -a $LOGFILE echo -e "Current QM : $QMNAME \n" | tee -a $LOGFILE ALLQUEUE=$(GetAllQueue $QMNAME) for queuename in $ALLQUEUE do $(GetQueueContent $QMNAME $queuename) DEPTH=$(GetQueueDepth $QMNAME $queuename) if [ "X$DEPTH" != "X0" ] then echo -e "\t!!![ATTENTION] The ($QMNAME:$queuename) depth is : $DEPTH" | tee -a $LOGFILE else echo -e "\t The ($QMNAME:$queuename) depth is : $DEPTH" | tee -a $LOGFILE fi done echo -e "------------------------------\n" | tee -a $LOGFILE done
echo "Successfully............" |
解决方案详解
- 设置环境变量setupenv
为实用IBM MQ的相关命令,需配置PATH环境变量,以便让脚本能直接引用相关命令。具体请参阅函数。
- 获取当前服务器上的所有QM(队列管理器)
采用函数GetAllQM()获取当前服务器上的所有QM。主要使用了dspmq命令,并对命令的输出进行了截取操作。这里讲述cat命令:
-b :以字节为单位进行分割。这些字节位置将忽略多字节字符边界,除非也指定了 -n 标志。 byte
-c :以字符为单位进行分割。 char
-d :自定义分隔符,默认为制表符。 define
-f :与-d一起使用,指定显示哪个区域。 fields 一般用以指定分隔符后的第几列
-n :取消分割多字节字符。仅和 -b 标志一起使用。如果字符的最后一个字节落在由 -b 标志的 List 参数指示的
范围之内,该字符将被写出;否则,该字符将被排除
笔者使用的cut -d '(' -f2 | cut -d ')' -f1 在网上搜寻得知。具体需求就是需要提取括号中的内容。
-d 指定了分隔符,-f 指定取哪个field。
此处先按照左括号分割,先取第二域,再按右括号分割,取第一个域。刚好提取了括号里面的内容。可能有更好的正则表达式方案可以实现此效果。但笔者正则表达式学艺不深,未能实现。
- 获取QM的所有队列GetAllQueue
根据1中的结果,调用函数获取了特定队列的所有queue。主要使用了两个命令:
- runmqsc XXX
- display qlocal(*)
与1同样,对display qlocal的返回进行了截取处理,并过滤掉了以”SYSTEM”开头的对接(属于系统预置队列)
- 获取队列深度GetQueueDepth
函数根据入参1(QM名)、入参2(QLOCAL名),使用display qlocal(XXX)获取队列的具体信息。同样,对返回值进行了截取处理,获得了具体的队列深度。
- 预览队列内容GetQueueContent
函数使用命令amqsbcg根据入参(QM名+QLOCAL名)预览队列消息,并写入到./MSG_DETAIL目录下,每个应用队列的预览消息形成一个文件,命令为:$QMNAME-$QLOCAL。
- 结果输出
除了将结果输出到终端外,笔者还通过tee将结果重定向了相关文件,便于永久保存。
运行结果
队列深度
如上,QM_SDR和QM_RCV未获取到队列信息是因为QM状态不正常。另外一个QM获取到正确的结果。
消息内容
扩展与总结
- 为实现类似此IBM MQ管理的脚本化,需要对IBM MQ的命令比较熟悉;
- 采用函数化的设计,读者可以轻易扩展出更多的功能,比如笔者的遗漏功能:获取QM的状态;