redis消息队列的四种实现方式之List的简单队列和延时队列

目录

redis为我们提供的数据结构是很多的,如果再Redis中要实现一个消息中间件至少有4种方式:

  1. List
  2. zSet
  3. PUB/SUB(发布与订阅)
  4. Steam

基于List实现

最简单是基于List来实现,如果说你的业务需求足够的简单,同时又想享有消息中间件的一部分功能,有没有实力来部署一个消息中间件的东西,那么就可以使用List。

List提供了从头或者尾去放入元素,也提供了从头或者尾去拿取元素,而且操作时间都非常的快,那么我们就可以把List视为一个队列,我从左边往里放元素,再从右边拿元素,很完美的符合消息队列的一个简单的模型。
Redis-List数据结构

生产者从左边去放元素,消费者就从右边拿。但是消费者什么时候拿有时候是不确定的,当不确定什么时候拿的时候,就得不停的去队列中看有没有该拿的元素。这种情况会发生CPU空转,浪费资源。

代码详解:

import com.zhao.utils.UuidUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.ListOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * 生产者
 */
@RestController
@RequestMapping("/testString")
public class ProducerController {
  @Autowired
  private RedisTemplate redisTemplate;

  @PostMapping(value = "testMethodList")
  public void producerList() {
    // 创建String类型实例
    ListOperations listOperations = redisTemplate.opsForList();
    // 从左边添加数据
    listOperations.leftPush("testListOne", UuidUtil.getUuid());
    System.out.println("添加数据:" + listOperations.range("testListOne", 0, -1));
  }
}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.ListOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * 消费者
 */
@RestController
@RequestMapping(value = "/consumerController")
public class ConsumerController {
  @Autowired
  private RedisTemplate redisTemplate;

  @PostMapping(value = "consumerList")
  public void consumerList() {
    // 创建List类型实例
    ListOperations listOperations = redisTemplate.opsForList();
    // 查询已有的数据
    System.out.println(listOperations.range("testListOne", 0, -1));
    while (true) {
      System.out.println("正在拿数据");
      // 从右边拿数据
      Object testListOne = listOperations.rightPop("testListOne");
      // 如果没有拿到数据 则重新拿 直到拿到数据再停止
      if (!ObjectUtils.isEmpty(testListOne)) {
        System.out.println("拿到数据:" + testListOne.toString());
        break;
      }
    }
  }
}
import com.zhao.RedistestApplication;
import com.zhao.controller.consumer.ConsumerController;
import com.zhao.controller.producer.ProducerController;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest(classes = RedistestApplication.class)
public class TestController {
  @Autowired
  private ProducerController producerController;

  @Autowired
  private ConsumerController consumerController;
      
  /**
   * 生产者
   */
  @Test
  public void testProducerList() {
    producerController.producerList();
  }

  /**
   * 消费者
   */
  @Test
  public void testConsumerList() {
    consumerController.consumerList();
  }
}

我们先启动消费者,当生产者没有往队列中放数据的时候,队列中现在还是空的,什么都没有。此时消费者就会一直不停地去访问队列,直到拿到数据为止。


这样就形成了“数据库空转”。当启动了生产者,生产者往队列中放入一条数据,消费者拿到数据,循环停止。
Brpop命令移出并获取列表的最后一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。 基本语法:

redis 127.0.0.1:6379> BLPOP LIST1 LIST2 .. LISTN TIMEOUT

如果列表为空,返回一个 nil 。 否则,返回一个含有两个元素的列表,第一个元素是被弹出元素所属的 key ,第二个元素是被弹出元素的值。
java 中的实例:

/**
 * 2
 * 延时拿数据
 */
@PostMapping(value = "consumerList")
public void consumerList() {
  // 创建Jedis实例
  Jedis jedis = new Jedis();
  System.out.println("开始拿数据了 testListOne现有数据:" + jedis.lrange("testListOne", 0, -1));
  // 从右边阻塞式拿数据 超时时间为0代表不限时
  List<String> testListOne = jedis.brpop(0, "testListOne");
  System.out.println("拿到数据:" + testListOne);
}

在以上实例中,操作会被阻塞,如果“testListOne”列表有数据,就会从列表的右边拿取第一个数据并返回,否则会无限期等待(可能是无限期,我自己就等了1分钟);如果超时时间大于0,会阻塞设置的时间;如果超时时间小于0,启动项目会报错。
同理,Blpop只是从左边拿数据,就不多解释了。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容