一、MQ简介及特点
MQ全称为Message Queue, 消息队列(MQ)是一种应用程序对应用程序的通信方法。应用程序通过写和检索出入列队的针对应用程序的数据(消息)来通信,而无需专用连接来链接它们。消息传递指的是程序之间通过在消息中发送数据进行通信,而不是通过直接调用彼此来通信,直接调用通常是用于诸如远程过程调用的技术。排队指的是应用程序通过队列来通信。队列的使用除去了接收和发送应用程序同时执行的要求。其中较为成熟的MQ产品有IBM
WebSphere MQ、RabbitMQ 、ZeroMQ 、ActiveMQ、Redis(当做一个轻量级的队列服务来使用)、Kafka、RocketMQ。它们之间的比较详见:MQ介绍与选型及之间比较。
特点:MQ的消费-生产者模型的一个典型的代表,一端往消息队列中不断的写入消息,而另一端则可以读取或者订阅队列中的消息。MQ和JMS类似,但不同的是JMS是SUN Java消息中间件服务的一个标准和API定义,而MQ则是遵循了AMQP协议的具体实现和产品。
以下主要介绍—IBM
WebSphere MQ
二、MQ使用场景
1、异步通信
有些业务不想也不需要立即处理消息。消息队列提供了异步处理机制,允许用户把一个消息放入队列,但并不立即处理它。想向队列中放入多少消息就放多少,然后在需要的时候再去处理它们。
2、解耦
降低工程间的强依赖程度,针对异构系统进行适配。在项目启动之初来预测将来项目会碰到什么需求,是极其困难的。通过消息系统在处理过程中间插入了一个隐含的、基于数据的接口层,两边的处理过程都要实现这一接口,当应用发生变化时,可以独立的扩展或修改两边的处理过程,只要确保它们遵守同样的接口约束
3、冗余
有些情况下,处理数据的过程会失败。除非数据被持久化,否则将造成丢失。消息队列把数据进行持久化直到它们已经被完全处理,通过这一方式规避了数据丢失风险。许多消息队列所采用的"插入-获取-删除"范式中,在把一个消息从队列中删除之前,需要你的处理系统明确的指出该消息已经被处理完毕,从而确保你的数据被安全的保存直到你使用完毕。
4、扩展性
因为消息队列解耦了你的处理过程,所以增大消息入队和处理的频率是很容易的,只要另外增加处理过程即可。不需要改变代码、不需要调节参数。便于分布式扩容
5、过载保护
在访问量剧增的情况下,应用仍然需要继续发挥作用,但是这样的突发流量无法提取预知;如果以为了能处理这类瞬间峰值访问为标准来投入资源随时待命无疑是巨大的浪费。使用消息队列能够使关键组件顶住突发的访问压力,而不会因为突发的超负荷的请求而完全崩溃
6、可恢复性
系统的一部分组件失效时,不会影响到整个系统。消息队列降低了进程间的耦合度,所以即使一个处理消息的进程挂掉,加入队列中的消息仍然可以在系统恢复后被处理。
7、顺序保证
在大多使用场景下,数据处理的顺序都很重要。大部分消息队列本来就是排序的,并且能保证数据会按照特定的顺序来处理。
8、缓冲
在任何重要的系统中,都会有需要不同的处理时间的元素。消息队列通过一个缓冲层来帮助任务最高效率的执行,该缓冲有助于控制和优化数据流经过系统的速度。以调节系统响应时间。 9、数据流处理 分布式系统产生的海量数据流,如:业务日志、监控数据、用户行为等,针对这些数据流进行实时或批量采集汇总,然后进行大数据分析是当前互联网的必备技术,通过消息队列完成此类数据收集是最好的选择
三、MQ原理
1、MQ原型
Pub/Sub发布订阅(广播):使用topic作为通信载体
PTP点对点:使用queue作为通信载体
2、MQ组成
Broker:消息服务器,作为server提供消息核心服务
Producer:消息生产者,业务的发起方,负责生产消息传输给broker,
Consumer:消息消费者,业务的处理方,负责从broker获取消息并进行业务逻辑处理
Topic:主题,发布订阅模式下的消息统一汇集地,不同生产者向topic发送消息,由MQ服务器分发到不同的订阅 者,实现消息的广播
Queue:队列,PTP模式下,特定生产者向特定queue发送消息,消费者订阅特定的queue完成指定消息的接收
Message:消息体,根据不同通信协议定义的固定格式进行编码的数据包,来封装业务数据,实现消息的传输
3、MQ常用协议
AMQP协议 AMQP即Advanced Message Queuing Protocol,一个提供统一消息服务的应用层标准高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计。基于此协议的客户端与消息中间件可传递消息,并不受客户端/中间件不同产品,不同开发语言等条件的限制。
优点:可靠、通用
MQTT协议 MQTT(Message Queuing Telemetry Transport,消息队列遥测传输)是IBM开发的一个即时通讯协议,有可能成为物联网的重要组成部分。该协议支持所有平台,几乎可以把所有联网物品和外部连接起来,被用来当做传感器和致动器(比如通过Twitter让房屋联网)的通信协议。 优点:格式简洁、占用带宽小、移动端通信、PUSH、嵌入式系统
STOMP协议 STOMP(Streaming Text Orientated Message Protocol)是流文本定向消息协议,是一种为MOM(Message
Oriented Middleware,面向消息的中间件)设计的简单文本协议。STOMP提供一个可互操作的连接格式,允许客户端与任意STOMP消息代理(Broker)进行交互。 优点:命令模式(非topic\queue模式)
XMPP协议 XMPP(可扩展消息处理现场协议,Extensible Messaging and Presence Protocol)是基于可扩展标记语言(XML)的协议,多用于即时消息(IM)以及在线现场探测。适用于服务器之间的准即时操作。核心是基于XML流传输,这个协议可能最终允许因特网用户向因特网上的其他任何人发送即时消息,即使其操作系统和浏览器不同。
优点:通用公开、兼容性强、可扩展、安全性高,但XML编码格式占用带宽大
其他基于TCP/IP自定义的协议 有些特殊框架(如:redis、kafka、zeroMq等)根据自身需要未严格遵循MQ规范,而是基于TCP\IP自行封装了一套协议,通过网络socket接口进行传输,实现了MQ的功能。
四、MQ的通讯模式
1) 点对点通讯:点对点方式是最为传统和常见的通讯方式,它支持一对一、一对多、多对多、多对一等多种配置方式,支持树状、网状等多种拓扑结构。
2) 多点广播:MQ适用于不同类型的应用。其中重要的,也是正在发展中的是"多点广播"应用,即能够将消息发送到多个目标站点(Destination List)。可以使用一条MQ指令将单一消息发送到多个目标站点,并确保为每一站点可靠地提供信息。MQ不仅提供了多点广播的功能,而且还拥有智能消息分发功能,在将一条消息发送到同一系统上的多个用户时,MQ将消息的一个复制版本和该系统上接收者的名单发送到目标MQ系统。目标MQ系统在本地复制这些消息,并将它们发送到名单上的队列,从而尽可能减少网络的传输量。
3) 发布/订阅(Publish/Subscribe)模式:发布/订阅功能使消息的分发可以突破目的队列地理指向的限制,使消息按照特定的主题甚至内容进行分发,用户或应用程序可以根据主题或内容接收到所需要的消息。发布/订阅功能使得发送者和接收者之间的耦合关系变得更为松散,发送者不必关心接收者的目的地址,而接收者也不必关心消息的发送地址,而只是根据消息的主题进行消息的收发。在MQ家族产品中,MQ
Event Broker是专门用于使用发布/订阅技术进行数据通讯的产品,它支持基于队列和直接基于TCP/IP两种方式的发布和订阅。
4) 群集(Cluster):为了简化点对点通讯模式中的系统配置,MQ提供Cluster(群集)的解决方案。群集类似于一个域(Domain),群集内部的队列管理器之间通讯时,不需要两两之间建立消息通道,而是采用群集(Cluster)通道与其它成员通讯,从而大大简化了系统配置。此外,群集中的队列管理器之间能够自动进行负载均衡,当某一队列管理器出现故障时,其它队列管理器可以接管它的工作,从而大大提高系统的高可靠性
五、IBM WebSphere MQ概念介绍(服务安装、配置略)
注:服务端安装完成后,创建列管理器时出错:AMQ8135:未授权,表明必须要用adminstrator管理员帐号创建运行。
我们把队列管理器比作是数据库,那么队列就是其中的一张表,消息就是表中的一条记录。
- 队列:我们可以简单地把队列看成一个容器,用于存放消息。
- 队列管理器:队列管理器构建了独立的 MQ 的运行环境,它是消息队列的管理者,用来维护和管理消息队列。
- 消息:MQ中的最小对象;默认情况下,消息缺省可以达到 4MB。消息可以分成持久消息和非持久消息。所 谓“持久”的 意思,就是在MQ 队列管理器重启动后,消息是否仍然能保持。持久的消息写入或读出队列的同时会在 Log 中记录,所以性能上比非持久消息差不少。
- 通道:通道则是两个队列管理器之间的一种单向的点对点的通信连接, 消息在通道中只能单向流动。队列管理器之间的通信是通过配置通道来实现 的,通道两侧的队列管理器对这个通道的相关参数应该能对应起来。在通道上可以配置不同的通信协议,这样就使得编程接口与通信协议无关。通道两端的 配置必须匹配, 且名字相同,否则无法连通。
- RUNMQSC:命令行交互界面管理工具;作为维护人员的我们,与MQ打交道有两种方式,一种是通过MQ提供的二进制命令工具(在mq安装目录的bin目录下),另一种方式则是通过命令行交互管理工具;这二者在功能上有很多是重合的,但并非完全可替代;RUNMQSC是一个通用的 MQ 对象管理工具,使用MQSC命令集可以对 MQ 对象进行;全方位的管理,也是各种管理方式最直接、最全面的一种。RUNMQSC 运行的命令集称MQSC (MQ Script Command)";在
RUNMQSC 中大小写无关,所有的命令会先转换成全大写再提交执行。所以如果要 表示大小相关的字串,比如对象名,则用引号将字串包住。输入以下命令启动MQSC命令:runmqsc[queueManagerName]
六、spring和IBM WebSphere MQ接收端集成配置
applicationContext-mq.xml:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jee="http://www.springframework.org/schema/jee" xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.5.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.0.xsd"> <jee:jndi-lookup id="jndiReciveQueueConnectionFactory" jndi-name="jms/recive/MQConnectionFactory" resource-ref="true"/> <!-- 接收方队列 --> <bean id="receiveQueue" class="org.springframework.jndi.JndiObjectFactoryBean"> <property name="jndiName"> <value>jms/MQReciver</value> </property> <property name="resourceRef" value="true"></property> </bean> <bean id="regulationApplicationContext" class="com.deppon.tps.core.bean.RegulationApplicationContext"></bean> <bean id="requestMessageListenerContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer"> <property name="concurrentConsumers" value="5" /> <property name="connectionFactory" ref="jndiReciveQueueConnectionFactory" /> <property name="destination" ref="receiveQueue" /> <property name="messageListener" ref="regulationApplicationContext" /> <property name="messageSelector" value="target='regulation-data'"></property> </bean> </beans>
context.xml(数据源)以下是tomcat配置:
注:jboss配置详见:http://blog.csdn.net/xpsharp/article/details/32163159
<?xml version="1.0" encoding="UTF-8"?> <Context> <WatchedResource>WEB-INF/web.xml</WatchedResource> <Resource name="jdbc/tpsds" auth="Container" type="javax.sql.DataSource" username="vehicle" password="nine-one" driverClassName="net.sf.log4jdbc.DriverSpy" url="jdbc:log4jdbc:oracle:thin:@192.168.68.91:1521:tpsdb" maxActive="4" maxIdle="2"/> <Resource name="jms/recive/MQConnectionFactory" auth="Container" type="com.ibm.mq.jms.MQQueueConnectionFactory" factory="com.ibm.mq.jms.MQQueueConnectionFactoryFactory" description="JMS Queue Connection Factory for sending messages" HOST="10.230.27.23" PORT="15201" CHAN="VTS.GET.CLIENT" TRAN="1" QMGR="QM_VTS_01"/> <Resource name="jms/MQReciver" auth="Container" type="com.ibm.mq.jms.MQQueue" factory="com.ibm.mq.jms.MQQueueFactory" description="JMS Queue for receiving messages" QU="VTS_IBM_MQ_01"/> </Context>
七、spring和IBM WebSphere MQ发送端集成配置
mq-spring.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.0.xsd"> <!-- 发送方链接工厂 --> <bean id="jndiSendQueueConnectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean"> <property name="jndiName"><value>jms/send/MQConnectionFactory</value></property> <property name="resourceRef" value="true" /> </bean> <!-- 发送方主题--> <bean id="sendQueue" class="org.springframework.jndi.JndiObjectFactoryBean"> <property name="jndiName"> <value>jms/MQSender</value> </property> <property name="resourceRef" value="true"></property> </bean> <!-- 整车、干线规则匹配发送方模板--> <bean id="<span style="color:#ff0000;">ruleMatchJmsSendTemplate</span>" class="org.springframework.jms.core.JmsTemplate"> <property name="connectionFactory" ref="jndiSendQueueConnectionFactory" /> <property name="defaultDestination" ref="sendQueue"></property> </bean> </beans>
context.xml (数据源)以下是tomcat配置:
注:jboss配置详见:http://blog.csdn.net/xpsharp/article/details/32163159
<?xml version="1.0" encoding="UTF-8"?> <Context> <!-- Default set of monitored resources --> <WatchedResource>WEB-INF/web.xml</WatchedResource> <Resource name="jdbc/tpsds" auth="Container" type="javax.sql.DataSource" username="vehicle" password="nine-one" driverClassName="oracle.jdbc.driver.OracleDriver" url="jdbc:oracle:thin:@192.168.68.91:1521:tpsdb" maxActive="4" maxIdle="2" /> <!--整车、干线匹配规则 mq发送方配置 --> <Resource name="jms/send/MQConnectionFactory" auth="Container" type="com.ibm.mq.jms.MQQueueConnectionFactory" factory="com.ibm.mq.jms.MQQueueConnectionFactoryFactory" description="JMS Queue Connection Factory for sending messages" HOST="10.230.27.23" PORT="15201" CHAN="VTS.PUT.CLIENT" TRAN="1" QMGR="QM_VTS_01"/> <Resource name="jms/MQSender" auth="Container" type="com.ibm.mq.jms.MQQueue" factory="com.ibm.mq.jms.MQQueueFactory" description="JMS Queue for sending messages" QU="VTS_IBM_MQ_01"/> </Context>
spring.xml
............ <bean id="mqSendDao" class="com.deppon.tps.module.orderManage.server.dao.impl.MqSendDaoImpl"> <property name="ruleMatchJmsSendTemplate" ref="ruleMatchJmsSendTemplate" /> </bean> <!--整车订单Service--> <bean id="vehicleOrderService" class="com.deppon.tps.module.orderManage.server.service.impl.VehicleOrderServiceImpl"> <property name="orderManageDaoImpl" ref="orderMangeDao" /> <property name="vehicleOrderDao" ref="vehicleOrderDao" /> <property name="mqSendDao" ref="mqSendDao" /> </bean>..................
程序实现:
package com.deppon.tps.module.orderManage.server.dao.impl; import java.lang.reflect.Field; import javax.jms.BytesMessage; import javax.jms.JMSException; import javax.jms.Message; import javax.jms.Session; import org.springframework.jms.core.JmsTemplate; import org.springframework.jms.core.MessageCreator; import org.springframework.util.SerializationUtils; import com.deppon.foss.framework.server.components.dataaccess.ibatis.iBatis3DaoImpl; import com.deppon.tps.core.bean.Cell; import com.deppon.tps.core.bean.Row; import com.deppon.tps.core.bean.Table; import com.deppon.tps.module.orderManage.server.dao.MqSendDao; public class MqSendDaoImpl extends iBatis3DaoImpl implements MqSendDao{ <span style="color:#ff0000;">private JmsTemplate ruleMatchJmsSendTemplate;</span> public void mqSend(Object orderCatchEntity){ Cell cell ; Row row = new Row(); Field[] fields = orderCatchEntity.getClass().getDeclaredFields(); try { for(Field field : fields) { cell = new Cell(); field.setAccessible(true); cell.setName(field.getName()); cell.setValue(field.get(orderCatchEntity)); row.add(cell); } } catch (SecurityException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } final Table table = new Table(); table.add(row); ruleMatchJmsSendTemplate.send(new MessageCreator() { public Message createMessage(Session session) throws JMSException { BytesMessage msg = session.createBytesMessage(); msg.setStringProperty("entrance", "logicPushRuleAnalyEntrance"); msg.setStringProperty("target", "regulation-data"); msg.writeBytes(SerializationUtils.serialize(table)); return msg; } }); } <span style="color:#ff0000;"> public void setRuleMatchJmsSendTemplate(JmsTemplate ruleMatchJmsSendTemplate) { this.ruleMatchJmsSendTemplate = ruleMatchJmsSendTemplate; }</span> }