ActiveMQ简介

ActiveMQ是Apache开源基金会研发的消息中间件,是完全支持  JMS 和 J2EE 规范的  JMS provider实现

ActiveMQ是主要应用在分布式系统架构当中的,帮助构建高性能,高可用性,可伸缩的企业级面向消息服务的系统。

 

ActiveMQ可以应用在流量消除峰值,数据流量特别大的情况下,如阿里双十一。

像那种不是和正常的业务逻辑特别相关联的处理场景,这个时候,我们可以对问题进行解耦合操作,比如说在操作订单的系统之后,需要对库存也进行操作,我们就需要对流量进行消峰处理。

 

首先我们在 activeMQ的官方网站下载  activeMQ的linux版本(tar.gz结尾的文件),http://activemq.apache.org/activemq-5153-release.html

然后通过  sftp 服务传送到 linux服务器上,然后解压缩文件,来到bin目录下启动activeMQ  sh activemq start

ps -ef|grep activemq检查启动状态,记得关闭centos的防火墙   systemctl stop firewalld.service

查看 activemq启动日志可以使用下面的命令:

tail -100f ../data/activemq.log

 

然后在另外一台机器上访问    http://ipaddr:8161/  出现下面的界面则说明  activeMQ安装并且启动成功,注意 activeMQ的默认端口号是 8161

conf目录下有一个文件  jetty.xml   看到里面有 <bean id="jettyPort"> ,然后可以更改里面的端口号,变成自己想要的
 

进入 Manage ActiveMQ broker输入账号和密码:默认账号和密码都是 admin

 

JMS的基本概念:

概念:

    java消息服务(Java Message Service),是java平台当中关于面向消息中间件的api,用于在两个应用程序之间或者分布式系统中发送消息,进行异步通信,JMS是一个与pigtail无关的API,支持 MOM(Message Oriented Middleware)(面向消息中间件),提供商都对JMS提供了支持。

    JMS定义了两种消息传递域:

     点对点:

        1.每个消息只能有一个消费者    

        2.消息产生者和消息消费者之间没有时间上的相关性,无论消费者在生产者发送消息的时候是否处于运行状态,都可以提取消息。

        3.我们可以在 activeMQ的控制台查看消息的消费,查看被哪些线程消费了,怎么消费的。

 发布订阅:
一个消息发送端发送了消息,很多个消息消费端进行消息的消费.
1.每个消息可以有多个消费者
2.消费的生产者和消费者之间存在时间上的相关性,订阅一个主题的消费者只能消费自它订阅之后发布的消息,而它往期的消息却无法收到,JMS规范允许客户端
   创建持久订阅.
3.JMS  API,
ConnectionFactory   连接工厂
Connection     封装客户端与JMS Provider之间的一个虚拟连接

Session 生产和消费消息的一个单线程上下文,用于创建 producer、consumer、message、queue

Destination      消息发送或者接收的目的地。
MessageProducer/Message consumer    消息生产者

JMS的消息只有被确认之后,才会认为是被成功消费,消息消费包含三个阶段:客户端接收消息,客户端处理消息,消息被确认

事务性会话:

        Session session = connection.createSession( Boolean.TRUE,Session.AUTO_AcknowLEDGE );  //当第一个参数设置成 true的时候,消息会在session.commit之后自动签收,只要没有签收,快递消息就一直存在。

非事务性会话

    Session session = connection.createSession(Boolean.FALSE,Session.AUTO_ACKNOWLEDGE);

    在该模式下,消息何时被确认取决于创建会话的时候的应答模式

    AUTO_ACKNOWLEDGE
当客户端成功从 receive方法中返回后,或者[MessageListener.onMessage]方法成功返回后,会话会自动确认该消息

注意一下,在消费消息的过程当中, receive方法和 MessageListener 这两种方法不能够同时工作。

    CLIENT_ACKNOWLEDGE 
客户端通过调用消息的  textMessage.acknowledge();确认消息

在这种模式中如果一个消息消费者消费一共是10个消息,那么消费了5个消息,然后在第5个消息通过 textMessage.acknowledge(),那么之前的消息全部都会被确认

DPUS_OK_ACKNOWLEDGE     延迟确认

 

activemq中的queue和topic的对比和区别:

 

类型

Topic

Queue

概要

Publish Subscribe messaging 发布订阅消息

Point-to-Point 点对点

有无状态

topic数据默认不落地,是无状态的。

Queue数据默认会在mq服务器上以文件形式保存,比如Active MQ一般保存在$AMQ_HOME\data\kr-store\data下面。也可以配置成DB存储。

完整性保障

并不保证publisher发布的每条数据,Subscriber都能接受到。

Queue保证每条数据都能被receiver接收。

消息是否会丢失

一般来说publisher发布消息到某一个topic时,只有正在监听该topic地址的sub能够接收到消息;如果没有sub在监听,该topic就丢失了。

Sender发送消息到目标Queue,receiver可以异步接收这个Queue上的消息。Queue上的消息如果暂时没有receiver来取,也不会丢失。

消息发布接收策略

一对多的消息发布接收策略,监听同一个topic地址的多个sub都能收到publisher发送的消息。Sub接收完通知mq服务器

一对一的消息发布接收策略,一个sender发送的消息,只能有一个receiver接收。receiver接收完后,通知mq服务器已接收,mq服务器对queue里的消息采取删除或其他操作。

  topic的使用案例如下:

一个发送端topicsender:

https://github.com/q907364606/activemq_learning/blob/master/provider/src/main/java/com/gupao/vip/mic/dubbo/jms/JmsTopicSender.java

两个接收端的 topicreceiver

https://github.com/q907364606/activemq_receiver/blob/master/order-provider/src/main/java/com/gupao/vip/mic/dubbo/jms/JmsTopicReceiver.java

https://github.com/q907364606/activemq_receiver/blob/master/order-provider/src/main/java/com/gupao/vip/mic/dubbo/jms/JmsTopicReceiver2.java

 

运行  TopicReceiver和TopicReceiver2的主方法,线程会阻塞在   consumer.receive() 这个方法上,等待消息进来。

在运行  TopicSender 的主方法,看到两个receiver接收到消息。

如果消息接收端是在 发送端发送完消息之后再去监听,那么接收端是接收不到消息的。

 

 

activeMQ的持久订阅:

持久订阅设置  connection中相同的连接id,ClientId 以及相同的订阅名

持久订阅的使用场景是在 消费端当在某些情况下不可用了当机了,但是中间的消息不能丢失,接下来后来启动的消息仍然可以消费的。

持久订阅发送端topicsender:

https://github.com/q907364606/activemq_learning/blob/master/provider/src/main/java/com/gupao/vip/mic/dubbo/jms/JmsTopicSender.java

持久订阅接收端的 topicreceiver

https://github.com/q907364606/activemq_receiver/blob/master/order-provider/src/main/java/com/gupao/vip/mic/dubbo/jms/JmsTopicPersistenteReceiver.java

 

持久订阅要先发起一个订阅

在receiver当中设置了  ClientId("dubbo-order");     和      session.DurableSubscriber(topic,"DUBBO-ORDER");

然后在消息发送端发送topic,不管消息接受端什么时候启动,都可以接收到消息,之前通过消息发送端发送的消息也都可以接受得到。

 

 

 

 

 

JMS  

PUB/SUB模型

1.订阅分为非持久订阅和持久订阅。

2.当所有的消息必须接收的时候,则需要用到持久订阅,则用非持久订阅。

P2P模型

特点:

1.如果session关闭时,有一些消息已经被收到,但是还没有被签收,那么当消费者下次连接到相同的队列时,消息还会被签收。

2.如果用户在receiver方法中设定了消息选择条件,那么不符合条件的消息会留在队列中不会被接收。

3.队列可以长久保存消息直到消息被消费者签收,消费者不需要担心因为消息丢失而时刻与jms proivider保持连接状态。

 

 

 

 

Broker:

其实启动的一个 activeMq就是一个  Broker的实例,可以将activeMq的 请求端和 服务端都连接到  Broker 服务上面。

Broker代码如下:

https://github.com/q907364606/activemq_learning/blob/master/provider/src/main/java/com/gupao/vip/mic/dubbo/jms/DefineBrokerServer.java

然后将sender 和  receiver都注册过来:

sender:

https://github.com/q907364606/activemq_learning/blob/master/provider/src/main/java/com/gupao/vip/mic/dubbo/jms/JmsSender.java

receiver:

https://github.com/q907364606/activemq_receiver/blob/master/order-provider/src/main/java/com/gupao/vip/mic/dubbo/jms/JmsReceiver.java

 

 

 

ActiveMQ当中支持的传输协议有下面的这些:

client端的  broker 端的通讯协议

TCP、UDP、NIO、SSL、Http、VM

 

 

ActiveMQ的持久化存储:

有四种持久化存储方式:   KahaDB Message Store(默认), AMQ  Message Store、使用Jdbc来持久化消息、MemoryMessage Store 基于内存的默认存储方式

在conf目录下的  activemq.xml 文件中  <persistenceAdapter></persistenceAdapter>中可以看出默认的存储策略是 kahaDB

如果要配置成  AMQ的方式需要这样配置:   AMQ的方式写入速度快,容易恢复

<amqPersistenceAdapter></amqPersistenceAdapter drrectory="" maxFileLength="">  <!--消息存储的directory路径  maxFileLength指定文件大小默认32m-->

JDBC基于数据库的存储

在 <persistenceAdapter></persistenceAdapter> 中加上这样的配置.
<jdbcPersistenceAdapter dataSource="#mysqlDataSource" createTablesOnStartup="true" /> 
<!--  createTablesOnStartup="true" 这个属性的目的是是否在加载activeMQ的时候初始化加载数据库  
dataSource="#mysqlDataSource"   注意这里必须要加上 # 这个参数
-->

        然后再在 activemq.xml文件中配置这样的内容
<bean id="mysqlDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" >
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/test"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>

然后在 activemq中的lib目录下添加下面的几个  jar 包,因为要用来连接 mysql 数据库所以要添加驱动包

commons-dbcp-1.4.jar,commons-pool-1.6.jar,mysql-connector-java-5.1.35.jar

然后到bin目录下重新启动 activeMQ ,   sh activemq restart

     启动的时候报错可以到  activemq下的 data目录下的  activemq.log  这个文件中查看启动的出错日志
配置了 mysql的数据库连接之后 我们看到生成了三张表
ACTIVEMQ_ACKS    存储持久订阅的信息
ACTIVEMQ_LOCK 锁表(用来做集群的时候,实现master选举的表)
ACTIVE_MSGS 消息表

JDBC Message store with activeMQ  journal

 

 

利用  activemq进行集群的操作,

首先我们在 activemq当中将 持久化的策略改成 kahadb的方式进行持久化

在另外一台机器上也安装  activemq ,并且将activemq开启,在 activemq.xml 的配置文件中增加下面的配置

<networkConnectors>
                <networkConnector uri="static://(tcp://192.168.159.136:61616,tcp://192.168.159.135:61616)" />
        </networkConnectors>

然后再重新启动两台  activemq,便可以实现集群

测试集群:

发送端  JmsSender的地址改成这个

"tcp://192.168.159.136:61616"
    接收端 JmsReceiver 的地址改成这个  

 
"tcp://192.168.159.135:61616"
     然后运行两个端,可以看到从 136 发送过来的数据 135可以消费消息

 

activemq当中丢失的消息,需要使用消息回流来解决、

 

 

在这种情形下消息的状态其实是A服务器中的activemq当中没有消息,而B服务器中的activemq当中有2条消息,所以当 A下面的消费
者想要消费 消息的时候这个时候是消费不到的,因为消息丢失,
为了解决这个问题,我们需要使用消息回流

为了能够让消息回流,需要在activemq.xml当中进行配置,在  <policyEntries></policyEntries>当中需要增加一个配置

  <!--  设置消息回流  -->

<policyEntry queue=">" enableAudit="false" ><!--  设置成false之后它认为消息可以被继续消费   -->
     <networkBridgeFilterFactory>
          <conditionalNetworkBridgeFilterFactory replayWhenNoConsumers="true" /> 
     </networkBridgeFilterFactory>
</policyEntry>  

配置了消息回流之后,发布出去的消息,不管怎样都可以在两边的消费者之间都可以消费

 

消息的发送策略:

持久化消息

默认情况下,生产者发送的消息是持久化的,消息发送到 broker之后,producer会等待broker对这条消息处理情况的反馈

可以设置消息发送端持久化消息的异步模式。

connection.setUserAsyncSend(true);

回执窗口大小设置:

connectionFactory.setProducerWindowSize();     //表示的当消息发送者发送的消息累积到某个大小以后,必须要等待服务器消息的回执,回执完消息递减,

非持久化消息

textMessage.setJMSDeliveryMode( DeliveryMode.NON_PERSISTENT);//设置为非持久化消息

非持久化消息模式下,默认就是异步的发送过程(  producer发送消息不需要等待 broker 的返回值 )

connectionFactory.setAlwaysSyncSend();

默认情况下,mq服务器(broker)采用异步方式向客户端主动推送消息(push),也就是说broker在向某个消费者会话推送消息后,不会等待消费者响应消息,指导消费者处理消息,完成后,主动向broker返回处理结果。

prefetchsize:

 预取消息数量:

 broker端一旦有消息,就主动按照默认的设置规则推送给当前活动的消费者,每次推送都有一定的数量限制,而这个数量就是prefetchSize,持久化消息的Queue

持久化消息的 Queue,默认的perfetchSize="1000",  非持久化消息  1000

topic   持久化消息 100   非持久化消息  32766

 

假如  prefetchSize=0

“预取消息数量”

此时对于 consumer来说就是一个pull模式

prefetchSize在这个地方设置  Destination destination = session.createQueue("first-queue?customer.prefetchSize=100");

 

optimizeAcknowledge  开启优化 ACK,批量提交

默认情况下  prefetchSize*0.65 的时候执行以下批量的确认

optimizeAcknowledge 可以在创建activemq连接的时候进行设置如下语句

ConnectionFactory factory = new ActiveMQConnectionFactory("tcp://192.168.159.138:61616?jms.optimizeAcknowledge=true&jms.optimizeAcknowledgeTimeOut=10000");

prefetchSize 和 optimizeAcknowledge 两者协同工作可以达到批量确认消息和批量获取消息。

一方面能够减少客户端在获取消息的阻塞次数,另外一方面还能减少获取消息时候的网络通信开销.

 

 

消息确认:

ACK_TYPE,消费端和broker交换ack指令的时候,还需要告知 broker ACK_TYPE

ACK_TYPE 表示确认指令的类型,broker可以根据不同的 ACK_TYPE,去针对当前消息做不同的应对策略。

REDELIVERED_ACK_TYPE  (broker会重新发送该消息)重发策略。

DELIVERED_ACK_TYPE,消息已经接收,但是尚未处理结束。

STANDARD_ACK_TYPE  消息处理成功

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值