关于activeMQ的一些问题总结

1.什么是ActiveMQ

ActiveMQ 是Apache出品,最流行的,能力强劲的开源消息中间件。
主要特点:
1. 多种语言和协议编写客户端
2. 完全支持JMS1.1和J2EE 1.4规范 (持久化,XA消息,事务)
3. 对Spring的支持,ActiveMQ可以很容易内嵌到使用Spring的系统里面去,而且也支持Spring2.0的特性
4. 通过了常见J2EE服务器的测试,其中通过JCA 1.5 resource adaptors的配置,可以让ActiveMQ可以自动的部署到任何兼容J2EE1.4商业服务器上
5. 支持多种传送协议
6. 支持通过JDBC和journal提供高速的消息持久化
7. 从设计上保证了高性能的集群,客户端-服务器,点对点
8. 支持Ajax
9. 支持与Axis的整合

10. 可以很容易得调用内嵌JMS provider,进行测试

MQ:消息队列

AcativeMQ是一种消息中间件(同类型其它中间件:rabitMQ/kafaka)

ActiveMQ的作用:

1.解决服务之间的耦合,实现系统间的异步通信,简化操作。

2.使用消息队列,增加系统并发处理量

3.解决大量访问造成拥堵问题

基于生产消费模型

生产者生产消息,把消息发送给activemq。Activemq接收到消息,然后查看有多少个消费者,然后把消息转发给消费者,此过程中生产者无需参与。

Activemq有两种通信方式点到点形式发布订阅模式(广播)。

1、 Queue  队列 ,生产者生产了一个消息,只能由一个消费者进行消费

2、 Topic 话题,生产者生产了一个消息,可以由多个消费者进行消费

如果是点到点模式的话,如果消息发送不成功此消息默认会保存到activemq服务端直到有消费者将其消费,所以此时消息是不会丢失的。

如果是发布订阅模式的通信方式,默认情况下只通知一次,如果接收不到此消息就没有了。可能出现消息丢失,这种场景只适用于对消息送达率要求不高的情况。。。。。。。。

如果要求消息必须送达不可以丢失的话,需要配置持久订阅。每个订阅端定义一个id,在订阅端向activemq注册。发布消息和接收消息时需要配置发送模式为持久化。此时如果客户端接收不到消息,消息会持久化到服务端,直到客户端正常接收后为止。

2.ActiveMQ实际工作应用场景

1、 用户注册,重点用户信息数据库保存,发短信、发邮件,增加业务处理复杂度,这时候使用MQ,将发短信、发邮箱,通知MQ,由另外服务平台完成

2、 搜索平台、缓存平台、索引库同步

查询数据,建立缓存、索引,不从数据库查询,从缓存或者索引库查询

当增加、修改、删除数据时,发送消息给MQ,缓存平台、索引平台从MQ获取到这个信息,更新缓存或者索引

3.使用方法

生产者//创建工厂连接,IP,端口,/开session创建目的地,,send即可发送到服务端(页面可看到)

消费者//创建工厂连接IP,端口 开session,创建目的地/消费者/get即可

Spring+active整合//配置文件配置工厂,bean(消息监听容器)

同步索引库:insert操作后,返回ok前,发布消息,传ID//消费:写个监听器取id—查询商品消息—(添加文档域)添加到solr索引库


4.生产者消费者模式的注意事项:

1.在创建生产者的时候可以不用开启连接,但是在消费者中一定要开启连接:connection.start();

2.建立会话>>>第一个参数为是否开启事物,如果选择了true,那么在最后要提交事务:

Session session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE);

最后要:session.commit();

3.直接消费的情况>>>等生产完了才开始消费

使用监听消费的情况>>>即监听是否生产了,生产一个立即消费一个

4.监听器启动之后,它会以一个额外的线程执行.

5.在测试类中,Junit结束后会强制退出所有线程.如果让监听器继续执行监听,可以不让Junit死掉.只需要加一行代码:while(true){};即可.

5.使用了activemq系统启动卡顿的解决办法:

<!-- 这个amq的标签因为本地没有,每次都要去线上找,所以导致系统启动卡住 -->
    <!-- <amq:connectionFactory id="amqConnectionFactory"
        brokerURL="tcp://localhost:61616" userName="admin" password="admin"  /> -->
        
    <!-- 另外一种解决办法 -->
    <bean id="amqConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
    	<property name="brokerURL" value="tcp://localhost:61616"></property>
    	<property name="userName" value="admin"></property>
    	<property name="password" value="admin"></property>
    </bean>

6.项目中使用activemq遇到的问题及怎么去解决

1.先讲严重的:服务挂掉。

这得从ActiveMQ的储存机制说起。在通常的情况下,非持久化消息是存储在内存中的,持久化消息是存储在文件中的,它们的最大限制在配置文件的<systemUsage>节点中配置。但是,在非持久化消息堆积到一定程度,内存告急的时候,ActiveMQ会将内存中的非持久化消息写入临时文件中,以腾出内存。虽然都保存到了文件里,但它和持久化消息的区别是,重启后持久化消息会从文件中恢复,非持久化的临时文件会直接删除。

那如果文件增大到达了配置中的最大限制的时候会发生什么?我做了以下实验:

设置2G左右的持久化文件限制,大量生产持久化消息直到文件达到最大限制,此时生产者阻塞,但消费者可正常连接并消费消息,等消息消费掉一部分,文件删除又腾出空间之后,生产者又可继续发送消息,服务自动恢复正常。

设置2G左右的临时文件限制,大量生产非持久化消息并写入临时文件,在达到最大限制时,生产者阻塞,消费者可正常连接但不能消费消息,或者原本慢速消费的消费者,消费突然停止。整个系统可连接,但是无法提供服务,就这样挂了

具体原因不详,解决方案:尽量不要用非持久化消息,非要用的话,将临时文件限制尽可能的调大。

详细配置信息见文档:http://activemq.apache.org/producer-flow-control.html

2、丢消息

这得从java的java.net.SocketException异常说起。简单点说就是当网络发送方发送一堆数据,然后调用close关闭连接之后。这些发送的数据都在接收者的缓存里,接收者如果调用read方法仍旧能从缓存中读取这些数据,尽管对方已经关闭了连接。但是当接收者尝试发送数据时,由于此时连接已关闭,所以会发生异常,这个很好理解。不过需要注意的是,当发生SocketException后,原本缓存区中数据也作废了,此时接收者再次调用read方法去读取缓存中的数据,就会报Software caused connection abort: recv failed错误。

通过抓包得知,ActiveMQ会每隔10秒发送一个心跳包,这个心跳包是服务器发送给客户端的,用来判断客户端死没死。如果你看过上面第一条,就会知道非持久化消息堆积到一定程度会写到文件里,这个写的过程会阻塞所有动作,而且会持续20到30秒,并且随着内存的增大而增大。当客户端发完消息调用connection.close()时,会期待服务器对于关闭连接的回答,如果超过15秒没回答就直接调用socket层的close关闭tcp连接了。这时客户端发出的消息其实还在服务器的缓存里等待处理,不过由于服务器心跳包的设置,导致发生了java.net.SocketException异常,把缓存里的数据作废了,没处理的消息全部丢失。

解决方案:用持久化消息,或者非持久化消息及时处理不要堆积,或者启动事务,启动事务后,commit()方法会负责任的等待服务器的返回,也就不会关闭连接导致消息丢失了。

关于java.net.SocketException请看详细研究:http://blog.163.com/_kid/blog/static/3040547620160231534692/

3.持久化消息非常慢。

默认的情况下,非持久化的消息是异步发送的,持久化的消息是同步发送的,遇到慢一点的硬盘,发送消息的速度是无法忍受的。但是在开启事务的情况下,消息都是异步发送的,效率会有2个数量级的提升。所以在发送持久化消息时,请务必开启事务模式。其实发送非持久化消息时也建议开启事务,因为根本不会影响性能。

4.消息的不均匀消费。

有时在发送一些消息之后,开启2个消费者去处理消息。会发现一个消费者处理了所有的消息,另一个消费者根本没收到消息。原因在于ActiveMQ的prefetch机制。当消费者去获取消息时,不会一条一条去获取,而是一次性获取一批,默认是1000条。这些预获取的消息,在还没确认消费之前,在管理控制台还是可以看见这些消息的,但是不会再分配给其他消费者,此时这些消息的状态应该算作“已分配未消费”,如果消息最后被消费,则会在服务器端被删除,如果消费者崩溃,则这些消息会被重新分配给新的消费者。但是如果消费者既不消费确认,又不崩溃,那这些消息就永远躺在消费者的缓存区里无法处理。更通常的情况是,消费这些消息非常耗时,你开了10个消费者去处理,结果发现只有一台机器吭哧吭哧处理,另外9台啥事不干。

解决方案:将prefetch设为1,每次处理1条消息,处理完再去取,这样也慢不了多少。

详细文档:http://activemq.apache.org/what-is-the-prefetch-limit-for.html

5.死信队列。

如果你想在消息处理失败后,不被服务器删除,还能被其他消费者处理或重试,可以关闭AUTO_ACKNOWLEDGE,将ack交由程序自己处理。那如果使用了AUTO_ACKNOWLEDGE,消息是什么时候被确认的,还有没有阻止消息确认的方法?有!

消费消息有2种方法,一种是调用consumer.receive()方法,该方法将阻塞直到获得并返回一条消息。这种情况下,消息返回给方法调用者之后就自动被确认了。另一种方法是采用listener回调函数,在有消息到达时,会调用listener接口的onMessage方法。在这种情况下,在onMessage方法执行完毕后,消息才会被确认,此时只要在方法中抛出异常,该消息就不会被确认。那么问题来了,如果一条消息不能被处理,会被退回服务器重新分配,如果只有一个消费者,该消息又会重新被获取,重新抛异常。就算有多个消费者,往往在一个服务器上不能处理的消息,在另外的服务器上依然不能被处理。难道就这么退回--获取--报错死循环了吗?

在重试6次后,ActiveMQ认为这条消息是“有毒”的,将会把消息丢到死信队列里。如果你的消息不见了,去ActiveMQ.DLQ里找找,说不定就躺在那里。

详细文档:http://activemq.apache.org/redelivery-policy.html

http://activemq.apache.org/message-redelivery-and-dlq-handling.html


猜你喜欢

转载自blog.csdn.net/weixin_41768263/article/details/80524329