Linux下IBM MQ 7.5安装配置指南:从队列管理器到应用接入 1. 安装前的准备工作与环境确认1.1 为什么要选IBM MQ 7.5开发版IBM MQ这玩意儿很多刚接触消息中间件的人一听就头疼总觉得是上世纪的大型机产物。但说实话在金融、政企、制造业这些行业里IBM MQ的存量部署量相当大不少核心系统的数据交换还是靠它撑着。7.5这个版本虽然是2013年左右发布的但胜在稳定、轻量、兼容性好而且开发版License免费用来学习、做原型验证、搭测试环境完全够用。开发版和企业版的区别说白了就是授权范围和用途不同。开发版不收费但官方规定只能用于开发和测试不能上生产。你学习MQ的基本概念、掌握队列管理器怎么建、通道怎么配、应用程序怎么连这套流程用开发版跑一遍跟企业版几乎没差别。等真到了生产环境再按企业版的标准去部署迁移成本也不高。1.2 确认Linux发行版与系统版本安装IBM MQ 7.5之前我建议你先确认自己的Linux发行版。MQ 7.5官方支持Red Hat Enterprise Linux 5、6、7以及SUSE Linux Enterprise Server 11等。但在实际测试中CentOS 6、CentOS 7、Oracle Linux 7这些RHEL系的发行版都能正常装。如果你是Ubuntu、Debian这类Debian系的系统会稍微麻烦一点——MQ 7.5官方只提供RPM包没有DEB包需要在Ubuntu上先装一个alien做格式转换或者干脆用Docker跑一个CentOS容器。我这次用的是CentOS 7.9内核版本3.10内存4G磁盘40G属于比较典型的“够用就行”的测试机配置。IBM MQ 7.5对硬件要求不高1G内存、2G磁盘就能跑起来但你要是同时跑队列管理器、Java应用、做性能压测建议至少给2G内存。操作系统确认命令我就不啰嗦了cat /etc/redhat-release和uname -a这两个命令足够你判断发行版和内核版本。装之前还要确认两件事一是网络能不能通因为后面安装依赖包时可能需要用yum二是防火墙和SELinux的状态这两个往往是MQ装完却连不上的罪魁祸首。1.3 获取开发版安装包IBM MQ 7.5的开发版安装包在IBM官网的Downloads页面能找到。你可能会问7.5这么老的版本官网还提供下载吗答案是提供的IBM把MQ 7.5、8.0这些版本的开发者版下载链接保留得很好只是入口藏得比较深。你在搜索框里输入“IBM MQ 7.5 Developer Trial”一般能找到对应的下载页面。下载下来你会得到一组RPM包命名方式类似这样MQSeriesRuntime-7.5.0-0.x86_64.rpm MQSeriesServer-7.5.0-0.x86_64.rpm MQSeriesClient-7.5.0-0.x86_64.rpm MQSeriesSDK-7.5.0-0.x86_64.rpm MQSeriesSamples-7.5.0-0.x86_64.rpm MQSeriesMan-7.5.0-0.x86_64.rpm如果你只需要服务端MQSeriesRuntime、MQSeriesServer、MQSeriesSDK、MQSeriesSamples这四个核心包是必须的。MQSeriesMan是帮助文档不装也能跑。MQSeriesClient是客户端库如果你在同一台机器上跑客户端连接测试也建议装上。注意不同操作系统的RPM包架构后缀不一样x86_64对应64位系统i386对应32位系统。现在基本都是64位系统直接选x86_64就行。下载时务必确认你的系统是RedHat系否则后面rpm安装会报“wrong architecture”或者“is not designed for this platform”之类的错误。2. 安装包的解压、依赖处理与正式安装2.1 解压后的文件结构下载好的安装包通常是一个.tar.gz压缩包先解压到一个干净的目录。我习惯放在/opt/mqinstall下方便统一管理mkdir -p /opt/mqinstall cd /opt/mqinstall tar -zxvf MQ_7.5_TRIAL_LNX_X86_64.tar.gz解压后你会看到一个MQServer目录里面才是真正的RPM包数组。顺便说一句IBM的这个tar包有时会在根目录放一个README或License文件建议先扫一眼主要是确认版本号和授权注意事项。2.2 RPM安装顺序与依赖处理这里有一个很多人踩过的坑RPM包不能一次性全部rpm -ivh *.rpm盲目安装因为包之间存在依赖关系。顺序建议是rpm -ivh MQSeriesRuntime-7.5.0-0.x86_64.rpm rpm -ivh MQSeriesServer-7.5.0-0.x86_64.rpm rpm -ivh MQSeriesSDK-7.5.0-0.x86_64.rpm rpm -ivh MQSeriesSamples-7.5.0-0.x86_64.rpm rpm -ivh MQSeriesMan-7.5.0-0.x86_64.rpm为什么是这个顺序因为MQSeriesServer依赖MQSeriesRuntime提供的基础库和运行环境而MQSeriesSDK又依赖MQSeriesServer中的头文件和服务端组件。先装Runtime再装Server这是从底层到上层的依赖关系。你要是乱序安装大概率会看到类似“libmqm.so is needed by MQSeriesServer”这样的依赖报错。依赖库方面CentOS 7最小化安装的情况下一般需要先装ksh和bc。MQ的很多管理脚本是用ksh写的缺了ksh可能导致后续的crtmqm、strmqm脚本执行异常。bc则是做运算法则校验用的不装问题不大但建议一起装了yum install -y ksh bc另外IBM MQ 7.5在安装时会自动创建名为mqm的系统用户和用户组不需要你手动创建。安装完成后/opt/mqm目录就是MQ的安装目录所有二进制文件、库文件、许可文件都在里面。2.3 安装完成的验证装完之后验证一下安装是否完整。我用三个命令来做基本检查ls -ld /opt/mqm /opt/mqm/bin/dspmqver /opt/mqm/bin/dspmqdspmqver会输出IBM MQ的版本信息比如Version: 7.5.0.0。dspmq是显示队列管理器状态的命令如果当前还没有创建任何队列管理器它会输出类似AMQ7064: No queue manager has been created的信息属于正常现象。到这里安装本身就算完成了。但别急着建队列管理器建议先做一步环境变量配置。MQ装完后/opt/mqm/bin下有一堆命令但默认没有加入当前用户的PATH。你可以把相关环境变量写进~/.bash_profileexport MQ_INSTALLATION_PATH/opt/mqm export PATH$PATH:/opt/mqm/bin:/opt/mqm/samp/bin export MANPATH$MANPATH:/opt/mqm/man注意用mqm用户登录时这些环境变量是必须的。你当然也可以用绝对路径/opt/mqm/bin/xxx执行命令但那样太累而且后续用runmqsc交互式敲命令时没有环境变量支持会各种别扭。3. 创建队列管理器从命名到初始化参数3.1 队列管理器的概念与命名规则在动手创建之前先搞清楚一个核心概念IBM MQ里最顶层的管理单元是“队列管理器Queue Manager”。你可以把它理解成一个独立的“消息处理服务器实例”——它管着自己下面的一堆队列、通道、监听器不同队列管理器之间的消息是物理隔离的互不干扰。命名规则上队列管理器的名字最多48个字符但在Linux上建议控制在12个字符以内方便用runmqsc交互时频繁输入。名字只能包含字母、数字、点号、下划线而且不能以数字开头。我测试时常用QMGR1、TESTQM这样的名字简单明了。3.2 用crtmqm创建队列管理器创建队列管理器直接使用crtmqm命令crtmqm -q TESTQM这里的-q参数表示启用队列管理器上的队列控制功能中文环境一般建议加这个参数它能保证队列文件的正确初始化。如果你不加-q在某些语言环境下可能会碰到队列文件编码不一致导致的怪异问题。创建成功后系统会输出类似IBM MQ queue manager created.字样。此时你可以用dspmq查看状态正常会显示QMNAME(TESTQM) STATUS(Ended normally)——注意这里的状态是“Ended normally”意思是队列管理器已经创建但还没启动不要误以为出错了。3.3 启动队列管理器启动队列管理器用strmqm命令strmqm TESTQM第一次启动会比较慢因为要初始化内部系统队列、恢复日志等。启动成功后输出会显示IBM MQ queue manager TESTQM started.。到这里队列管理器已经在运行了但你还没有任何队列可以收发消息。接下来需要进入runmqsc交互式环境创建队列、通道、监听器这些资源。runmqsc是IBM MQ的管理命令解释器类似于数据库的sqlplus。用法很简单runmqsc TESTQM进入后会出现提示符。在这个交互式环境下你可以执行DEFINE、DISPLAY、ALTER、DELETE、START、STOP等管理命令。注意runmqsc中的命令是不区分大小写的但资源名字要注意大小写一致性。IBM MQ在Linux上的命名是大小写敏感的Queue1和queue1是两个不同的队列。为了避免混乱建议统一用大写字母定义资源名。4. 队列与通道配置让消息真正流动起来4.1 创建本地队列队列是消息的存储容器本地队列就是真正物理存储消息的队列。在runmqsc里执行DEFINE QLOCAL(TEST.QUEUE) DESCR(Test local queue) MAXDEPTH(5000) DEFPSIST(YES)简单解释一下这些参数的意义QLOCAL表示这是一个本地队列消息真正存储在这个队列管理器的本地磁盘上。DESCR是对队列的描述信息方便别人看队列是干嘛用的。MAXDEPTH是队列的最大深度就是最多能堆积多少条消息。默认是5000测试环境够用。DEFPSIST(YES)表示消息默认是持久化的。持久化消息会写入日志队列管理器重启后消息不丢非持久化消息存在内存中性能更快但重启会丢。如果做的是日志、通知类数据建议用持久化。创建完队列后可以用DISPLAY QUEUE(TEST.QUEUE)来查看队列的详细信息确认创建成功。4.2 创建服务器连接通道通道是客户端应用连接队列管理器的大门。IBM MQ里有很多种通道类型做开发测试时最常用的是SVRCONN服务端连接通道。应用程序通过这个通道连接上队列管理器然后才能读写队列。DEFINE CHANNEL(TEST.SVRCONN) CHLTYPE(SVRCONN) TRPTYPE(TCP) REPLACE这条命令定义了一个名为TEST.SVRCONN的TCP服务端连接通道。REPLACE是“如果同名通道已存在就替换”的意思主要用于脚本幂等执行。4.3 创建监听器并绑定端口有了通道还不够队列管理器必须有一个监听器在指定的TCP端口上“听候指令”客户端应用的连接请求才能到达。创建监听器DEFINE LISTENER(LST.TEST) TRPTYPE(TCP) PORT(1414) CONTROL(QMGR) START LISTENER(LST.TEST)这里有两个关键点PORT(1414)IBM MQ的默认端口就是1414。如果你机器上的1414被占了可以换个端口比如1415。但客户端连接时端口必须和这里配置的一致。CONTROL(QMGR)表示监听器由队列管理器启动时自动启动队列管理器停止时也自动停止。这个参数很省心不用每次重启队列管理器后手动去启动监听器。启动监听器后可以用DISPLAY LISTENER(LST.TEST)查看监听器状态。正常情况下状态是RUNNING。4.4 授权与权限设置很多人在本地测试时发现应用连不上队列管理器或者连上了但打不开队列问题往往出在权限配置上。IBM MQ的权限体系比较复杂但开发测试环境你只需要掌握一个命令setmqaut。比如要给mqm用户或者某个应用用户授予对TEST.QUEUE队列的全部权限setmqaut -m TESTQM -t qmgr -p mqm connect inq setmqaut -m TESTQM -t queue -n TEST.QUEUE -p mqm put get browse inq第一行是给mqm用户授予连接队列管理器的权限第二行是授予对队列的写入、读取、浏览和查询权限。如果你希望所有本地用户都能访问可以使用-g mqm指定用户组或者直接用-p参数指定具体用户。实际操作中我建议明确指定用户不要图省事直接给-g mqm因为mqm组用户相当于MQ的超级管理员生产环境这么搞风险很大。重要提示每次修改完权限后不需要重启队列管理器或队列权限即时生效。这一点我实测过比改操作系统文件权限要人性化很多。4.5 保存并退出runmqsc所有配置完成之后用END命令退出runmqsc。如果你希望修改自动保存直接输END即可如果输QUIT效果其实一样都会保存并退出。除非你在运行过程中显式地使用了-z之类的回滚选项否则配置都会写入队列管理器的配置文件。退出后可以用runmqsc TESTQM testscript.mqsc的方式把上述所有命令保存成脚本这样以后重建环境时一行命令就能搞定。这也是我强烈推荐的做法——把整个初始化过程固化成脚本比每次手动敲命令强太多。5. 应用接入Java与C客户端的连接测试5.1 使用Java应用测试连接IBM MQ 7.5自带一套JMS和Java库位于/opt/mqm/java/lib目录。测试前先把这些库加入CLASSPATHexport CLASSPATH/opt/mqm/java/lib/com.ibm.mq.jar:/opt/mqm/java/lib/com.ibm.mqjms.jar:/opt/mqm/java/lib/jms.jar:/opt/mqm/java/lib/connector.jar:/opt/mqm/java/lib/com.ibm.mq.jmqi.jar:$CLASSPATH然后写一个简单的Java程序目标是往TEST.QUEUE里发一条消息再读回来。这里的关键点有MQEnvironment.hostname设置为服务器地址本机测试就用localhost。MQEnvironment.port要填监听器绑定的端口即1414。MQEnvironment.channel填通道名TEST.SVRCONN。连接工厂创建之后必须setTransportType(JCATransport.JMSC)表示走客户端模式连接。默认的BINDINGS模式是进程内绑定只适合应用和队列管理器在同一台机器、同一个用户环境下的场景。如果你用的是纯MQ基础类非JMS还有一套更直接的写法但代码量会多不少。开发测试阶段我建议直接用JMS接口代码最简洁也最容易排查问题。5.2 C/SDK客户端连接IBM MQ同时提供C语言的客户端接入方式。在Linux环境里编译时需要链接libmqm.so和libmqic.so两个库。一个最小化的C客户端发送程序核心步骤也就是MQCONN连接队列管理器、MQOPEN打开队列、MQPUT发送消息、MQDISC断开连接。编译命令大致如下gcc -o mqput mqput.c -I/opt/mqm/inc -L/opt/mqm/lib -lmqm -lmqic如果你只想快速验证发送方可以用IBM MQ自带的示例程序。在/opt/mqm/samp/bin目录下有amqsputc和amqsgetc两个命令行工具分别用于发送和获取消息用法/opt/mqm/samp/bin/amqsputc TEST.QUEUE TESTQM输入内容后按两下CtrlD结束输入消息就发送到了TEST.QUEUE。再用/opt/mqm/samp/bin/amqsgetc TEST.QUEUE TESTQM就会把消息读出来打印到标准输出。用这种方式做端到端验证远比写一个复杂的Java程序高效。5.3 验证消息的持久化与重复消费实际开发中总会遇到“消息队列重复消费”的问题。这个和MQ本身的关系在于IBM MQ支持“刚好一次”传递前提是你正确使用了SYNCPOINT同步点机制。用JMS做事务型会话时消息的接收和业务处理处在同一个事务中。当session.commit()成功提交后MQ才会真正把消息标记为“已消费”。如果在commit()之前应用崩溃了MQ会认为这条消息还没被消费等应用下一次重连时消息会被重新投递给消费者——这就是“重复消费”现象产生的根本原因。所以在使用IBM MQ时你的消费者应用必须做到“幂等性”——也就是同一条消息处理两次和一次最终结果是一样的。这个在上游消息、支付回调对接时尤其重要。MQ本身不会主动去重它只保证“至少一次”或“刚好一次”的投递语义去重逻辑必须由业务代码自己实现。处理重复消费的常见方案给每条消息加一个唯一的业务ID业务侧用一个去重表或Redis做记录消息处理前先查一下这个ID是否处理过。防重逻辑放在消息消费侧这是行业里的标准做法。6. 常见问题与排查技巧实录6.1 客户端连接失败AMQ4036实际测试中我最常遇到的错误就是AMQ4036含义是“对队列管理器或队列没有授权”。这个错误几乎可以断定问题出在setmqaut没有配置好或者通道配置的MCAUSER设置了受限用户。排查步骤用DISPLAY CHANNEL(TEST.SVRCONN)查看通道的MCAUSER字段。如果MCAUSER指向了一个不存在或者权限受限的用户比如nobody客户端连接必挂。检查是否执行了setmqaut授权命令特别是connect权限。如果还是不不行可以临时把通道的MCAUSER置空即不限制再测试。注意生产环境不能这么干否则任何人连上通道就能访问队列管理器。在开发测试环境如果懒得做详细授权最省事的方案是把TEST.SVRCONN的MCAUSER设置为mqmALTER CHANNEL(TEST.SVRCONN) CHLTYPE(SVRCONN) MCAUSER(mqm)这样所有通过该通道进来的连接都拥有mqm用户权限开发调试非常方便。但记住仅限测试环境。6.2 端口不可达检查防火墙与SELinux如果你发现应用连接报超时或者telnet 192.168.x.x 1414一直卡住问题大概率出在Linux防火墙或SELinux上。CentOS 7的firewalld默认会把外部端口的访问挡掉。放行1414端口firewall-cmd --zonepublic --add-port1414/tcp --permanent firewall-cmd --reload如果不想麻烦测试环境直接停掉防火墙也可以systemctl stop firewalld systemctl disable firewalld另一个容易忽视的是SELinux。很多人装完MQ后连接失败查了半天才发现是SELinux拦截了进程的网络访问。临时关闭SELinuxsetenforce 0永久关闭则编辑/etc/selinux/config把SELINUXenforcing改成SELINUXdisabled然后重启系统。注意SELinux从enforcing到disabled必须重启才能完全生效只改文件不重启是不行的。6.3 队列管理器无法启动用strmqm TESTQM启动时如果卡住很久或者直接报错一种常见原因是MQ的日志目录权限不对。检查/var/mqm目录的所有者是否为mqm用户ls -ld /var/mqm chown -R mqm:mqm /var/mqm还有一种情况是系统临时目录空间不足MQ启动时需要创建共享内存和临时文件。用df -h /tmp检查一下如果使用率接近100%清理临时文件后重启MQ。6.4 runmqsc输出乱码或命令不可识别如果你用的是中文语言环境的Linux某些MQ 7.5版本的runmqsc交互接口可能出现乱码或者输入命令后报错“Invalid command”。这时候最有效的两个方法在连接时强制使用英文语言环境export LANGen_US.UTF-8然后再runmqsc TESTQM。把整个会话脚本通过重定向执行比如runmqsc TESTQM /opt/mqinstall/test.mqsc这样脚本内容就是纯ASCII不存在字符集混入问题。6.5 日志与错误定位的常用命令最后再讲一下排查问题的“三板斧”。IBM MQ的错误日志主要放在/var/mqm/qmgrs/TESTQM/errors/AMQERR01.LOG /var/mqm/errors/AMQERR01.LOG这两个文件平时不引人注意但一旦出问题里面的信息量非常大。比如客户端连不上时服务端日志里会详细记录“通道校验失败”“连接被拒绝”“权限不足”等具体原因比客户端报错信息有用得多。另外两个实用命令dspmq -o status # 查看所有队列管理器及运行状态 DISPLAY CHSTATUS(TEST.SVRCONN) # 在runmqsc里查看通道当前状态和连接数DISPLAY CHSTATUS能看到当前有多少个客户端连接占有这个通道特别适合排查“连接数打满”的问题。MQ 7.5默认通道最大连接数是100如果你测试时并发连接数超过100需要调整MAXINST和MAXINSTC参数但开发环境一般不会碰到。7. 运维必要知识日志管理、队列监控与备份建议7.1 日志文件的使用情况IBM MQ 7.5默认使用循环日志circular logging日志文件存放在/var/mqm/log/TESTQM目录下。循环日志的好处是自动覆盖旧日志不会把磁盘写满坏处是如果你需要做灾难恢复它只能恢复到问题发生前最近的一小段时间。开发测试环境用循环日志就够了完全不需要改成线性日志。线性日志会持续追加磁盘空间不够就会导致队列管理器拒绝启动这在生产环境是常态但测试环境没必要给自己找事。7.2 队列深度的日常监控测试环境你可能不在意队列深度但一旦应用写多读少消息就会在TEST.QUEUE里堆积时间久了可能触发MAXDEPTH上限。到那时MQPUT会直接报MQRC_Q_FULL原因码2053如果应用没有做异常处理很容易引发连环故障。日常监控队列深度我用一个很简单的命令echo DISPLAY QSTATUS(TEST.QUEUE) CURDEPTH | runmqsc TESTQM实时看队列当前深度是运维MQ最基本的操作。生产环境一般会通过MQ的dmpmqcfg定期导出配置、用QMgr Status页面或者第三方监控工具做告警但原理都是从队列深度、通道状态、日志错误三个维度出发。7.3 配置备份与快速恢复最后强烈建议大家把配置过程“脚本化”。我在/opt/mqinstall目录下维护了一个init_mq.mqsc内容就是上面讲到的所有DEFINE命令DEFINE QLOCAL(TEST.QUEUE) MAXDEPTH(5000) DEFPSIST(YES) REPLACE DEFINE CHANNEL(TEST.SVRCONN) CHLTYPE(SVRCONN) TRPTYPE(TCP) REPLACE DEFINE LISTENER(LST.TEST) TRPTYPE(TCP) PORT(1414) CONTROL(QMGR) REPLACE START LISTENER(LST.TEST)以后换机器、重装系统时只需要两条命令就能恢复整个环境crtmqm -q TESTQM strmqm TESTQM runmqsc TESTQM /opt/mqinstall/init_mq.mqsc再配合dmpmqcfg -m TESTQM -a导出全部配置包含权限整个环境的“灾备恢复”就算完成了一大半。我个人的体会是消息中间件的安装配置本身只是第一步真正考验人的是后续的监控、备份、权限管理。把这几件事在测试环境里提前演练熟了到了生产环境才不会手忙脚乱。如果你后续计划从Java、Spring Boot这些现代框架接入MQ7.5本身对JMS的支持已经很成熟连接池、事务、消息确认这些机制都能用不会因为版本老而影响开发体验。可以先在7.5上把概念跑通等需要更优秀的吞吐性能和更简便的运维管理时再平滑升级到9.x版本也不迟。