【redis】 redis 实现消息队列

消息队列MQ 主要是用来:

  1. 解耦应用 2 异步化消息 3 流量削峰填谷

为什么要用Redis实现轻量级MQ 在业务的实现过程中,就算没有大量的流量,解耦和异步化几乎也是处处可用,此时MQ就显得尤为重要。但与此同时MQ也是一个蛮重的组件,例如我们如果用RabbitMQ就必须为它搭建一个服务器,同时如果要考虑可用性,就要为服务端建立一个集群,而且在生产如果有问题也需要查找功能。在中小型业务的开发过程中,可能业务的其他整个实现都没这个重。过重的组件服务会成倍增加工作量。 所幸的是,Redis提供的list数据结构非常适合做消息队列

如何实现:


public class RedisQueueListener {
    private static final Logger logger = LoggerFactory.getLogger(RedisQueueListener.class);


    private final Integer THREAD_COUNT = 1; //监听队列线程数

    ExecutorService executorService = Executors.newFixedThreadPool(THREAD_COUNT);

    @Autowired
    private RedissonClient redissonClient;

    @PostConstruct
    public void redisQueueListen() {
        executorService.execute(new Runnable() {
            [@Override](https://my.oschina.net/u/1162528)
            public void run() {
                logger.info("启动【{}】个线程去处理队列:{}",THREAD_COUNT,GlobalConfig.QUEUE_NAME);
                RBlockingQueue<Object> blockingQueue = null;
                while (true) {
                    blockingQueue = redissonClient.getBlockingQueue(GlobalConfig.QUEUE_NAME);
                    try {
                        Object message = blockingQueue.take();
                        if (message != null && !"".equals(message)) {
                            logger.info("监听到了信息 :{}", message);
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                        logger.info("监听redis队列报错,队列名称:{}", GlobalConfig.QUEUE_NAME);
                    }

                }
            }
        });
    }

  public void addRedisQueue(String message){
        RBlockingQueue<Object> blockingQueue = redisson.getBlockingQueue(GlobalConfig.QUEUE_NAME);
        blockingQueue.add(message);
    }
}

如何实现ack机制? ack,即消息确认机制(Acknowledge)。

首先来看RabbitMQ的ack机制: •Publisher把消息通知给Consumer,如果Consumer已处理完任务,那么它将向Broker发送ACK消息,告知某条消息已被成功处理,可以从队列中移除。如果Consumer没有发送回ACK消息,那么Broker会认为消息处理失败,会将此消息及后续消息分发给其他Consumer进行处理(redeliver flag置为true)。 •这种确认机制和TCP/IP协议确立连接类似。不同的是,TCP/IP确立连接需要经过三次握手,而RabbitMQ只需要一次ACK。 •值的注意的是,RabbitMQ当且仅当检测到ACK消息未发出且Consumer的连接终止时才会将消息重新分发给其他Consumer,因此不需要担心消息处理时间过长而被重新分发的情况。

那么在我们用Redis实现消息队列的ack机制的时候该怎么做呢? 需要注意两点: 1.work处理失败后,要回滚消息到原始pending队列 2.假如worker挂掉,也要回滚消息到原始pending队列

实现方案

(该方案主要解决worker挂掉的情况)

1.维护两个队列:pending队列和doing表(hash表)。 2. workers定义为ThreadPool。 3.由pending队列出队后,workers分配一个线程(单个worker)去处理消息——给目标消息append一个当前时间戳和当前线程名称,将其写入doing表,然后该worker去消费消息,完成后自行在doing表擦除信息。 4.启用一个定时任务,每隔一段时间去扫描doing队列,检查每隔元素的时间戳,如果超时,则由worker的ThreadPoolExecutor去检查线程是否存在,如果存在则取消当前任务执行,并把事务rollback。最后把该任务从doing队列中pop出,再重新push进pending队列。 5.在worker的某线程中,如果处理业务失败,则主动回滚,并把任务从doing队列中移除,重新push进 pending队列。

转载于:https://my.oschina.net/wangjunBlog/blog/1817506

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值