RabbitMQ学习(5)- RabbitMQ队列

 

目录

 

消息路由失败会怎样?

1、mandatory参数

2、immediate参数

3、备份交换器

消息过期时间TTL

1.有两种方式可以设置消息的TTL:

死信队列

如何实现延迟队列

1.DB定时轮询;

2.DelayQueue;

3.Redis sortedSet集合;

4.RabbitMQ TTL+DLX;

RabbitMQ的RPC实现

持久化

生产者确认机制

1.通过事务机制

2.通过发送方确认(publisherconfirm)机制


消息路由失败会怎样?

在发送消息channel.basicPublish方法中有两个参数分别是mandatoryimmediate,它们都有当消息在传递过程中不可达目的地时,将消息返回给生产者的功能。RabbitMQ提供的备份交换器(Alternate Exchange)可以将未能被交换器路由的消息(没有绑定队列或者没有匹配的绑定)存储起来,而不用返回给客户端。

1、mandatory参数

当mandatory参数设为true时,如果交换器无法根据自身的类型和路由键找到一个符合条件的队列,那么RabbitMQ会调用Basic.Return命令将消息返回给生产者。当mandatory参数设置为false时,出现上述情形,则消息直接被丢弃。

	public static void mandatory() throws Exception{
		ConnectionFactory factory = new ConnectionFactory();
		factory.setHost(HOST);
		factory.setPort(PORT);
		factory.setUsername(USERNAME);
		factory.setPassword(PASSWORD);
		Connection connection = factory.newConnection();
		Channel channel = connection.createChannel();
		// 创建一个交换器
		channel.exchangeDeclare(EXCHANGE_NAME, "direct");
		// 创建队列
		channel.queueDeclare(QUEUE_NAME, true, false, false, null);
		// 将交换器与队列通过路由键绑定
		channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, ROUTING_KEY);
		
		String message = "Hello World";
		// mandatory = true
		channel.basicPublish(EXCHANGE_NAME, "123", true,
				MessageProperties.PERSISTENT_TEXT_PLAIN,
				message.getBytes());
		// 添加监听器
		channel.addReturnListener(new ReturnListener() {
			@Override
			public void handleReturn(int replyCode, String replyText, String exchange, String routingkey, 
					BasicProperties properties, byte[] body)
					throws IOException {
				System.out.println("exchange:" + exchange);
				System.out.println("routingKey:" + routingkey);
				System.out.println("生产者接收到服务器返回的路由失败消息:" + new String(body));
			}
		});
		TimeUnit.SECONDS.sleep(5);
		// 关闭资源
		channel.close();
		connection.close();
	}

2、immediate参数

当immediate参数设为true时,如果交换器在将消息路由到队列时发现队列上并不存在任何消费者,那么这条消息将不会存入队列中。当与路由键匹配的所有队列都没有消费者时,该消息会通过Basic.Return返回至生产者。(这参数基本已经废弃,了解一下就行,不建议使用。官方说此方法影响了镜像队列的性能,增加了复杂度,所以将其取消;使用TTL+DLX代替,虽然不能完全代替,但是能实现它所需要做的功能)

3、备份交换器

备份交换器可以将未被路由的消息存储在 RabbitMQ 中,再在需要的时候去处理这些消息。

关于备份交换器:

(1) 如果设置的备份交换器不存在,客户端和RabbitMQ服务端都不会出现异常,此时消息会丢失。

(2) 如果备份交换器没有绑定任何队列,客户端和RabbitMQ服务端都不会出现异常,此时消息会丢失。

(3) 如果备份交换器没有任何匹配的队列,客户端和RabbitMQ服务端都不会出现异常,此时消息会丢失。

(4) 如果备份交换器和mandatory参数一起使用,如果备份交换器有效,那么mandatory参数无效 。

private static void main() throws Exception {
	ConnectionFactory factory = new ConnectionFactory();
	factory.setHost(HOST);
	factory.setPort(PORT);
	factory.setUsername(USERNAME);
	factory.setPassword(PASSWORD);
	Connection connection = factory.newConnection();
	Channel channel = connection.createChannel();

	Map<String, Object> map = new HashMap<>();
	map.put("alternate-exchange", EXCHANGE_NAME_BAK);

	// 创建一个交换器 设置备份交换器
	channel.exchangeDeclare(EXCHANGE_NAME, "direct", false, false, false, map);
	channel.exchangeDeclare(EXCHANGE_NAME_BAK, "fanout");

	// 创建队列
	channel.queueDeclare(QUEUE_NAME, true, false, false, null);
	channel.queueDeclare(QUEUE_NAME_BAK, true, false, false, null);

	// 将交换器与队列通过路由键绑定
	channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, ROUTING_KEY);
	channel.queueBind(QUEUE_NAME_BAK, EXCHANGE_NAME_BAK, ROUTING_KEY);
	
    // 消息RoutingKey与交换器绑定路由的BindingKey不匹配,消息路由失败
	String message = "hello world";
	channel.basicPublish(EXCHANGE_NAME, "123", true,
				MessageProperties.PERSISTENT_TEXT_PLAIN,
				message.getBytes());
		
	TimeUnit.SECONDS.sleep(5);
	channel.close();
	connection.close();
}

消息过期时间TTL

1.有两种方式可以设置消息的TTL:

  1. 通过设置队列属性值,队列中所有消息的过期时间都是相同的;

    Map<String, Object> map = new HashMap<>();
    map.put("x-message-ttl", 5000);// 消息过期时间
    
    // 创建队列
    channel.queueDeclare(QUEUE_NAME, true, false, false, map);
  2. 通过设置消息本身的过期时间,则队列中每条消息的TTL都可以不同。

     

private static void ttl() throws Exception {
	ConnectionFactory factory = new ConnectionFactory();
	factory.setHost(HOST);
	factory.setPort(PORT);
	factory.setUsername(USERNAME);
	factory.setPassword(PASSWORD);
	Connection connection = factory.newConnection();
	Channel channel = connection.createChannel();

	// 创建一个交换器
	channel.exchangeDeclare(EXCHANGE_NAME, "direct");

	// 创建队列
	channel.queueDeclare(QUEUE_NAME, true, false, false, null);

	// 将交换器与队列通过路由键绑定
	channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, ROUTING_KEY);
		
	AMQP.BasicProperties.Builder builder = new AMQP.BasicProperties().builder();
	builder.deliveryMode(2);// 持久化消息
	builder.expiration("10000");// 设置消息超时时间,单位:ms
	
	String message = "hello world";
	channel.basicPublish(EXCHANGE_NAME, ROUTING_KEY, builder.build(), message.getBytes());
		
	TimeUnit.SECONDS.sleep(5);
	channel.close();
	connection.close();
}

如果两种方式一起设置,则消息的TTL以两者之间最小值为准。

注意:

  1. 对于第一种设置队列TTL属性的方法,一旦消息过期,就会从队列中抹去;而在第二种方法中,即使消息过期,也不会马上从队列中抹去。
  2. 队列中间位置的消息过期,RabbitMQ不会主动删除。
  3. 会定期扫描队列头部的消息,删除过期消息。
  4. 未删除的未过期消息自然不会进入死信队列。

死信队列

DLX,全称为Dead-Letter-Exchange,可以称之为死信交换器,也有人称之为死信邮箱。当消息在一个队列中变成死信(deadmessage)之后,它能被重新被发送到另一个交换器中,这个交换器就是DLX,绑定DLX的队列就称之为死信队列。

消息变成死信一般是由于以

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值