Redis 流(Stream)方法使用详解

一、简介

  本文今天主要是流(Stream)的方法的使用,以及redis对应的Java实现该怎么用。因为篇幅问题,我这里写了一个测试类,引入 RedisTemplate对象,后面例子里就不一一引入了。大家理解就行,如果大家还不知道如何通过Spring Boot 整合redis则可以查看我之前的文章:SpringBoot整合redis(redis支持单节点和集群)

package com.alian.datastruct;

import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import java.util.List;
import java.util.concurrent.TimeUnit;

@Slf4j
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
public class RedisStreamTest {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
}

二、常用方法

2.1、XADD

  • XADD 向队列添加消息,如果指定的队列不存在,则创建一个队列

语法

XADD STREAM_NAME STREAM_ID FIELD VALUE [FIELD VALUE ...]

命令操作

127.0.0.1:6379> xadd stream1 * name alian age 28
"1672034159754-0"

  这里的 * 表示redis自动生成流ID,比如这里生成的是 1672034159754-0

Java操作

    @Test
    public void add() {
        String redisKey = "stream1";
        // 给流stream1,添加新元素
        Map<String, String> record = new HashMap<>();
        record.put("name", "alian");
        record.put("age", "28");
        redisTemplate.opsForStream().add(redisKey, record);
        List<MapRecord<String, Object, Object>> range = redisTemplate.opsForStream().range(redisKey, Range.unbounded());
        log.info("获取到的流的信息:{}",range);
    }
获取到的流的信息:[MapBackedRecord{recordId=1672035315041-0, kvMap={name=alian, age=28}}]

2.2、XRANGE、XREVRANGE

  • XRANGE 获取流中的数据(- 表示最小值,+表示最大值)
  • XREVRANGE 逆序获取流中的数据(- 表示最小值,+表示最大值)

语法

XRANGE STREAM_NAME start end [COUNT count]
XREVRANGE STREAM_NAME end start [COUNT count]

命令操作

127.0.0.1:6379> xadd stream2 * name alian
"1672036792167-0"
127.0.0.1:6379> xadd stream2 * age 28
"1672036804362-0"
127.0.0.1:6379> xrange stream2 - +
1) 1) "1672036792167-0"
   2) 1) "name"
      2) "alian"
2) 1) "1672036804362-0"
   2) 1) "age"
      2) "28"
127.0.0.1:6379> xrevrange stream2 + -
1) 1) "1672036804362-0"
   2) 1) "age"
      2) "28"
2) 1) "1672036792167-0"
   2) 1) "name"
      2) "alian"
127.0.0.1:6379> xrange stream2 - + COUNT 1
1) 1) "1672036792167-0"
   2) 1) "name"
      2) "alian"
  • 向流(stream2)中添加消息,字段 name,值 alian
  • 向流(stream2)中添加消息,字段 age,值 28
  • 获取流(stream2)中所有的数据
  • 逆序获取流(stream2)中所有的数据

Java操作

    @Test
    public void rangeAndRevRange() {
        String redisKey = "stream2";
        // 给流stream2,添加新元素
        Map<String, String> record1 = new HashMap<>();
        record1.put("name", "alian");
        redisTemplate.opsForStream().add(redisKey, record1);
        // 给流stream2,添加新元素
        Map<String, String> record2 = new HashMap<>();
        record2.put("age", "28");
        redisTemplate.opsForStream().add(redisKey, record2);
        List<MapRecord<String, Object, Object>> range = redisTemplate.opsForStream().range(redisKey, Range.unbounded());
        log.info("获取到的流的信息:{}",range);
        List<MapRecord<String, Object, Object>> revRange = redisTemplate.opsForStream().range(redisKey, Range.unbounded());
        log.info("逆序获取到的流的信息:{}",revRange);
        List<MapRecord<String, Object, Object>> rangeLimit = redisTemplate.opsForStream().range(redisKey, Range.unbounded(), RedisZSetCommands.Limit.limit().count(1));
        log.info("获取指定数量的流的信息:{}",rangeLimit);
    }
获取到的流的信息:[MapBackedRecord{recordId=1672036632962-0, kvMap={name=alian}}, MapBackedRecord{recordId=1672036632964-0, kvMap={age=28}}]
逆序获取到的流的信息:[MapBackedRecord{recordId=1672036632962-0, kvMap={name=alian}}, MapBackedRecord{recordId=1672036632964-0, kvMap={age=28}}]
获取指定数量的流的信息:[MapBackedRecord{recordId=1672036632962-0, kvMap={name=alian}}]

2.3、XTRIM

  • XTRIM 对流进行修剪,限制长度

语法

XTRIM STREAM_NAME MAXLEN [~] len

命令操作

127.0.0.1:6379> xadd stream3 * name alian
"1672038871792-0"
127.0.0.1:6379> xadd stream3 * age 28
"1672038883291-0"
127.0.0.1:6379> xadd stream3 * sex man
"1672038924677-0"
127.0.0.1:6379> xtrim stream3 MAXLEN 2
(integer) 1
127.0.0.1:6379> xrange stream3 - +
1) 1) "1672038883291-0"
   2) 1) "age"
      2) "28"
2) 1) "1672038924677-0"
   2) 1) "sex"
      2) "man"
  • 向流(stream3)中添加消息,字段 name,值 alian
  • 向流(stream3)中添加消息,字段 age,值 28
  • 向流(stream3)中添加消息,字段 sex,值 man
  • 使用(xtrim )对流进行修剪,限制长度为2
  • 获取流(stream2)中所有的数据,发现最先加入的数据被裁剪了:字段 name,值 alian

Java操作

    @Test
    public void xTrim() {
        String redisKey = "stream3";
        // 给流stream3,添加新元素
        Map<String, String> record1 = new HashMap<>();
        record1.put("name", "alian");
        redisTemplate.opsForStream().add(redisKey, record1);
        Map<String, String> record2 = new HashMap<>();
        record2.put("age", "28");
        redisTemplate.opsForStream().add(redisKey, record2);
        Map<String, String> record3 = new HashMap<>();
        record3.put("sex", "男");
        redisTemplate.opsForStream().add(redisKey, record3);
        // 对流进行裁剪
        Long trim = redisTemplate.opsForStream().trim(redisKey, 2);
        log.info("对流进行裁剪返回结果:{}",trim);
        // 获取流的信息
        List<MapRecord<String, Object, Object>> range = redisTemplate.opsForStream().range(redisKey, Range.unbounded());
        log.info("获取到的流的信息:{}",range);
    }
对流进行裁剪返回结果:1
获取到的流的信息:[MapBackedRecord{recordId=1672038780943-0, kvMap={age=28}}, MapBackedRecord{recordId=1672038780943-1, kvMap={sex=男}}]

2.4、XDEL

  • XDEL 移除指定元素

语法

XDEL STREAM_NAME STREAM_ID [STREAM_ID  ...]

命令操作

127.0.0.1:6379> xadd stream4 * name alian
"1672039288047-0"
127.0.0.1:6379> xadd stream4 * age 28
"1672039298619-0"
127.0.0.1:6379> xadd stream4 * sex man
"1672039305185-0"
127.0.0.1:6379> xdel stream4 "1672039298619-0" "1672039305185-0"
(integer) 2
127.0.0.1:6379> xrange stream4 - +
1) 1) "1672039288047-0"
   2) 1) "name"
      2) "alian"
  • 向流(stream4)中添加消息,字段 name,值 alian
  • 向流(stream4)中添加消息,字段 age,值 28
  • 向流(stream4)中添加消息,字段 sex,值 man
  • 使用(xdel )移除流中ID为, 1672039298619-0 1672039305185-0 的元素
  • 获取流(stream4)中所有的数据,发现只剩下一个元素了,ID为 1672039288047-0,字段 name,值 alian

Java操作

    @Test
    public void xDel() {
        String redisKey = "stream4";
        // 给流stream3,添加新元素
        Map<String, String> record1 = new HashMap<>();
        record1.put("name", "alian");
        RecordId recordId1 = redisTemplate.opsForStream().add(redisKey, record1);
        Map<String, String> record2 = new HashMap<>();
        record2.put("age", "28");
        RecordId recordId2 = redisTemplate.opsForStream().add(redisKey, record2);
        Map<String, String> record3 = new HashMap<>();
        record3.put("sex", "男");
        RecordId recordId3 = redisTemplate.opsForStream().add(redisKey, record3);
        // 删除后面两个流元素
        Long delete = redisTemplate.opsForStream().delete(redisKey, recordId2, recordId3);
        // 获取流的信息
        List<MapRecord<String, Object, Object>> range = redisTemplate.opsForStream().range(redisKey, Range.unbounded());
        log.info("获取到的流的信息:{}", range);
    }
获取到的流的信息:[MapBackedRecord{recordId=1672039170095-0, kvMap={name=alian}}]

2.5、XLEN

  • XLEN 获取流包含的元素数量,即消息长度

语法

XLEN STREAM_NAME

命令操作

127.0.0.1:6379> xadd stream5 * name alian
"1672039548344-0"
127.0.0.1:6379> xadd stream5 * age 28
"1672039557808-0"
127.0.0.1:6379> xadd stream5 * sex man
"1672039565111-0"
127.0.0.1:6379> xlen stream5
(integer) 3
  • 向流(stream5)中添加消息,字段 name,值 alian
  • 向流(stream5)中添加消息,字段 age,值 28
  • 向流(stream5)中添加消息,字段 sex,值 man
  • 使用(xlen )获取流包含的元素数量,得到 3

Java操作

    @Test
    public void xLen() {
        String redisKey = "stream5";
        // 给流stream3,添加新元素
        Map<String, String> record1 = new HashMap<>();
        record1.put("name", "alian");
        redisTemplate.opsForStream().add(redisKey, record1);
        Map<String, String> record2 = new HashMap<>();
        record2.put("age", "28");
        redisTemplate.opsForStream().add(redisKey, record2);
        Map<String, String> record3 = new HashMap<>();
        record3.put("sex", "男");
        redisTemplate.opsForStream().add(redisKey, record3);
        // 获取流包含的元素数量
        Long size = redisTemplate.opsForStream().size(redisKey);
        log.info("获取流包含的元素数量:{}", size);
        // 获取流的信息
    }
获取流包含的元素数量:3

2.6、XREAD

  • XREAD 以阻塞或非阻塞方式获取流元素

语法

XREAD [COUNT count] [BLOCK milliseconds] STREAMS key [key ...] id [id ...]

命令操作

127.0.0.1:6379> xadd stream6 * name alian
"1672047437914-0"
127.0.0.1:6379> xadd stream6 * age 28
"1672047445511-0"
127.0.0.1:6379> xadd stream6 * goods UAV
"1672047473355-0"
127.0.0.1:6379> xadd stream6 * price 99.9
"1672047482703-0"
127.0.0.1:6379> xread count 3 STREAMS stream6 0-0
1) 1) "stream6"
   2) 1) 1) "1672047437914-0"
         2) 1) "name"
            2) "alian"
      2) 1) "1672047445511-0"
         2) 1) "age"
            2) "28"
      3) 1) "1672047473355-0"
         2) 1) "goods"
            2) "UAV"
127.0.0.1:6379> xread count 2 BLOCK 10000  STREAMS stream6 0-0
1) 1) "stream6"
   2) 1) 1) "1672047437914-0"
         2) 1) "name"
            2) "alian"
      2) 1) "1672047445511-0"
         2) 1) "age"
            2) "28"
  • 向流(stream6)中添加消息,字段 name,值 alian
  • 向流(stream6)中添加消息,字段 age,值 28
  • 向流(stream6)中添加消息,字段 goods,值 UAV
  • 向流(stream6)中添加消息,字段 price,值 99.9
  • 使用(xread )非阻塞的方式获取流(stream6)中 3 个流元素
  • 使用(xread )阻塞的方式获取流(stream6)中 2 个流元素,超时时间为 10000毫秒

Java操作

    @Test
    public void xRead() {
        String redisKey = "stream6";
        // 给流stream6添加新元素
        Map<String, String> record1 = new HashMap<>();
        record1.put("name", "alian");
        redisTemplate.opsForStream().add(redisKey, record1);
        Map<String, String> record2 = new HashMap<>();
        record2.put("age", "28");
        redisTemplate.opsForStream().add(redisKey, record2);

        Map<String, String> record3 = new HashMap<>();
        record3.put("goods", "UAV");
        redisTemplate.opsForStream().add(redisKey, record3);
        Map<String, String> record4 = new HashMap<>();
        record4.put("price", "99.9");
        redisTemplate.opsForStream().add(redisKey, record4);

        // 获取流包含的元素数量
        List<MapRecord<String, Object, Object>> result1 = redisTemplate.opsForStream().read(StreamReadOptions.empty().count(3), StreamOffset.fromStart(redisKey));
        log.info("获取流包含的元素数量:{}", result1);
        // 阻塞方式读取流元素
        List<MapRecord<String, Object, Object>> result2 = redisTemplate.opsForStream().read(StreamReadOptions.empty().block(Duration.ofMillis(10 * 1000)).count(2), StreamOffset.fromStart(redisKey));
        log.info("阻塞方式读取流元素:{}", result2);
    }
获取流包含的元素数量:[MapBackedRecord{recordId=1672047314962-0, kvMap={name=alian}}, MapBackedRecord{recordId=1672047314964-0, kvMap={age=28}}, MapBackedRecord{recordId=1672047314964-1, kvMap={goods=UAV}}]
:阻塞方式读取流元素:[MapBackedRecord{recordId=1672047314962-0, kvMap={name=alian}}, MapBackedRecord{recordId=1672047314964-0, kvMap={age=28}}]

2.7、XGROUP

  • XGROUP CREATE 为流创建一个具有指定名字的消费者组
  • XGROUP SETID 修改消费者组的最后递送消息ID

语法

#STREAM_NAME存在
XGROUP create STREAM_NAME GROUP_NAME 0
#STREAM_NAME不存在
XGROUP create STREAM_NAME GROUP_NAME $ MKSTREAM

命令操作
xgroup create 必须目标流存在,如果不存在则在后面增加参数:MKSTREAM

127.0.0.1:6379> xgroup create stream7 group1 $ MKSTREAM
OK
127.0.0.1:6379> xgroup create stream7 group2 0
OK
127.0.0.1:6379> xgroup create stream7 group3 0
OK
127.0.0.1:6379> xinfo groups stream7
1) 1) "name"
   2) "group1"
   3) "consumers"
   4) (integer) 0
   5) "pending"
   6) (integer) 0
   7) "last-delivered-id"
   8) "0-0"
2) 1) "name"
   2) "group2"
   3) "consumers"
   4) (integer) 0
   5) "pending"
   6) (integer) 0
   7) "last-delivered-id"
   8) "0-0"
3) 1) "name"
   2) "group3"
   3) "consumers"
   4) (integer) 0
   5) "pending"
   6) (integer) 0
   7) "last-delivered-id"
   8) "0-0"
  • 通过 xgroup create 为流(stream7)创建组( group1 ),如果流本身不存在则在后面加参数: $ MKSTREAM
  • 通过 xgroup create 为流(stream7)创建组( group2
  • 通过 xgroup create 为流(stream7)创建组( group3
  • 通过 xinfo groups stream7 查看流(stream7)的组信息

  我们演示下xgroup setid的使用

127.0.0.1:6379> xgroup setid stream7 group2 5
OK
127.0.0.1:6379> xadd stream7 * name alian
"1672119736048-0"
127.0.0.1:6379> xinfo groups stream7
1) 1) "name"
   2) "group1"
   3) "consumers"
   4) (integer) 0
   5) "pending"
   6) (integer) 0
   7) "last-delivered-id"
   8) "0-0"
2) 1) "name"
   2) "group2"
   3) "consumers"
   4) (integer) 0
   5) "pending"
   6) (integer) 0
   7) "last-delivered-id"
   8) "5-0"           ##投送ID变成了5
3) 1) "name"
   2) "group3"
   3) "consumers"
   4) (integer) 0
   5) "pending"
   6) (integer) 0
   7) "last-delivered-id"
   8) "0-0"
  • 通过 xgroup setid 给流(stream7)修改消费者组( group2 )的最后递送消息ID,修改为 5
  • 通过 xgroup create 为流(stream7)创建组( group2
  • 向流(stream7)中添加消息,字段 name,值 alian
  • 通过 xinfo groups 查看流(stream7)的组信息,看到最后的投送ID已经变成了 5-0

Java操作

    @Test
    public void xGroup() {
        String redisKey = "stream7";
        String group1 = redisTemplate.opsForStream().createGroup(redisKey, "group1");
        log.info("创建第一个组返回:{}",group1);
        String group2 = redisTemplate.opsForStream().createGroup(redisKey, "group2");
        log.info("创建第二个组返回:{}",group2);
        String group3 = redisTemplate.opsForStream().createGroup(redisKey, "group3");
        log.info("创建第三个组返回:{}",group3);
        StreamInfo.XInfoGroups groups = redisTemplate.opsForStream().groups(redisKey);
        log.info("获取组的信息:{}",groups);
    }
创建第一个组返回:OK
创建第二个组返回:OK
创建第三个组返回:OK
获取组的信息:XInfoGroups[
	XInfoStream{name=group1, consumers=0, pending=0, last-delivered-id=0-0}, 
	XInfoStream{name=group2, consumers=0, pending=0, last-delivered-id=0-0}, 
	XInfoStream{name=group3, consumers=0, pending=0, last-delivered-id=0-0}
]

2.8、XREADGROUP

  • XREADGROUP 读取消费者组中的消息

语法

XREADGROUP GROUP group consumer [COUNT count] [BLOCK milliseconds] [NOACK] STREAMS key [key ...] id [id ...]

命令操作

127.0.0.1:6379> xgroup create stream8 group1 $ mkstream
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> xadd stream8 * a 1
QUEUED
127.0.0.1:6379> xadd stream8 * a 2
QUEUED
127.0.0.1:6379> xadd stream8 * a 3
QUEUED
127.0.0.1:6379> exec
1) "1672128676947-0"
2) "1672128676947-1"
3) "1672128676947-2"
127.0.0.1:6379> xreadgroup group group1 consumer1 count 1 streams stream8 >
1) 1) "stream8"
   2) 1) 1) "1672128676947-0"
         2) 1) "a"
            2) "1"
127.0.0.1:6379> xreadgroup group group1 consumer2 count 1 streams stream8 >
1) 1) "stream8"
   2) 1) 1) "1672128676947-1"
         2) 1) "a"
            2) "2"
127.0.0.1:6379> xreadgroup group group1 consumer1 count 1 streams stream8 >
1) 1) "stream8"
   2) 1) 1) "1672128676947-2"
         2) 1) "a"
            2) "3"
127.0.0.1:6379> xreadgroup group group1 consumer2 count 1 streams stream8 >
(nil)
  • 通过 xgroup create 为流(stream8)创建组( group1 ),如果流本身不存在则在后面加参数: $ MKSTREAM
  • 使用事务的方式向流(stream8)中添加消息,字段 a,值 1;字段 a,值 2;字段 a,值 3
  • 通过 xreadgroup 的一个消费者(consumer1)读取流(stream8)中的一条消息,读取到的元素ID为:1672128676947-0
  • 通过 xreadgroup 的一个消费者(consumer2)读取流(stream8)中的一条消息,读取到的元素ID为:1672128676947-1
  • 通过 xreadgroup 的一个消费者(consumer1)读取流(stream8)中的一条消息,读取到的元素ID为:1672128676947-2
  • 通过 xreadgroup 的一个消费者(consumer2)读取流(stream8)中的一条消息,未读取到元素了

Java操作

    @Test
    public void xReadGroup() {
        String redisKey = "stream8";
        String group1 = redisTemplate.opsForStream().createGroup(redisKey, "group1");
        log.info("创建第一个组返回:{}", group1);
        // 消费者
        Consumer consumer = Consumer.from("group1", "consumer1");
        while (true) {
            // 读取消息
            List<MapRecord<String, Object, Object>> list = redisTemplate.opsForStream().read(consumer, StreamReadOptions.empty().count(1).block(Duration.ofSeconds(5)), StreamOffset.create(redisKey, ReadOffset.lastConsumed()));
            log.info("读取到的信息:{}", list);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

我们通过客户端添加消息

127.0.0.1:6379> xadd stream8 * a 1
"1672127284221-0"
127.0.0.1:6379> xadd stream8 * a 2
"1672127323212-0"
127.0.0.1:6379> xadd stream8 * a 3
"1672127327613-0"
读取到的信息:[MapBackedRecord{recordId=1672127284221-0, kvMap={a=1}}]
读取到的信息:[MapBackedRecord{recordId=1672127323212-0, kvMap={a=2}}]
读取到的信息:[MapBackedRecord{recordId=1672127327613-0, kvMap={a=3}}]

2.9、XPENDING

  • XPENDING 显示待处理消息的相关信息

语法

XPENDING key group [[IDLE min-idle-time] start end count [consumer]]

命令操作

先初始化信息

127.0.0.1:6379> xgroup create stream9 group1 $ mkstream
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> xadd stream9 * b 1
QUEUED
127.0.0.1:6379> xadd stream9 * b 2
QUEUED
127.0.0.1:6379> xadd stream9 * b 3
QUEUED
127.0.0.1:6379> exec
1) "1672190304546-0"
2) "1672190304546-1"
3) "1672190304546-2"
127.0.0.1:6379> xreadgroup group group1 consumer1 count 1 streams stream9 >
1) 1) "stream9"
   2) 1) 1) "1672190304546-0"
         2) 1) "b"
            2) "1"
127.0.0.1:6379> xreadgroup group group1 consumer2 count 1 streams stream9 >
1) 1) "stream9"
   2) 1) 1) "1672190304546-1"
         2) 1) "b"
            2) "2"
127.0.0.1:6379> xreadgroup group group1 consumer1 count 1 streams stream9 >
1) 1) "stream9"
   2) 1) 1) "1672190304546-2"
         2) 1) "b"
            2) "3"

上面的操作和之前是一样的就不解释了,接下里获取信息

127.0.0.1:6379> xpending stream9 group1
1) (integer) 3
2) "1672190304546-0"   #首条消息的ID
3) "1672190304546-2"   #最后一条消息的ID
4) 1) 1) "consumer1"   #各个消费者目前症状处理的消息数量
      2) "2"
   2) 1) "consumer2"
      2) "1"
127.0.0.1:6379> xpending stream9 group1 - + 2     #最多取出2条待处理的相关信息
1) 1) "1672190304546-0"
   2) "consumer1"
   3) (integer) 250258
   4) (integer) 1
2) 1) "1672190304546-1"
   2) "consumer2"
   3) (integer) 238307
   4) (integer) 1
127.0.0.1:6379> xpending stream9 group1 - + 3      #最多取出3条待处理的相关信息
1) 1) "1672190304546-0"
   2) "consumer1"
   3) (integer) 265972
   4) (integer) 1
2) 1) "1672190304546-1"
   2) "consumer2"
   3) (integer) 254021
   4) (integer) 1
3) 1) "1672190304546-2"
   2) "consumer1"
   3) (integer) 239477
   4) (integer) 1
127.0.0.1:6379> xpending stream9 group1 - + 3 consumer2    #最多取出3条与给定消费者consumer2的相关信息
1) 1) "1672190304546-1"
   2) "consumer2"
   3) (integer) 270089
   4) (integer) 1
  • 通过 xpending stream9 group1 可以查看到流的基本信息,包括 首条消息的ID、最后一条消息的ID、各个消费者目前症状处理的消息数量
  • 也可以在命令后面增加参数 count ,意思就是最多取出 count 条待处理的相关信息
  • 当然也可以在命令后面增加参数 count ,并指定消费者,比如 consumer2,意思就是最多取出 count 条与给定消费者 consumer2 的相关信息

Java操作

  需要注意的是,我这里的初始化的数据,都是通过客户端来生成的,也就是上面的命令初始化的操作。然后直接通过方法 pending()方法获取相关信息。

    @Test
    public void xPending() {
        String redisKey = "stream9";
//        String group1 = redisTemplate.opsForStream().createGroup(redisKey, "group1");
//        log.info("创建第一个组返回:{}", group1);
        PendingMessagesSummary pendingSummary = redisTemplate.opsForStream().pending(redisKey, "group1");
        log.info("显示待处理的消息:{}", pendingSummary);
        PendingMessages pendingMessages = redisTemplate.opsForStream().pending(redisKey, "group1", Range.unbounded(), 2);
        log.info("最多显示2条待处理的消息:{}", pendingMessages);
        PendingMessages pending = redisTemplate.opsForStream().pending(redisKey, Consumer.from("group1", "consumer2"));
        log.info("显示给定消费者2待处理的相关信息:{}", pending);
    }
显示待处理的消息:PendingMessagesSummary{
	groupName = 'group1',
    totalPendingMessages = '3',
    minMessageId = '1672190304546-0', 
    maxMessageId = '1672190304546-2', 
    pendingMessagesPerConsumer = {
		consumer1 = 2,
		consumer2 = 1
	}
}
最多显示2条待处理的消息:PendingMessages{
	groupName = 'group1', 
    range = unbounded - unbounded, 
    pendingMessages = [PendingMessage {
		id = 1672190304546 - 0, 
        consumer = group1: consumer1, 
        elapsedTimeSinceLastDeliveryMS = 1216746, 
        totalDeliveryCount = 1
	}, PendingMessage {
		id = 1672190304546 - 1, 
        consumer = group1: consumer2, 
        elapsedTimeSinceLastDeliveryMS = 1204795, 
        totalDeliveryCount = 1
	}]
}
显示给定消费者2待处理的相关信息:PendingMessages{
	groupName = 'group1', 
    range = unbounded - unbounded, 
    pendingMessages = [PendingMessage {
		id = 1672190304546 - 1, 
        consumer = group1: consumer2, 
        elapsedTimeSinceLastDeliveryMS = 1204798, 
        totalDeliveryCount = 1
	}]
}

2.10、XACK

  • XACK 将消息标记为“已处理”

语法

XACK STREAM_NAME group id [id ...]

命令操作

127.0.0.1:6379> xack stream9 group1 1672190304546-2
(integer) 1
127.0.0.1:6379> xpending stream9 group1
1) (integer) 1
2) "1672190304546-0"
3) "1672190304546-1"
4) 1) 1) "consumer1"
      2) "1"           #此处结果减了1
   2) 1) "consumer2"
      2) "1"

  通过命令的方式标记了消费者1 consumer1的一条记录 1672190304546-2 标记为已处理

Java操作

    @Test
    public void xAck() {
        String redisKey = "stream9";
        // 消费者2的消息进行标记
        Long acknowledge = redisTemplate.opsForStream().acknowledge(redisKey, "group1", "1672190304546-1");
        log.info("将消息标记为已处理:{}", acknowledge);
        PendingMessagesSummary pendingSummary = redisTemplate.opsForStream().pending(redisKey, "group1");
        log.info("显示待处理的消息:{}", pendingSummary);
    }
将消息标记为已处理:1
显示待处理的消息: PendingMessagesSummary {
	groupName = 'group1', 
    totalPendingMessages = '1', 
    minMessageId = '1672190304546-0', 
    maxMessageId = '1672190304546-0', 
    pendingMessagesPerConsumer = {
		consumer1 = 1
	}
}

  通过java方式把消费者2的一条记录 1672190304546-1 标记为已处理,最后就只剩一条消息了

2.11、XCLAIM

  • XCLAIM 转移消息的归属权

语法

XCLAIM key group consumer min-idle-time id [id ...] [IDLE ms]
  [TIME unix-time-milliseconds] [RETRYCOUNT count] [FORCE] [JUSTID] [LASTID id]

命令操作

127.0.0.1:6379> xpending stream9 group1
1) (integer) 1
2) "1672190304546-0"
3) "1672190304546-0"
4) 1) 1) "consumer1"     #原来是consumer1
      2) "1"
127.0.0.1:6379> xclaim stream9 group1 consumer2 5000 1672190304546-0
1) 1) "1672190304546-0"
   2) 1) "b"
      2) "1"
127.0.0.1:6379> xpending stream9 group1
1) (integer) 1
2) "1672190304546-0"
3) "1672190304546-0"
4) 1) 1) "consumer2"    #现在是consumer2
      2) "1"

  从结果上我们看下消息从 consumer1转移到了 consumer2上面去了

127.0.0.1:6379> xclaim stream9 group1 consumer1 5000 1672190304546-0 JUSTID
1) "1672190304546-0"
127.0.0.1:6379> xpending stream9 group1
1) (integer) 1
2) "1672190304546-0"
3) "1672190304546-0"
4) 1) 1) "consumer1"
      2) "1"

  从结果上我们看下消息又从 consumer2转移到了 consumer1上面去了,只不过使用 JUSTID,只会返回ID

Java操作

    @Test
    public void xClaim() {
        List<ByteRecord> recordList = redisTemplate.execute((RedisCallback<List<ByteRecord>>) connection -> {
            // XCLAIM指令的实现
            return connection.streamCommands().xClaim("stream9".getBytes(), "group1", "consumer2", Duration.ofSeconds(10), RecordId.of("1672190304546-0"));
        });
        if (recordList != null) {
            for (ByteRecord byteRecord : recordList) {
                log.info("修改消息的消费者:id={}, value={}", byteRecord.getId(), byteRecord.getValue());
            }
        }
    }
修改消息的消费者:id=1672190304546-0, value={[B@7c1b22a9=[B@334b392d}

2.12、XINFO

  • XINFO GROUPS 打印消费组信息
  • XINFO CONSUMERS 打印消费者信息
  • XINFO STREAM 打印流信息

语法

XINFO GROUPS key
XINFO CONSUMERS key groupname
XINFO STREAM key [FULL [COUNT count]]

命令操作

127.0.0.1:6379> xinfo  groups stream9
1) 1) "name"
   2) "group1"
   3) "consumers"
   4) (integer) 2
   5) "pending"
   6) (integer) 1
   7) "last-delivered-id"
   8) "1672190304546-2"
127.0.0.1:6379> xinfo consumers stream9 group1
1) 1) "name"
   2) "consumer1"
   3) "pending"
   4) (integer) 1
   5) "idle"
   6) (integer) 231744
2) 1) "name"
   2) "consumer2"
   3) "pending"
   4) (integer) 0
   5) "idle"
   6) (integer) 440873
127.0.0.1:6379> xinfo stream stream9
 1) "length"
 2) (integer) 3
 3) "radix-tree-keys"
 4) (integer) 1
 5) "radix-tree-nodes"
 6) (integer) 2
 7) "groups"
 8) (integer) 1
 9) "last-generated-id"
10) "1672190304546-2"
11) "first-entry"
12) 1) "1672190304546-0"
    2) 1) "b"
       2) "1"
13) "last-entry"
14) 1) "1672190304546-2"
    2) 1) "b"
       2) "3"
  • 通过 XINFO GROUPS 打印流( stream9 )的消费组信息
  • 通过 XINFO CONSUMERS 打印流( stream9 )中组的 group1 的消费者信息
  • 通过 XINFO STREAM 打印流( stream9 )的相关信息

Java操作

    @Test
    public void xInfo() {
        String redisKey = "stream9";
        // 消费者2的消息进行标记
        StreamInfo.XInfoGroups groups = redisTemplate.opsForStream().groups(redisKey);
        log.info("获取组的信息:{}", groups);
        StreamInfo.XInfoConsumers consumers = redisTemplate.opsForStream().consumers(redisKey, "group1");
        log.info("获取消费者的信息:{}", consumers);
        StreamInfo.XInfoStream infoStream = redisTemplate.opsForStream().info(redisKey);
        log.info("获取流的信息:{}", infoStream);
    }
获取组的信息: XInfoGroups[XInfoStream {
	 name = group1, 
     consumers = 2, 
     pending = 1, 
      last - delivered - id = 1672190304546 - 2
}]
获取消费者的信息: XInfoConsumers[XInfoStream {
        name = consumer1, 
        pending = 1,
        idle = 546332
    }, XInfoStream {
        name = consumer2, pending = 0, idle = 755461
    }
]
获取流的信息: XInfoStream {
	length = 3, 
    radix - tree - keys = 1, 
    radix - tree - nodes = 2, 
    groups = 1, 
    last - generated - id = 1672190304546 - 2,
    first - entry = {
		1672190304546 - 0 = {
			[B @6fe595dc = [B @3a8cea24
		}
	},
	last - entry = {
		1672190304546 - 2 = {
			[B @5af5d76f = [B @1eb9a3ef
		}
	}
}
  • 5
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值