rabbitmq技术预研

rabbitmq学习

RabbitMQ技术预研

编辑 审核 批准 日期

目录
1 概述 4
1.1 项目背景 4
1.2 项目目标 4
1.3 项目范围 4
1.4 参考资料 4
2 产品介绍 4
2.1 技术简介 4
2.2 功能特点 4
2.3 技术架构 4
2.4 逻辑架构 4
2.5 运行架构 4
2.6 源代码 5
3 安装与维护 5
3.1 安装 5
3.2 维护 5
4 策略设计 5
4.1 验证工具 5
4.2 验证方法 5
4.3 验证流程 5
5 环境设计 5
5.1 网络拓扑图 5
5.2 部署视图 5
5.3 环境参数 5
6 场景设计 6
7 执行计划 6
8 验证结果 6
9 应用实践 6
10 总结 6

1
RabbitMQ的简介与技术架构
1.1RabbitMQ简介(是什么?能干什么?)
简而言之: RabbitMQ是采用Erlang语言实现AMQP(高级消息队列协议)的消息中间件
AMQP协议: AMQP 说到底还是一个通信协议,通信协议都会涉及报文交互,从low-level 举例来说,AMQP 本身是应用层的协议,其填充于TCP 协议层的数据部分。而从high-level 来说, AMQP是通过协议命令进行交互的。AMQP 协议可以看作一系列结构化命令的集合,这里的命令代表一种操作,类似于HTTP 中的方法(GET 、POST 、PUT 、DELETE 等) 。
RabbitMQ的应用场景:
1)异步处理:
场景说明:用户注册后,需要发注册邮件和注册短信。邮件和短信对我正常的使用网站没有任何影响,客户端没有必要等着其发送完成才显示注册成功。引入消息队列后,把发送邮件,短信不是必须的业务逻辑异步处理。不用等到发送邮件或者短信成功后给出响应,再执行下面的操作。提高了响应时间。
2)应用解耦:
场景说明: 双11是购物狂节,用户下单后,订单系统需要通知库存系统,传统的做法就是订单系统调用库存系统的接口. 这样的做法会有些缺点:当库存系统出现故障,订单就会失败。为了解除订单系统和库存系统的耦合,引入消息队列。这样订单系统在用户下单后完成持久化处理,将消息写入消息队列,返回给用户下单成功。库存系统消费消息队列中的消息,进行库操作,就算库存系统出现故障,消息队列也会等到故障恢复后进行可靠投递,不会导致消息丢失。
3)流量削峰:
场景说明:流量削峰一般在秒杀活动中应用广泛,秒杀活动,一般会因为流量过大,导致应用挂掉,为了解决这个问题,一般在秒杀应用前加入消息队列。
作用:
1.可以控制活动人数,超过此一定阀值的订单直接丢弃。用户的请求,服务器收到之后,首先写入消息队列,加入消息队列长度超过最大值,则直接抛弃用户请求或跳转到错误页面。
2.可以缓解短时间的高流量压垮应用(应用程序按自己的最大处理能力获取订单),秒杀业务根据消息队列中的请求信息,再做后续处理。

1.2系统架构及核心组件
RabbitMQ系统结构如图1.2.1所示

图 1.2.1 RabbitMQ系统结构图
组成部分说明:
Broker:消息队列服务进程,此进程包括两个部分:Exchange和Queue
Exchange:消息队列交换机,按一定的规则将消息路由转发到某个队列,对消息进行过滤。
Queue:消息队列,存储消息的队列,消息到达队列并转发给指定的消费方。
Producer:消息生产者,即生产方客户端,生产方客户端将消息发送到MQ。
Consumer:消息消费者,即消费方客户端,接收MQ转发的消息。
消息发布的流程:
1、生产者和Broker建立TCP连接。
2、生产者和Broker建立通道。
3、生产者通过通道消息发送给Broker,由Exchange将消息进行转发。
4、Exchange将消息转发到指定的Queue(队列)。
接收消息的流程:
1、消费者和Broker建立TCP连接。
2、消费者和Broker建立通道 。
3、消费者监听指定的Queue(队列)。
4、当有消息到达Queue时Broker默认将消息推送给消费者。
5、消费者接收到消息。
2RabbitMQ在Linux系统下的安装
2.1安装Erlang(RabbitMQ的运行环境)
从Erlang Solution安装

添加erlang solutions源

$ wget https://packages.erlang-solutions.com/erlang-solutions-1.0-1.noarch.rpm
$ sudo rpm -Uvh erlang-solutions-1.0-1.noarch.rpm
$ sudo yum install erlang
2.2安装RabbitMQ
先下载rpm:
wget http://www.rabbitmq.com/releases/rabbitmq-server/v3.6.6/rabbitmq-server-3.6.6-1.el7.noarch.rpm
下载完成后安装:
yum install rabbitmq-server-3.6.6-1.el7.noarch.rpm
安装时如果遇到下面的依赖错误
Error: Package: socat-1.7.2.3-1.el6.x86_64 (epel)
Requires: libreadline.so.5()(64bit)
可以尝试先执行
$ sudo yum install socat
关于RabbitMQ的一些基本操作
$ sudo chkconfig rabbitmq-server on # 添加开机启动RabbitMQ服务
$ sudo /sbin/service rabbitmq-server start # 启动服务
$ sudo /sbin/service rabbitmq-server status # 查看服务状态
$ sudo /sbin/service rabbitmq-server stop # 停止服务

查看当前所有用户

$ sudo rabbitmqctl list_users

查看默认guest用户的权限

$ sudo rabbitmqctl list_user_permissions guest
(先不用更改用户权限!!!带//都先不做)
//# 由于RabbitMQ默认的账号用户名和密码都是guest。为了安全起见, 先删掉默认用户
//$ sudo rabbitmqctl delete_user guest
//# 添加新用户
//$ sudo rabbitmqctl add_user [username] [password]
//# 设置用户tag
//$ sudo rabbitmqctl set_user_tags [username] administrator
//# 赋予用户默认vhost的全部操作权限
//$ sudo rabbitmqctl set_permissions -p / [username] “." ".” “.*”

查看用户的权限

$ sudo rabbitmqctl list_user_permissions [username]

查看服务状态

sudo /sbin/service rabbitmq-server status # 查看服务状态

2.3开启web管理RabbitMQ接口
如果只从命令行操作RabbitMQ,多少有点不方便。幸好RabbitMQ自带了web管理界面,只需要启动插件便可以使用。
$ sudo rabbitmq-plugins enable rabbitmq_management
然后通过浏览器访问(只能在本机进行访问,需要加上配置才可以远程连接进行访问)
http://ip:15672
输入用户名和密码访问web管理界面了。
2.4配置RabbitMQ
在/etc/rabbitmq下创建rabbitmq.config文件,编辑文件如下
[{rabbit, [{loopback_users, []}]}].
这里的意思是开放使用rabbitmq管理插件的,当前用户默认只能是本机访问,localhost或者127.0.0.1,从外部访问需要添加上面的配置。
保存配置后重启服务:

service rabbitmq-server stop
service rabbitmq-server start
此时就可以从外部访问了,但此时再看log文件,发现内容还是原来的,还是显示没有找到配置文件,可以手动删除这个文件再重启服务,不过这不影响使用

rm [email protected]
service rabbitmq-server stop
service rabbitmq-server start
注意:记得要开放5672和15672端口

/sbin/iptables -I INPUT -p tcp --dport 5672 -j ACCEPT
/sbin/iptables -I INPUT -p tcp --dport 15672 -j ACCEPT

3RabbitMQ的六种工作模式
RabbitMQ有以下几种工作模式 :
1、Work queues
2、Publish/Subscribe
3、Routing
4、Topics
5、Header
6、RPC
下面会逐一介绍
3.1Work Queues工作队列模式
模式图如图3.1.1所示
图3.1.1 工作队列模式说明
工作队列模式是多个消费端同时消费一个队列中的消息。
应用场景:对于任务过重或任务较多情况使用工作队列可以提高任务处理的速度
3.2Publish/subscribe 发布与订阅模式
模式图如图3.2.1所示
图3.2.1 发布订阅模式图
发布订阅模式:
1、每个消费者监听自己的队列。
2、生产者将消息发给broker(Exchange和队列),由交换机(需要指定成Fanout模式)将消息转发到绑定此交换机的每个队列,每个绑定交换机的队列都将接收 到消息

3.3Routing 路由模式
路由模式图如图3.3.1 所示
图3.3.1 路由模式图
路由模式:
1、每个消费者监听自己的队列,并且设置routingkey。
2、生产者将消息发给交换机,由交换机(需要指定成Direct模式)根据routingkey来转发消息到指定的队列。

3.4Topics 通配符模式(主题模式)
通配符模式图如图3.4.1所示
图3.4.1 通配符模式图
路由模式:
1、每个消费者监听自己的队列,并且设置带统配符的routingkey。
2、生产者将消息发给broker,由交换机(需要指定为Topic模式)根据routingkey来转发消息到通配符指定的队列。
3、通配符的定义格式:符号“#”匹配一个或多个词,符号“”仅匹配一个词。因此“lazy.#”能够匹配到“lazy.irs.corporate”,但是“.orange.*”只会匹配到“abc.orange.def”。
3.5Header模式
header模式与routing不同的地方在于,header模式取消routingkey,使用header中的 key/value(键值对)匹配 队列。
交换机绑定队列时要指定headers(一个map集合)并把交换机设置为Header模式。
3.6RPC模式
RPC模式如图3.6.1所示
图3.6.1 RPC模式
RPC即客户端远程调用服务端的方法 ,使用MQ可以实现RPC的异步调用,基于Direct交换机实现,流程如下:
1、客户端即是生产者就是消费者,向RPC请求队列发送RPC调用消息,同时监听RPC响应队列。
2、服务端监听RPC请求队列的消息,收到消息后执行服务端的方法,得到方法返回的结果
3、服务端将RPC方法 的结果发送到RPC响应队列
4、客户端(RPC调用方)监听RPC响应队列,接收到RPC调用结果。

4SpringBoot整合RabbitMQ
4.1引入依赖

org.springframework.boot
spring-boot-starter-amqp

4.2配置application.yml
server:
port: 44000
spring:
application:
name: test‐rabbitmq‐producer
rabbitmq:
host: 127.0.0.1
port: 5672
username: guest
password: guest
virtualHost: /
4.3 定义RabbitConfig类,配置Exchange、Queue、及绑定交换机
import org.springframework.amqp.core.*;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class RabbitmqConfig {
public static final String QUEUE_INFORM_EMAIL = “queue_inform_email”;
public static final String QUEUE_INFORM_SMS = “queue_inform_sms”;
public static final String EXCHANGE_TOPICS_INFORM=“exchange_topics_inform”;
/**

  • 交换机配置
  • ExchangeBuilder提供了fanout、direct、topic、header交换机类型的配置
  • @return the exchange
    /
    @Bean(EXCHANGE_TOPICS_INFORM)
    public Exchange EXCHANGE_TOPICS_INFORM() {
    //durable(true)持久化,消息队列重启后交换机仍然存在
    return ExchangeBuilder.topicExchange(EXCHANGE_TOPICS_INFORM).durable(true).build();
    }
    //声明队列
    @Bean(QUEUE_INFORM_SMS)
    public Queue QUEUE_INFORM_SMS() {
    Queue queue = new Queue(QUEUE_INFORM_SMS);
    return queue;
    }
    //声明队列
    @Bean(QUEUE_INFORM_EMAIL)
    public Queue QUEUE_INFORM_EMAIL() {
    Queue queue = new Queue(QUEUE_INFORM_EMAIL);
    return queue;
    }
    /
    * channel.queueBind(INFORM_QUEUE_SMS,“inform_exchange_topic”,“inform.#.sms.#”);
  • 绑定队列到交换机 .
  • @param queue the queue
  • @param exchange the exchange
  • @return the binding
    */
    @Bean
    public Binding BINDING_QUEUE_INFORM_SMS(@Qualifier(QUEUE_INFORM_SMS) Queue queue,
    @Qualifier(EXCHANGE_TOPICS_INFORM) Exchange exchange) {
    return BindingBuilder.bind(queue).to(exchange).with(“inform.#.sms.#”).noargs();
    }
    @Bean
    public Binding BINDING_QUEUE_INFORM_EMAIL(@Qualifier(QUEUE_INFORM_EMAIL) Queue queue,
    @Qualifier(EXCHANGE_TOPICS_INFORM) Exchange exchange) {
    return BindingBuilder.bind(queue).to(exchange).with(“inform.#.email.#”).noargs();
    }
    }

4.4生产端发送消息
import com.xuecheng.test.rabbitmq.config.RabbitmqConfig;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@SpringBootTest
@RunWith(SpringRunner.class)
public class Producer05_topics_springboot {
@Autowired
RabbitTemplate rabbitTemplate;
@Test
public void testSendByTopics(){
for (int i=0;i<5;i++){
String message = “sms email inform to user”+i;
rabbitTemplate.convertAndSend(RabbitmqConfig.EXCHANGE_TOPICS_INFORM,“inform.sms.email”,message);
System.out.println(“Send Message is:’” + message + “’”);
}
}
}
4.5消费端配置
引入pom
配置application.yml
增加一个类RecieveHandler用来监听mq队列;类上用@Component注解标注
import com.rabbitmq.client.Channel;
import com.xuecheng.test.rabbitmq.config.RabbitmqConfig;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
@Component
public class ReceiveHandler {
//监听email队列,如果是json
@RabbitListener(queues = {RabbitmqConfig.QUEUE_INFORM_EMAIL})
public void receive_email(String msg,Message message,Channel channel){
System.out.println(msg);
}
//监听sms队列
@RabbitListener(queues = {RabbitmqConfig.QUEUE_INFORM_SMS})
public void receive_sms(String msg,Message message,Channel channel){
System.out.println(msg);
}
}
5消费端设置多线程消费同一队列
问题描述: 使用@RabbitListener注解指定消费方法,默认情况是单线程监听队列,可以观察当队列有多个任务时消费端每次只消费一个消息,单线程处理消息容易引起消息处理缓慢,消息堆积,不能最大利用硬件资源

解决方案: 可以配置mq的容器工厂参数,增加并发处理数量即可实现多线程处理监听队列,实现多线程处理消息。
1.在消费端加入RabbitMQ配置类RabbitConfig.java
@Bean(“customContainerFactory”)
public SimpleRabbitListenerContainerFactory containerFactory(SimpleRabbitListenerContainerFactoryConfigurer configurer, ConnectionFactory connectionFactory) {
SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
factory.setConcurrentConsumers(10); //设置线程数
factory.setMaxConcurrentConsumers(10); //最大线程数
configurer.configure(factory, connectionFactory);
return factory;
}
2.在@RabbitListener注解中指定容器工厂
@RabbitListener(queues = {“监听队列名”},containerFactory = “customContainerFactory”)
6生产方确认消息发送成功
在application.yml中加入配置spring:rabbitmq:publisher-returns: true和spring:rabbitmq:publisher-confirms: true
确认消息是否发送成功需要开启这两个配置
在生产方的RabbitMQConfig中加入RabbitMQTemplate的配置
@Bean
public RabbitTemplate rabbitTemplate() {
Logger log = LoggerFactory.getLogger(RabbitTemplate.class);
// 消息发送失败返回到队列中, yml需要配置 publisher-returns: true
rabbitTemplate.setMandatory(true);
// 消息返回, yml需要配置 publisher-returns: true
rabbitTemplate.setReturnCallback((message, replyCode, replyText, exchange, routingKey) -> {
String messageId = message.getMessageProperties().getMessageId();
log.error(“消息:{} 发送失败, 应答码:{} 原因:{} 交换机: {} 路由键: {}”, messageId, replyCode, replyText, exchange, routingKey);
throw new RabbitException(CodeMsg.MESSAGE_SEND_ERROR.getCode(),CodeMsg.MESSAGE_SEND_ERROR.getMsg());
});
// 消息确认, yml需要配置 publisher-confirms: true
rabbitTemplate.setConfirmCallback((correlationData, ack, cause) -> {
if (ack) {
// log.debug(“消息发送到exchange成功,id: {}”, correlationData.getId());
} else {
log.error(“消息发送到exchange失败,原因: {}”, cause);
throw new RabbitException(CodeMsg.MESSAGE_SEND_ERROR.getCode(),CodeMsg.MESSAGE_SEND_ERROR.getMsg());
}
});

	return rabbitTemplate;
}

生产方消息发送不成功直接返回错误信息或者抛出异常(自动捕捉异常并返回错误信息)
7消费方确认消息消费成功
采用手动设置消费成功标识的方式。因为:消费者的ack方式默认是自动的,也就是说消息一旦被消费(无论是否处理成功),消息都会被确认,然后会从队列中删除。这就意味着当消息处理失败的时候,也会被从队列中删除,这绝对不是我们所期望的。我们希望当消息正确消费时,消息从队列中删除,否则,消息不能删除,该消息应该继续被消费,直到成功消费(或者记录次数,3次以后抛弃此条消息)。
1.更改application.yml文件为手动ack
spring:
rabbitmq:
host: xxx.xxx.xxx.xx
port: 5672
username: xxxx
password: xxxx
listener:
direct:
acknowledge-mode: manual # 配置该消费者的ack方式为手动
在监听队列并消费消息时
import com.google.gson.Gson;
import com.rabbitmq.client.Channel;
import com.space.rbq.store.bean.Order;
import com.space.rbq.store.service.StoreService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.IOException;

/**

  • 负责接收处理订单服务发送的消息

  • @author zhuzhe

  • @date 2018/6/7 10:09

  • @email [email protected]
    */
    @Slf4j
    @Component
    public class OrderConsumer {

    @Autowired
    private StoreService storeService;

    /对列名称/
    public final String QUEUE_NAME1 = “first-queue”;

    /**

    • queues 指定从哪个队列(queue)订阅消息

    • @param message

    • @param channel
      */
      @RabbitListener(queues = {QUEUE_NAME1})
      public void handleMessage(Message message,Channel channel) throws IOException {
      try {
      // 处理消息
      System.out.println(“OrderConsumer {} handleMessage :”+message);
      // 执行减库存操作
      storeService.update(new Gson().fromJson(new String(message.getBody()),Order.class));

      /**
       * 第一个参数 deliveryTag:就是接受的消息的deliveryTag,可以通过msg.getMessageProperties().getDeliveryTag()获得
       * 第二个参数 multiple:如果为true,确认之前接受到的消息;如果为false,只确认当前消息。
       * 如果为true就表示连续取得多条消息才发会确认,和计算机网络的中tcp协议接受分组的累积确认十分相似,
       * 能够提高效率。
       *
       * 同样的,如果要nack或者拒绝消息(reject)的时候,
       * 也是调用channel里面的basicXXX方法就可以了(要指定tagId)。
       *
       * 注意:如果抛异常或nack(并且requeue为true),消息会重新入队列,
       * 并且会造成消费者不断从队列中读取同一条消息的假象。
       */
       // 确认消息
       // 如果 channel.basicAck   channel.basicNack  channel.basicReject 这三个方法都不执行,消息也会被确认
       // 所以,正常情况下一般不需要执行 channel.basicAck
       // channel.basicAck(message.getMessageProperties().getDeliveryTag(), true);
      

      }catch (Exception e){
      log.error(“OrderConsumer handleMessage {} , error:”,message,e);
      // 处理消息失败,将消息重新放回队列
      channel.basicNack(message.getMessageProperties().getDeliveryTag(), false,true);
      }
      }
      }
      /*

  • 消息的标识,false只确认当前一个消息收到,true确认consumer获得的所有消息

  • channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);

  • ack返回false,并重新回到队列

  • channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, true);

  • 拒绝消息

  • channel.basicReject(message.getMessageProperties().getDeliveryTag(), true);

/
7.1可以配置自动重试来实现自动重新消费消息的功能
只需要在application.yml中配置即可
spring.rabbitmq.listener.simple.retry.max-attempts=5 最大重试次数
spring.rabbitmq.listener.simple.retry.enabled=true 是否开启消费者重试(为false时关闭消费者重试,这时消费端代码异常会一直重复收到消息)
spring.rabbitmq.listener.simple.retry.initial-interval=5000 重试间隔时间(单位毫秒)
spring.rabbitmq.listener.simple.default-requeue-rejected=false 重试次数超过上面的设置之后是否丢弃(false不丢弃时需要写相应代码将该消息加入死信队列)
8死信队列(DLX死信交换机)
当消息在一个队列中变成死信之后,可以被重新推送到死信交换机中,死信交换机会把消息推送到与之绑定的死信队列上
8.1消息变成死信的几种情况:
1.消息被拒绝(basic.reject / basic.nack),并且requeue = false(没有开启自动重试)
2.消息TTL过期(消息已经达到预设的过期时间)
3.队列达到最大长度(设置队列的最大长度后,消息数量达到了队列的最大长度)
8.2死信的处理办法
1.丢弃,如果不是很重要,可以选择丢弃
2.记录死信入库,然后做后续的业务分析或处理
3.通过死信队列,由负责监听死信的应用程序进行处理
由业务可以考虑一下是用第几种情况,springboot配置死信队列如下所示。
1.在RabbitConfig中配置死信队列名
public final static String deadQueueName = “dead_queue”;
public final static String deadRoutingKey = “dead_routing_key”;
public final static String deadExchangeName = “dead_exchange”;
/
*
* 死信队列 交换机标识符
/
public static final String DEAD_LETTER_QUEUE_KEY = “x-dead-letter-exchange”;
/
*
* 死信队列交换机绑定键标识符
*/
public static final String DEAD_LETTER_ROUTING_KEY = “x-dead-letter-routing-key”;

2.在正常绑定交换机时,加入死信队列配置
// 1.定义邮件队列
@Bean
public Queue fanOutEamilQueue() {
// 将普通队列绑定到死信队列交换机上
Map args = new HashMap<>(2);
args.put(DEAD_LETTER_QUEUE_KEY, deadExchangeName);
args.put(DEAD_LETTER_ROUTING_KEY, deadRoutingKey);
Queue queue = new Queue(FANOUT_EMAIL_QUEUE, true, false, false, args);
return queue;
}
3.正常绑定普通交换机与普通队列
4.创建死信交换机与死信队列进行绑定
/**
* 创建配置死信邮件队列
*
* @return
/
@Bean
public Queue deadQueue() {
Queue queue = new Queue(deadQueueName, true);
return queue;
}
/

* 创建死信交换机
/
@Bean
public DirectExchange deadExchange() {
return new DirectExchange(deadExchangeName);
}
/

* 死信队列与死信交换机绑定
*/
@Bean
public Binding bindingDeadExchange(Queue deadQueue, DirectExchange deadExchange) {
return BindingBuilder.bind(deadQueue).to(deadExchange).with(deadRoutingKey);
}

5.生产者正常发送消息
6.消费者在配置普通消费队列监听器以外,还需要配置死信队列监听器
@RabbitListener(queues = “dead_queue”)
public void process(Message message, @Headers Map headers, Channel channel) throws Exception {
// 获取消息Id
String messageId = message.getMessageProperties().getMessageId();
String msg = new String(message.getBody(), “UTF-8”);
System.out.println(“死信邮件消费者获取生产者消息msg:”+msg+",消息id"+messageId);
// // 手动ack
Long deliveryTag = (Long) headers.get(AmqpHeaders.DELIVERY_TAG);
// 手动签收
channel.basicAck(deliveryTag, false);
System.out.println(“执行结束…”);
}
9设置消息的过期时间与队列长度
rabbitmq可以设置消息的过期时间,等到消息的过期时间到期,会把消息放到死信队列中
可以在生产者声明队列时配置
@Bean(“myTtlQueue”)
public Queue ttlQueue() {
//设置在这个队列上的私信的去处->
// mine-dead-letter-exchange交换机,
// 并且routingKey为mine.dead.letter
Map args = new HashMap<>(4);
args.put(“x-dead-letter-exchange”, “mine-dead-letter-exchange”);
args.put(“x-dead-letter-routing-key”, “mine.dead.letter”);

    //过期时间由队列统一设置
    //注意不是 x-expires,x-expires为队列存活时间,
    // x-message-ttl为队列内的消息存活时间
    //注意更改队列/交换机设置需要删除原有的
    args.put("x-message-ttl", 20000);
    return new Queue("mine-ttl-queue", true, false, false, args);

}

在发送时还可以只针对某一条消息设置过期时间
rabbitTemplate.convertAndSend(“mine-ttl-exchange”, “mine.ttl”, "this is a message ",message -> {
//设置10秒过期
message.getMessageProperties().setExpiration(“10000”);
return message;
});
设置队列长度可以在声明队列时设置,直接在队列的参数上加上一个参数args.put(“x-max-length”, 最大消息数量);即可。
注意,如果队列的消息达到最大值,会从队首开始抛除消息而不是队尾
如果想要改变消息数量超过队列长度后,抛弃掉新加入的消息的话,还需要在声明队列时加一个参数
arguments.put(“x-overflow”, “reject-publish”);
10消息持久化
rabbitmq中的消息持久化分为交换机持久化,队列持久化,以及消息持久化
其中交换机持久化以及队列持久化,都是在声明时加上durable = true参数来设置
消息持久化需要在消息发送时设置参数deliveryMode = 2来实现消息持久化存储。

11部署RabbitMQ集群
可以参考https://www.cnblogs.com/shihaiming/p/11014257.html这篇博客
1.配置hosts文件
更改三台MQ节点的计算机名分别为mq01、mq02 和mq03,然后修改hosts配置文件
vim /etc/hostname //其他两台相同
mq01.localdomain
vi /etc/hosts
192.168.100.143 mq01 //注意不能带.注意-主机名称也要更改
192.168.100.144 mq02
192.168.100.145 mq03

2.三个节点配置yum源,安装rabbitmq软件

3.拷贝erlang.cookie
Rabbitmq的集群是依附于erlang的集群来工作的,所以必须先构建起erlang的集群景象。Erlang的集群中各节点是经由过程一个magic cookie来实现的,这个cookie存放在/var/lib/rabbitmq/.erlang.cookie中,文件是400的权限。所以必须保证各节点cookie一致,不然节点之间就无法通信。
[root@mq01 ~]# cat /var/lib/rabbitmq/.erlang.cookie
XAHPZVPYUQDWWJIOHUPQ
用scp的方式将mq01节点的.erlang.cookie的值复制到其他两个节点中。
scp /var/lib/rabbitmq/.erlang.cookie [email protected]:/var/lib/rabbitmq/.erlang.cookie
scp /var/lib/rabbitmq/.erlang.cookie [email protected]:/var/lib/rabbitmq/.erlang.cookie

4.分别查看三个节点并添加管理服务,最后启动rabbitmq服务
RabbitMQ提供了一个非常友好的图形化监控页面插件(rabbitmq_management),让我们可以一目了然看见Rabbit的状态或集群状态。
/usr/lib/rabbitmq/bin/rabbitmq-plugins list //查看插件安装情况
/usr/lib/rabbitmq/bin/rabbitmq-plugins enable rabbitmq_management //启用rabbitmq_management服务
service rabbitmq-server start

5.查看监听端口(插件监控的端口是15672)

6.将mq02、mq03作为内存节点加入mq01节点集群中
在mq02、mq03执行如下命令:
rabbitmqctl stop_app //停掉rabbit应用
rabbitmqctl join_cluster --ram rabbit@mq01 //把当前节点作为内存节点加入到磁盘节点mq01中,如果不想把mq02作为内存节点,不要加–ram参数
如果想要更改节点类型,可以使用命令rabbitmqctl change_cluster_node_type disc(ram),前提是必须停掉rabbit应用
rabbitmqctl start_app //启动rabbit应用

7.查看集群状态 rabbitmqctl cluster_status查看

8.配置镜像集群模式
在mq01节点的控制台上创建策略
(1)点击admin菜单–>右侧的Policies选项–>左侧最下下边的Add/update a policy。
Name:策略名称,自己起一个
Pattern:匹配的规则,如果是匹配所有的队列,那就是,要匹配a开头的队列就是a
Definition:使用ha-mode模式中的all,也就是同步所有匹配的队列。问号链接帮助文档。
(2)点击apply添加策略

添加队列后,看到队列后面有+2,鼠标移上去有同步提示说明配置完成

你可能感兴趣的:(rabbitmq)