MQ 介绍及安装
介绍
MQ,简单地说就是消息队列,应用程序把消息放进队列里,等待其他的应用程序或自己把它读走,用于进程间通信,并且可以像 socket 那样用于不同主机间的进程间通信。它有四个重要的概念:
队列管理器
用来管理队列。
队列
用来存放消息。
消息
就是要进行存储与传递的消息。
通道
队列管理器之间传递消息的管道。
安装
到这里下载 MQ for 64-bit linux。下载完解压后,先运行 MQ 的许可证程序:
./mqlisence.sh
然后安装你想要装的组件:
rpm -U MQSeriesXXXXXXX.rpm
MQ 基本操作
创建队列管理器
crtmqm -q qm_name
启动队列管理器
strmqm qm_name
查看队列管理器
dspmq -m qm_name
创建队列
创建队列不像创建队列管理器那样有直接的命令可以使用,而是要先运行命令:
runmqsc
再执行语句:
def ql(QUEUE1)
也可以把语句写到一个文件里面,再把这个文件当作 runmqsc 的输入:
runmqsc < statement.txt
如果在执行 strmqm qm_name
之后再运行 runmqsc
,就表示是对 qm_name 这个队列管理器进行操作,如果要想对其他的队列管理器操作,则要在 runmqsc
后面加队列管理器名:
runmqsc qm_name
队列有很多属性,具体的细节可查看 IBM 的手册。
停止队列管理器
endmqm qm_name // 受控停止
endmqm -i qm_name // 立即停止
endmqm -p qm_name // 强制停止
删除队列管理器
dltmqm qm_name
错误与及解决办法
我在创建队列管理器时出现下以提示信息:
The queue manager is associated with installation ‘Installation1’. AMQ6024: Insufficient resources are available to complete a system request.
错误信息在 /var/mqm/errors/ 可以查看到:
cat AMQ7116.0.FDC
Probe Description :- AMQ6024: Insufficient resources are available to
complete a system request.
FDCSequenceNumber :- 0
Arith1 :- 18446744073709551615 (0xffffffffffffffff)
Arith2 :- 22 (0x16)
Comment1 :- Failed to get memory segment: shmget(0x00000000,
73834496) [rc=-1 errno=22] Invalid argument
Comment2 :- Invalid argument
Comment3 :- Configure kernel (for example, shmmax) to allow a
shared memory segment of at least 73834496 bytes
这个问题可以这样解决:
sudo sysctl -w kernel.shmmax=73834496
sysctl
可以动态修改内核参数而不用重启。
MQ client 封装库
MQI
Message Queue Interface 一共包含 13 个函数。它们分别是(可以在 cmqc.h 查看它们的原型):
MQCONN 和 MQCONNX
连接队列管理器。两者唯一的区别是 MQCONNX 比 MQCONN 多了一个连接选项参数。
MQDISC
断开与队列管理器的连接。
MQOPEN 和 MQCLOSE
每一个队列都必须单独调用 MQOPEN 来打开。并且这两者必须配对出现。
MQPUT
把消息放到一个打开的队列中。
MQPUT1
也是把消息放到一个打开的队列中。不过它比 MQPUT 多执行了两个函数:MQOPEN 和 MQCLOSE。
MQGET
从一个打开的队列中读取或浏览信息。在它的参数当中,有一个 MQGMO 的参数很重要,可以用来指示该操作是读取还是浏览的,如果是读取的,则从队列中读走消息;如果是浏览的,则消息还留在队列中。因为要提供一个 buffer 以及该 buffer 的长度给 MQGET 用来存放读取的消息,如果消息太长,buffer 存放不下,也可以设定该参数告诉 MQGET 到底是返回部分消息还是操作失败。
MQBEGIN
The MQBEGIN MQI function is only used when a queue manager has been configured to coordinate global units of work involing database products.
MQCMIT 和 MQBACK
MQCMIT 用来提交当前 unit of work。对局部的 unit of work 而言,仅仅包括 MQ 的操作:从应用程序连接到队列管理器或才最后一次执行 MQCMIT/MQBACK 以来的所有在同步点之下执行的 MQGET/MQPUT 操作。对全局的 units of work 而言,它包括数据库操作和 MQ 操作。
MQBACK 用来回滚当前 unit of work。这些操作和 MQCMIT 描述的操作相同。MQBACK 会导致所有的操作被撤销,put 到队列的消息会被移除掉,从队列 get 的消息则会重新返回到队列中。
MQINQ 和 MQSET
MQINQ 查询属性,而 MQSET 则设置属性。
以上每一个函数调用都返回一个 completion code 和一个 reason code。completion code 只有三种值:
1. MQCC_OK: 表示函数调用完全成功。
2. MQCC_WARNING: 表示函数调用部分完全。可以查看 reason code 了解更多的细节。
3. MQCC_FAILED: 表示函数调用失败。可以查看 reason code 了解更多的细节。
而 reason code 的值则有很多。具体的细节的可查看reason code list。
mqclient
因为工作的需要,所以自己封装了 MQI 13 个函数中的部分接口。目前 mqclient(这里可以查看) 库只提供了 6 个接口:
1 2 3 4 5 6 | |
一开始是把两个 open() 函数放在 put() 和 get() 里面的,但考虑到每 get() 一次都要 open() 和 close() 一次,会不会不够高效呢?如果把两个 open() 函数独立出来,那只调用一次 open() 后就可以连续的 get() 了。所以就把它们独立出来。而 close() 则放在 disconnect() 里面。
在使用的过程中发现,将 mqclient_get_open() 和 mqclient_put_open() 独立出来,会导致当使用同一个 struct mqclient 结构时,如果要操作多条写或读队列,则只有最后调用这两个接口的那条队列可以操作成功。例如有两条队列 Q1 Q2 都要进行 put() 操作,
1 2 3 4 | |
但实际所有的操作都是对 Q2 进行的。当然可以先操作完 Q1 再操作 Q2。这里只是把一条消息添加到 Q1 和 Q2 上,但如果有多条消息分别要添加到 Q1 和 Q2 上呢,并且逻辑一定要先往 Q1 put 一条消息后再往 Q2 put 一条消息。这时就不得不要再添加一个 struct mqclient 结构了。然后代码就要写成:
1 2 3 4 5 6 | |