RabbitMq fanout 实现本地缓存删除

原来做了个功能,是用redis做的分布式缓存,但是因为并发和性能问题,需要用本地缓存实现,本地缓存的主要问题是数据变更的时候一般只能清掉当前节点的缓存,无法清除其他节点的缓存,考虑用mq的广播模式来实现,fanout+动态队列,因为每个节点都是不同的队列,才能实现每个节点都被消费,队列配置如下

package com.test.config;
import java.util.UUID;
import org.springframework.amqp.core.AcknowledgeMode;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.FanoutExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.test.listener.ClearCacheListener;


@Configuration
public class FanoutRabbitConfig {

    public static final String MY_FANOUTEXCHANGE_NAME = "local-cache-exchange";

    //用UUID来生成一个queue名称,也可以用服务器IP端口作为queue名称
    public static final String MY_QUEUE_NAME = UUID.randomUUID().toString();

    @Autowired
    RabbitTemplate rabbitTemplate;
    
    //创建动态queue 自动删除队列,不然会造成队列堆积
    @Bean
    public Queue myQueue() {
        return new Queue(MY_QUEUE_NAME, true,false,true);
    }

    //创建Exchange
    @Bean
    public FanoutExchange fanoutExchange() {
        return new FanoutExchange(MY_FANOUTEXCHANGE_NAME, true, false);
    }

    //绑定当前queue到Exchange
    @Bean
    public Binding bindingExchangeMyQueue() {
        return BindingBuilder.bind(myQueue()).to(fanoutExchange());
    }

    //设置消息处理
    @Bean
    public SimpleMessageListenerContainer mqMessageContainer(ClearCacheListener clearCacheListener) {
        SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(rabbitTemplate.getConnectionFactory());
        container.setQueueNames(MY_QUEUE_NAME);
        container.setExposeListenerChannel(true);
        container.setPrefetchCount(1);//设置每个消费者获取的最大的消息数量
        container.setConcurrentConsumers(1);//消费者个数
        container.setAcknowledgeMode(AcknowledgeMode.MANUAL);//设置确认模式为手工确认
        container.setMessageListener(clearCacheListener);//消息处理类
        return container;
    }

}

ClearCacheListener 代码

package com.test.listener;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.core.ChannelAwareMessageListener;
import org.springframework.beans.factory.annotation.Autowired;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.rabbitmq.client.Channel;

public class ClearCacheListener implements ChannelAwareMessageListener {

  private static final Logger log = LoggerFactory.getLogger(ClearCacheListener.class);
  private static final ObjectMapper MAPPER = new ObjectMapper();
  

  @Override
  public void onMessage(Message message,Channel channel) {
       try {
         JsonNode jsonNode = MAPPER.readTree(message.getBody());
         log.info("删除缓存id",jsonNode);
         deleteLocalCache(jsonNode.asText();
         channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
       }catch (Exception e) {
         log.error("处理清除缓存消息失败",e);
      }
  }
}

中间碰到的几个问题

1、没用动态队列,只能有一个节点消费,只能清除一个节点的缓存

2、队列的autoDelete用默认的false,导致应用多次发布之后,堆积了很多队列,但这些队列不在存在消费者,广播这些无用的队列也没意义,占用空间

你可能感兴趣的:(mq,rabbitmq,缓存)