RabbitMQ实践建议-摘抄

1.虚拟主机

   虚拟主机(Virtual Host ,在RabbitMQ中叫做 vhost )是AMQP 协议里面的一个基本概念。客户端在连接消息服务器时必须制定一个虚拟主机。本质上讲,虚拟主机就是一台缩小版的RabbitMQ服务器,其内部拥有自己的队列、交换器、绑定等,比较特别的RabbitMQ中的权限控制是以vhost为单位的,也就是说,消息客户端在访问时不能把vhost A中的交换器绑定到vhost B中这事 RabbliMQ的一个很重要的设计。因此,在实际场景中可以用一台RabbitMQ服务器服务多个不同的应用,应用通过不同的虚拟主机提供访问消息时逻辑上的隔离,从而为应用程序提供安全访问,这种方式既能把同一台RabbitMQ服务器的不同业务应用区分开,又可以避免其内部队列,交换器的命名冲突。

 建议在使用RabbitMQ是仔细梳理系统中的不同业务,并为他们分配自己的vhost;

2.消息保存

   RabbitMQ 对于queue中的消息保存方式分为disk 和 RAM两种方式,disk就是写入磁盘,也就是通常所理解的持久化,这种方式的好处就是在发生系统意外宕机的情况时,原来的消息数据可以在系统重启的时候恢复。根据官网的介绍,RabbitMQ在两种情况下会将数据消息写入磁盘,一是在发布消息时明确需要写入磁盘,二是当消息服务器内存紧张的时候会将部分内存中的消息转移到磁盘。采用disk方式,消息数据会被保存在.rdq后缀名的文件中,当文件达到一定大小(默认是16777216字节,即16兆)时会生成一个新的文件,当文件中的已经被删除的消息比例大于阈值时会触发文件合并操作,以提升磁盘利用率。采用RAM方式,只是在RAM中保存内部数据库表数据,而不会保存消息、消息存储索引、队列索引和其他节点状态等数据,所以必须在启动是从集群中的其他节点同步原来的消息数据,这也就意味着集群中必须包含至少一个disk方式的节点,正因为这样,所以不能手工删除集群中的最后一个disk节点,在绝大部分的情况下,对消息相关数据的保存采用disk方式,如果有其他高可用手段保证,则可以选中RAM方式,以提升消息队列的工作效率。

    消息持久化涉及Queue、Message、Exchange三部分, 

  1. Queue持久化: Queue持久化是通过设置durable为true来实现的,
  2. Message持久化:com.rabbitmq.client.MessageProperties ,在channle 接口中的 basicPublish 中设置为 PERSISTENT_TEXT_PLAIN表示需要持久化消息
  3. Exchange持久化:将durable设置为true

3.消息确认模式

     如何确保生产者消息准确发送到Broker中(注:如果消息到达Broker之前发生宕机或者在数据没有在Broker中持久化之前发生宕机)RabbitMQ 提供了两种解决方式 ----> 一通过AMQP协议的事务机制,二是把信道设置成确认模式。

     不要将AMQP协议中的事务和数据库事务混淆,在AMQP中当信道设置为事务模式之后,生产者和Broker之间会有一种发送/相应机制判断当前命令操作是否可以继续,不过,由于事务模式需要生产者应用同步等待Broker的执行结果,在性能上会有很大降低消息服务器的吞吐量,解决方案偏重一些,所以不建议这种模式。

     发送确认模式是RabbitMQ对AMQP的拓展实现,在2.3.1以上的版本中可用,把信道设置成确认模式之后,在该信道上发布的所有信息都会被分配一个唯一的ID,一旦消息被投递到多有匹配的队列中,该信道就会向生产者发送确认消息,在确认消息中包含了之前的唯一ID,从而让生产者知道消息已经到达队列,发送确认的方式最大的有点是“异步”,性能影响较小。

     设置确认模式可以调用信道的confirmSelect方法,不过 确认模式和 事务模式不能共存,设置生产者确认模式有三种方法

  •  普通确认:每次发送消息后,就调用waitForConfirms方法等待Broker的确认消息,本质上就是串行方式确认。缺点:需要线程数多
  • 批量确认:每发完一批消息之后,调用waitForConfirms方法等待Broker的确认,缺点:出现错误时需要批量重新发送会出现数据重复的问题,无法解决
  • 异步确认:通过调用addConfirmListener方法注册回调,在Broker确认了一条或者多条消息之后由客户端回调该方法。缺点:每个信道需要维护一个尚未确认的消息集合,当消息来的时候需要消息总数+1,当客户端回调之后在-1。

4.消费者应答

       消费应答是解决Broker将消息发送到consume回发生消息没有准确处理的问题,消费者回执(consumer AckKonwLedgement) 。在实际应用中可能会发生消费者在接受消息的时候没有处理完就宕机,导致消息丢失的问题,可以要求消费者在消费完成后发送一个回执到RabbitMQ 服务器,RabbitMQ服务器收到回执后再将该消息从队列中删除,如果没有收到回执并且监测到消费者与RabbitMQ服务器的连接断开,则有RabbitMQ服务器扶着发消息发送到其他消费者(如果有多个消费者的情况下)。

  1. 两种消息回执模式:自动回执 / 手动回执  自动回执:当Broker发送消息到Consumer之后自动删除消息。手动回执: 当Broker发送消息到消费者之后并不会立即把消息删除,而是等到消费者会送的确认消息后在删除,消费者处理完成之后回向Broker发送ACK指令如果消费者因为意外没有返回ACK ,Broker会将消息保存起来或者发送给其他消费者
    //是否开启自动回执模式,是由消费消息时嗲用basicConsume方法的入参autoAck决定。当autoAck为true时候 == 自动触发 当autoAck为false == 手动触发
    
    String basicConsume(String queue,boolean autoAck,String consumerTag,Consumer callback)throws IOException
  2. 拒绝消费:当消费者处理失败或者拒绝处理消息时,可以给Broker发送拒绝消息的指令,并且可以要求Broker将消息丢弃或者重新放回队列中,两种方式 “拒绝一条” 或者 “拒绝多条” 
    /**
    * 拒绝消息被定义在 com.rabbitmq.client.Channel 中
    */
    /**
    * 对一条消息进行拒绝
    * #param deliveryTag 发布的消息都有一个唯一的deliveryTag 他在channel范围内唯一
    * @param requeue 表示如何处理这条消息,true 表示重新放入RabbitMQ中 false 表示通知RabbitMQ销毁这条消息
    */
    void basicReject(long deliveryTag,boolean requeue) throws IOException
    
    
    /**
    * 对一条消息进行拒绝
    * @param multiple 批量确认标志,true 表示包含当前消息在内的 ,一批消息 
    * #param deliveryTag 发布的消息都有一个唯一的deliveryTag 他在channel范围内唯一
    * @param requeue 表示如何处理这条消息,true 表示重新放入RabbitMQ中 false 表示通知RabbitMQ销毁这条消息
    */
    void basicNack(long deliveryTag,boolean multiple,boolean requeue)throws IOException

       3.消息预取:可以通过设置预取数量(Prefetch Count )限制每个消费者在收到下一个确认回执前一次最多可以接受多少条消息

//可以通过com.rabbitmq.client.Channel 接口中的basicQos方法 prefetchCount 设置预取数量


void basicQos(int prefetchSize,int prefetchCount,boolean global) throws IOException;

void basicQos(int prefetchCount,boolean global) throws IOException;

void basicQos(int prefetchCount) throws IOException;

//不要设置无限制的预取数量,浙江导致消费者接受所有的消息,导致内存耗尽,然后消息又被重新推送。合理分配

5.流控机制

     RabbitMQ使用流控(Flow control)机制来确保稳定性,由于Erlang进程之间并不共享内存,而是通过传递消息来通信,所以每个进程都有自己的进程邮箱(mailbox)。因为Erlang默认不会对mailbox的大小设置限制,所以有大量的消息发送到某个进程中,将导致该mailbox过大,最终内存溢出、进程崩溃。所以在RabbitMQ中如果生产者告诉发送消息,而消费者消费的速度又低于生产者发送的速度,没有流控很快就使内部mailbox达到阈值限制,从而阻塞生产者的操作(因为有Block机制,所以进程不会崩溃),然后RabbitMQ会进行换页操作,把内存中的数据持久化到磁盘上。

    为了解决这个问题,RabbitMQ使用一种基于信用证的流控机制,在消息处理进程内部又一个信用组(InitialCredit,MoreCreditAfter)表示在生产者进程中对应于某个消费者的初始credit和消费者要返回给生产者credit。

6.通道

   消息客户端和消息服务器之间的通信是双向的,不管是对客户端还是服务器来说,保持他们之间网络连接是很消耗资源的,为了不占用大量的TCP/IP连接的情况下能有大量的逻辑连接,AMQP增加了通道(channel)概念,在RabbitM支持并鼓励在一个连接中创建多个通道,因为相对来说创建和销毁通道的代价会更小,需要提醒的是,作为经验法则,应该尽量避免在线程之间共享通道,你的应用应该使用每个线程单独的通道,而不是在多个线程上共享,同一个通道,因为大多数客户端不会让通道线程安全

 

总结:

   RabbitMQ最大的优势在于提供了比较灵活的消息路由策略,高可用,可靠性,已经丰富的插件,多种平台支持和完善的文档

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值