rabbitmq延时队列

rabbitmq延时队列

在开发中使用到定时任务这个功能,以前都是使用timer,quartz,redis的过期事件,quartz的话做集群依赖数据库,redis使用集群的时候不支持过期事件,都存在各种问题,所有想到了使用rabbitmq的延时队列来实现,那这其中也涉及到rabbitmq事务的相关设置,这里就简单写一下我工作中的体会

定义延时队列

队列的示意图
这里就不再详细的介绍基本概念,主要涉及 发布者,交换器,队列,消费者,消费者和队列之间通过TCP建立Connection,connection中存在channel
下面为延时队列的一个流程图,
延迟队列示意图
下面直接贴代码:

    //创建连接工厂,注意publisherConfirms,这个值必须设置
	@Bean
	public ConnectionFactory connectionFactory() {
		CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
		connectionFactory.setHost(host);
		connectionFactory.setPort(port);
		connectionFactory.setUsername(username);
		connectionFactory.setPassword(password);
		connectionFactory.setVirtualHost(virtualHost);
		//消息发送到rabbitmq交换器后接受ack回调,回调中会告诉发送方,
		//rabbit是否接受成功,没有成功的话,要做相应的处理,比如重发或者记录
		connectionFactory.setPublisherConfirms(true); //这里相当于通过这个设置能实现事务的一半
		//消息发送到rabbitmq交换器后无相应队列育交换器绑定时进行回调
		connectionFactory.setPublisherReturns(true);
		return connectionFactory;
	}

	/**
	 * 声明延迟队列交换器 exchange
	 * @return
	 */
	@Bean
	public DirectExchange delayExchange() {
		return new DirectExchange("delay_exchange");
	}
	/**
	 * 声明延迟队列 queue
	 */
	@Bean
	Queue delayQueue(){
		return QueueBuilder.durable("delay_queue")
		         // DLX,dead letter发送到的exchange:消息过期后转到的exchange
				.withArgument("x-dead-letter-exchange", "process_exchange") 
				 // dead letter携带的routing key:跳转到指定exchange后传送到指定routingkey的队列
				.withArgument("x-dead-letter-routing-key", "delay") 
				.build();
	}

	/**
	 * 将延迟队列与exchange绑定
	 * @return
	 */
	@Bean
	Binding delayBinding() {
		return BindingBuilder.bind(delayQueue())
				.to(delayExchange())
				.with("delay");
	}

上面延迟队列就声明完毕,下面声明一下正常消费队列

    //正常消费队列 交换器exchange 注意这里exchangeName和上面x-dead-letter-exchange对应的一致
    @Bean
	public DirectExchange processExchange() {
		return new DirectExchange("process_exchange");
	}
	@Bean
	public Queue processQueue() {
		return QueueBuilder.durable("process_queue")
				.build();
	}

    @Bean
	Binding queueBinding() {
		return BindingBuilder.bind(processQueue())
				.to(processExchange())
				//这个值必须和x-x-dead-letter-routing-key保持一致,这样才会传输到指定的队列中
				.with("delay");
	}

@Bean
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)	//必须是prototype类型(有待考证)
RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
    final RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
    //使用return-callback时必须设置mandatory为true
    rabbitTemplate.setMandatory(true);
    rabbitTemplate.setReturnCallback(new RabbitTemplate.ReturnCallback() {
        @Override
        public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) {
        //做相应的操作
        }
    });
    rabbitTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback() {
        @Override
        public void confirm(CorrelationData correlationData, boolean ack, String s) {
            if (!ack) {
                logger.info("=============消息发送失败=============");
                Msg msg = JSON
                        .parseObject(correlationData.getId(), Msg.class);
                //这里做了重新传送,Msg是自定义的类,传递的消息。correlationData会设置一个id,在发送的时候设置一下,
                //这里由于是返回的,已经带有id不用重新再设置
                rabbitTemplate.convertAndSend(exchangeName, forceCloseRepoRouting, msg, correlationData);
            } else {
                logger.info("=============消息发送成功=============");
            }
            logger.info("correlationData= {},b={},s={}",correlationData!=null?correlationData.toString():"",ack,s);
        }
    });
    rabbitTemplate.setMessageConverter(new Jackson2JsonMessageConverter());
    return rabbitTemplate;
}

消息发送方法:

public void send() {
    Msg msg=new Msg();
    msg.setId(1);
    //携带确认数据,设置correlationDate的id,主要是用于消息没有发送成功,返回给生产者是通过id判断是哪个信息
    CorrelationData correlationData = new CorrelationData(JSON.toJSONString(msg));
    rabbitTemplate.convertAndSend(exchangeName, forceCloseRepoRouting, msg, correlationData);
}

到这里除了监听代码没有写出来,其他的代码都已经写出来了,慢慢干货,当然这里还有一些问题,后面有时间在和大家一块儿学习讨论吧

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值