六、RabbitMQ应用
1、RabbitConfig配置队列、交换器
@Configuration
public class RabbitMqConfig {
/**
* 定义routingKey
*/
public final static String ROUTING_KEY_TEST = "routingKey.thc_sob.send_task";
/**
* 定义Queue名称
*/
public static final String QUEUE_NAME = "queue.name.thc-sob.send_task";
/**
* 定义Exchange名称
*/
public static final String EXCHANGE_NAME = "exchange.name.thc-sob.send_task";
/**
* 定义测试队列
* @return
*/
@Bean
Queue testQueue(){
/**
* Queue(String name, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments)
* 1、name:名称;
* 2、durable:持久性,是否持久化至硬盘(若要使队列中消息不丢失,同时也需要将消息声明为持久化);
* 3、exclusive:是否声明该队列是否为连接(connection)独占,若为独占,连接关闭后队列即被删除;
* 4、autoDelete:自动删除,若没有消费者订阅该队列,队列将被删除;
* 5、arguments:其他参数
*/
return new Queue(QUEUE_NAME);
}
/**
* 定义测试交换机
*/
@Bean(name = "dispenseExchange")
DirectExchange testExchange(){
/**
* DirectExchange(String name, boolean durable, boolean autoDelete, Map<String, Object> arguments)
* 1、name:名称;
* 2、durable:持久性,是否持久化至硬盘(若要使队列中消息不丢失,同时也需要将消息声明为持久化);
* 3、autoDelete:自动删除,若没有消费者订阅该队列,队列将被删除;
* 4、arguments:其他参数
*/
return new DirectExchange(EXCHANGE_NAME);
}
/**
* 定义绑定
* @return
*/
@Bean
Binding testBind(){
return BindingBuilder.bind(testQueue())
.to(testExchange())
.with(ROUTING_KEY_TEST);
}
}
2、消息发送方
//测试消息发送;消息接收
@Component
class Send{
@Autowired
private AmqpTemplate amqpTemplate;
/**
* 发送消息
* @param
*/
public void sendMessage(String exchangeName, String routingKey, String message){
this.amqpTemplate.convertAndSend(exchangeName, routingKey, message);
}
}
3、消息接收方
/**
* @RabbitListener标注在类上面表示当有收到消息的时候,就交给@RabbitHandler的方法处理,具体使用哪个方法处理,根据MessageConverter转换后的参数类型。
*/
@Component
@RabbitListener(queues = QUEUE_NAME)
public class Received{
@RabbitHandler
public void process(String message){
System.out.println(message);
}
}
七、队列
1、延时队列:先把消息发到正常队列,正常队列有超时时间,当达到时间后自动转发到死信队列,然后由消费者去消费死信队列里的消息。
a、死信(Dead-letter)
-
消息被拒绝(basic.reject 或者 basic.nack),并且requeue=false;
-
消息的过期时间到期了;
-
队列长度限制超过了。
b、过期设置方式
-
创建队列时指定过期时间(x-message-ttl),此时队列所有的消息具有统一过期时间。
-
发送消息为每个消息设置 expiration,此时消息之间过期时间可能不同。
//延时交换机
public static final String DELAY_EXCHANGE = "exchange.delay";
//死信交换机
public static final String DEAD_LETTER_EXCHANGE = "exchange.dead.letter";
//延时队列
public static final String DELAY_QUEUE = "queue.delay";
//死信队列
public static final String DEAD_LETTER_QUEUE = "queue.dead.letter”;
//延时RootKey
public static final String DEAD_LETTER_QUEUE = "routingKey.delay.letter";
//死信RootKey
public static final String DEAD_LETTER_QUEUE = "routingKey.dead.letter";
-
创建普通交换机“exchange.delay”
-
创建死信交换机(跟普通交换机创建方式相同)“exchange.dead.letter”
-
创建普通队列(延时队列)“queue.delay”:配置死信交换机“exchange.dead.letter”的x-dead-letter-exchange属性;配置死信rootKey属性“routingKey.dead.letter”;
-
创建死信队列“queue.dead.letter”
-
用“routingKey.dead.letter”绑定死信队列和死信交换机
-
用“routingKey.delay.letter”绑定延时队列和延时交换机
2、死信队列:
队列的Time To Live (TTL) :RabbitMQ会确保有效时间达到后将队列删除,但是并不保证这个动作有多及时,队列过期代表着处于未使用状态,即:
-
队列无任何消费者
-
队列没有被重新声明
-
队列在过期未调用Basic.Get命令获取消息
八、RabbitMQ集群
1、作用:
(1)、允许消费者和生产者在RabbitMQ节点崩溃的情况下继续运行。
(2)、通过增加节点来扩展RabbitMQ处理更多的消息,承载更多的业务量。
2、模式
(1)、普通模式
默认的集群模式,以两个节点(rabbit01、rabbit02)为例,对于Queue来说,消息实体只存在于其中一个节点rabbit01(或者rabbit02),rabbit01和rabbit02两个节点仅有相同的元数据,即队列的结构。当消息进入rabbit01节点的Queue后,consumer从rabbit02节点消费时,RabbitMQ会临时在rabbit01、rabbit02间进行消息传输,把rabbit01中的消息实体取出并经过rabbit02发送给consumer。所以 consumer应尽量连接每一个节点,从中取消息。即对于同一个逻辑队列,要在多个节点建立物理Queue。否则无论consumer连rabbit01或rabbit02,出口总在rabbit01,会产生瓶颈。当rabbit01节点故障后,rabbit02节点无法取到rabbit01节点中还未消费的消息实体。如果做了消息持久化,那么得等rabbit01节点恢复,然后才可被消费;如果没有持久化的话,就会产生消息丢失的现象。
(2)、镜像模式
将需要消费的队列变为镜像队列,存在于多个节点,这样就可以实现RabbitMQ的HA高可用性。作用就是消息实体会主动在镜像节点之间实现同步,而不是像普通模式那样,在consumer消费数据时临时读取。缺点就是,集群内部的同步通讯会占用大量的网络带宽。