目录
一、简介
本文今天主要是流(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
}
}
}