activeMq的面试题

转载自http://www.javashuo.com/article/p-rjxagmxh-eg.htmljava

1、activemq服务器宕机怎么办?

        这得从activemq的存储机制提及。在一般的状况下,非持久化消息是存储在内存中的,持久化消息是存储在文件中的,他们的最大限制在配置文件的<systemUsage> 节点中配置。可是在非持久化消息堆积到必定程度,内存告急的时候,activemq会将内存中的非持久化消息写入临时文件中,以腾出内存。缓存

       虽然都保存到了文件里,但它和持久化消息的区别是:重启后持久化消息会从文件中恢复,非持久化的临时文件会直接删除。安全

       那若是文件增大到达了配置中的最大限制的时候会发生什么?我作了如下实验:服务器

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

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

       解决方案:尽可能不要使用非持久化消息,非要用的话,将临时文件限制尽量的调大。并发

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异常,把缓存中的数据做废了,没处理的消息所有丢失。socket

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

3、持久化消息很是慢

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

4、消息的不均匀消费

     有时在发送一些消息以后,开启了两个消费者去处理消息。会发现一个消费者处理了全部的消息,另外一个消费者根本没收到消息。缘由在于activemq的prefetch机制。当消费者去获取消息时,不会一条一条企业获取,而是一次性的获取一批,默认是1000条。这些预获取的消息,在还没确认消费以前,在管理控制台仍是能够看见这些消息的,可是不会再分配给给其余消费者,此时这些消息的状态应该算做“已分配为消费”,若是消息最后被消费,则会在服务器被删除,若是消费者崩溃,则这些消息会被从新分配给新的消费者。可是若是消费者既不消费确认,又不崩溃,那这些消息就永远躺在消费者的缓冲区里没法处理。更一般的状况是,消费这些消息很是耗时,你开了10个消费者去处理,结果发现只有一台机器处理,另外九台啥事不干。

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

5、死信队列

     若是你想在消息处理失败后,不被服务器删除,还能被其余消费者处理或者重试,能够关闭AUTO_ACKNOWLEDGE,将ack交由程序本身处理。那若是使用了AUTO_ACKNOWLEDGE,消息是何时确认的,还有没有阻止消息确认的方法?有!

    消费消息有2种方法:一种是调用consumer.receive()方法,该方法将阻塞直到得到并返回一条信息。这种状况下,消息返回非方法调用者以后就自动被确认了。另外一种方法就是采用listener回调函数,在有消息到达时,会调用listener接口的onMessage方法。在这种状况下,在onMessage方法执行完毕后,消息才会被确认,此时只要在方法中抛出异常,该消息就不会被确认。

    那么问题来了,若是一条消息不能被处理,UI被退回到服务器从新分配,若是只有一个消费者,该消息又从新被获取,从新抛异常。就算有多个消费者,每每在一个服务器上不能处理的消息,在另外的服务器上依然不能被处理。难道就这么退回-获取-报错死循环吗?

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

6、ActiveMQ中有消息重发时间间隔和重发次数吗?

     ActiveMQ:是Apache出品,最流行的,能力强劲的开源消息总线。是一个彻底支持JMS1.1和j2ee 1.4规范的JMS Provider实现。

    JMS(java消息服务):是一个java平台中关于面向消息中间件(MOM)的API,用于在两个应用程序之间,或分布式系统中发送消息,进行异步通讯。

     首先,咱们的大概了解下,在哪些状况下,ActiveMQ服务器会将消息发给消费者,这里为简单起见,假定采用的消息发送模式为队列(即消息发送方和消息接收方)。

    1.若是消息接收者在处理完一条消息的处理过程后没有对MOM进行应答,则该消息将由MOM重发

    2.若是咱们队某个队列设置了预读参数(consumer.prefetchSize),若是消息接收者在处理第一条消息时(没向MOM发送消息接收确认)就宕机了,则预读数量的全部消息都将被重发!

    3.若是Session是事务的,则只要消息接收方有一条消息没有确认接收,或发送消息期间MOM或客户端某一方忽然宕机,则该事务范围中的全部消息MOM都将重发。

    4.说到这里,你们可能会有疑问,ActiveMQ消息服务器怎么知道消费者客户端是消息正在处理中还没来得急对消息进行应答仍是已经处理完成了没有应答或是宕机了根本没机会应答呢?其实在全部的客户端机器上,内存中都运行着一套客户端的ActiveMq环境,该环境负责缓存发来的消息,赋值维持着和ActiveMQ服务器的消息通信,负责失效转移(fail-over)等,全部的判断和处理都是由这套客户端环境来完成的。

       咱们能够对ActiveMq的重发策略(Redelivery Policy)来进行自定义配置,其中的配置参数主要有如下几个:

      

 可用属性
属性 默认值 说明
collisionAvoidanceFactor 0.15 设置防止冲突范围的正负百分比,只有启用useCollisionAvoidance参数时才生效。
maximumRedeliveries 6 最大重传次数,达到最大重连次数后抛出异常。为-1时不限制次数,为0时表示不进行重传。
maximumRedeliveryDelay  -1 最大传送延迟,只在useExponentialBackOff为true时有效(V5.5),假设首次重连间隔为10ms,倍数为2,那么第二次重连时间间隔为 20ms,第三次重连时间间隔为40ms,当重连时间间隔大的最大重连时间间隔时,之后每次重连时间间隔都为最大重连时间间隔。
initialRedeliveryDelay 1000L 初始重发延迟时间
useCollisionAvoidance false 启用防止冲突功能,由于消息接收时是可使用多线程并发处理的,应该是为了重发的安全性,避开全部并发线程都在同一个时间点进行消息接收处理。全部线程在同一个时间点处理时会发生什么问题呢?应该没有问题,只是为了平衡broker处理性能,不会有时很忙,有时很空闲。
useExponentialBackOff false  启用指数倍数递增的方式增长延迟时间。
 backOffMultiplier  5 重连时间间隔递增倍数,只有值大于1和启用useExponentialBackOff参数时才生效。