Redis Stream消息队列

工具类部分内容
package com.hwd.campus.common.redis.utils;
import com.hwd.campus.common.redis.constant.RedisKeyPrefixConst;
import com.hwd.campus.common.redis.service.RedisListSelect;
import com.hwd.campus.common.redis.service.RedisSelect;
import lombok.AllArgsConstructor;
import org.springframework.data.redis.connection.stream.Record;
import org.springframework.data.redis.connection.stream.StreamInfo;
import org.springframework.data.redis.core.*;
import org.springframework.stereotype.Component;
import java.util.*;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
/**
* @author
* @datetime 2023-01-11 09:25:52
* @description
*/
@Component
@AllArgsConstructor
public class RedisUtils {
private RedisTemplate<String, Object> redisTemplate;
private StringRedisTemplate stringRedisTemplate;
private static final Long DAY_SECONDS = 60 * 60 * 24L;
private static final Long SEVEN_DAY_SECONDS = 7 * DAY_SECONDS;
public StreamInfo.XInfoGroups groups(String key) {
return stringRedisTemplate.opsForStream().groups(key);
}
public void addGroup(String key, String groupName) {
stringRedisTemplate.opsForStream().createGroup(key, groupName);
}
/**
* 添加流
*
* @param streamKey 流关键
* @param msgContext 上下文
*/
public void addStream(String streamKey, Object msgContext) {
stringRedisTemplate.opsForStream().add(Record.of(msgContext).withStreamKey(streamKey));
}
}
此处采用Stream实现消息队列
创建监听器
package com.hwd.campus.manage.biz.listener;
import com.hwd.campus.common.redis.constant.RedisKeyPrefixConst;
import com.hwd.campus.common.redis.utils.RedisUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.stream.*;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.data.redis.stream.StreamMessageListenerContainer;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.time.Duration;
/**
* @author
* @datetime 2023-01-14 11:04:28
* @description 消费监听,自动ack
*/
@Slf4j
@Component
public class LogStreamConsumerRunner implements ApplicationRunner, DisposableBean {
@Resource
private RedisConnectionFactory redisConnectionFactory;
@Resource
private ThreadPoolTaskExecutor threadPoolTaskExecutor;
@Resource
private LogStreamConsumer logStreamConsumer;
@Resource
private RedisUtils redisUtils;
private StreamMessageListenerContainer<String, ObjectRecord<String, String>> streamMessageListenerContainer;
@Override
public void run(ApplicationArguments args) {
addConsumeGroup(RedisKeyPrefixConst.OPERATE_LOG_STREAM_KEY, RedisKeyPrefixConst.OPERATE_LOG_CONSUME_GROUP);
addConsumeGroup(RedisKeyPrefixConst.LOGIN_LOG_STREAM_KEY, RedisKeyPrefixConst.LOGIN_LOG_CONSUME_GROUP);
threadPoolTaskExecutor.setMaxPoolSize(100);
// 创建配置对象
StreamMessageListenerContainer.StreamMessageListenerContainerOptions<String, ObjectRecord<String, String>> options =
StreamMessageListenerContainer.StreamMessageListenerContainerOptions
.builder()
// 一次性最多拉取多少条消息
.batchSize(10)
//执行消息轮询的执行器
.executor(this.threadPoolTaskExecutor)
// 消息消费异常的handler
.errorHandler(Throwable::printStackTrace)
//超时时间,设置为0,表示不超时(超时后会抛出异常)
.pollTimeout(Duration.ZERO)
// 序列化器
.serializer(new StringRedisSerializer())
.targetType(String.class)
.build();
//根据配置对象创建监听容器对象
streamMessageListenerContainer = StreamMessageListenerContainer.create(this.redisConnectionFactory, options);
//使用监听容器对象开始监听消费
receiveAutoAck(RedisKeyPrefixConst.OPERATE_LOG_CONSUME_GROUP, RedisKeyPrefixConst.OPERATE_LOG_CONSUME_NAME, RedisKeyPrefixConst.OPERATE_LOG_STREAM_KEY);
receiveAutoAck(RedisKeyPrefixConst.LOGIN_LOG_CONSUME_GROUP, RedisKeyPrefixConst.LOGIN_LOG_CONSUME_NAME, RedisKeyPrefixConst.LOGIN_LOG_STREAM_KEY);
//启动监听
streamMessageListenerContainer.start();
}
private void receiveAutoAck(String consumeGroup, String consumeName, String streamKey) {
streamMessageListenerContainer.receiveAutoAck(
Consumer.from(consumeGroup, consumeName),
StreamOffset.create(streamKey, ReadOffset.lastConsumed()), this.logStreamConsumer);
}
private void addConsumeGroup(String streamKey, String consumeGroup) {
if (redisUtils.hasKey(streamKey)) {
StreamInfo.XInfoGroups groups = redisUtils.groups(streamKey);
if (groups.isEmpty()) {
redisUtils.addGroup(streamKey, consumeGroup);
}
} else {
redisUtils.addGroup(streamKey, consumeGroup);
}
}
@Override
public void destroy() {
this.streamMessageListenerContainer.stop();
}
}
进行消费进行日志增加
package com.hwd.campus.manage.biz.listener;
import cn.hutool.json.JSONUtil;
import com.hwd.campus.manage.biz.model.vo.LoginVo;
import com.hwd.campus.manage.biz.service.ILoginLogService;
import com.hwd.campus.manage.biz.service.IOperateLogService;
import com.hwd.campus.common.redis.constant.RedisKeyPrefixConst;
import com.hwd.campus.common.redis.utils.RedisUtils;
import com.hwd.campus.common.web.filter.model.OperateLogModel;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.connection.stream.ObjectRecord;
import org.springframework.data.redis.stream.StreamListener;
import org.springframework.stereotype.Component;
import java.util.Objects;
/**
* @author
*/
@Component
@Slf4j
@AllArgsConstructor
public class LogStreamConsumer implements StreamListener<String, ObjectRecord<String, String>> {
private RedisUtils redisUtils;
private IOperateLogService manageOperateLogService;
private ILoginLogService manageLoginLogService;
@Override
public void onMessage(ObjectRecord<String, String> message) {
log.info("接受到来自redis的消息");
log.info(("message id " + message.getId().getValue()));
String stream = message.getStream();
log.info(("stream " + stream));
Object value = message.getValue();
log.info(("value " + value));
if (RedisKeyPrefixConst.OPERATE_LOG_STREAM_KEY.equals(stream)) {
OperateLogModel operateLogModel = JSONUtil.toBean(message.getValue(), OperateLogModel.class);
manageOperateLogService.addOperateLog(operateLogModel);
} else if (RedisKeyPrefixConst.LOGIN_LOG_STREAM_KEY.equals(stream)) {
LoginVo loginVo = JSONUtil.toBean(message.getValue(), LoginVo.class);
manageLoginLogService.addLoginLog(loginVo);
}
//消费完毕删除该条消息
redisUtils.streamDelete(Objects.requireNonNull(stream), message.getId().getValue());
}
}
可通过接口往stream里面set值
redisUtils.addStream(RedisKeyPrefixConst.LOGIN_LOG_STREAM_KEY, JSONUtil.toJsonStr(loginVo));
Redis Stream消息队列的更多相关文章
- 程序员过关斩将--redis做消息队列,香吗?
Redis消息队列 在程序员这个圈子打拼了太多年,见过太多的程序员使用redis,其中一部分喜欢把redis做缓存(cache)使用,其中最典型的当属存储用户session,除此之外,把redis作为 ...
- Redis 做消息队列
一般来说,消息队列有两种场景,一种是发布者订阅者模式,一种是生产者消费者模式.利用redis这两种场景的消息队列都能够实现.定义: 生产者消费者模式:生产者生产消息放到队列里,多个消费者同时监听队列, ...
- Redis作为消息队列服务场景应用案例
NoSQL初探之人人都爱Redis:(3)使用Redis作为消息队列服务场景应用案例 一.消息队列场景简介 “消息”是在两台计算机间传送的数据单位.消息可以非常简单,例如只包含文本字符串:也可以更 ...
- redis resque消息队列
Resque 目前正在学习使用resque .resque-scheduler来发布异步任务和定时任务,为了方便以后查阅,所以记录一下. resque和resque-scheduler其优点在于功能比 ...
- 【springboot】【redis】springboot+redis实现发布订阅功能,实现redis的消息队列的功能
springboot+redis实现发布订阅功能,实现redis的消息队列的功能 参考:https://www.cnblogs.com/cx987514451/p/9529611.html 思考一个问 ...
- 【Redis】php+redis实现消息队列
在项目中使用消息队列一般是有如下几个原因: 把瞬间服务器的请求处理换成异步处理,缓解服务器的压力 实现数据顺序排列获取 redis实现消息队列步骤如下: 1).redis函数rpush,lpop 2) ...
- Lumen开发:结合Redis实现消息队列(1)
1.简介 Lumen队列服务为各种不同的后台队列提供了统一的API.队列允许你推迟耗时任务(例如发送邮件)的执行,从而大幅提高web请求速度. 1.1 配置 .env文件的QUEUE_DRIVER选项 ...
- Redis除了做缓存--Redis做消息队列/Redis做分布式锁/Redis做接口限流
1.用Redis实现消息队列 用命令lpush入队,rpop出队 Long size = jedis.lpush("QueueName", message);//返回存放的数据条数 ...
- sping+redis实现消息队列的乱码问题
使用spring支持redis实现消息队列,参考官方样例:https://spring.io/guides/gs/messaging-redis/ 实现后在运行过程中发现消费者在接收消息时会出现乱码的 ...
- go+redis实现消息队列发布与订阅
在做项目过程中,实现websocket得时候,不知道哪里写的不太合适,客户端消息收到一定程度,剩下的消息收不到,修改了缓冲区大小,还是没有解决问题,后面因为项目结束期比较紧张,没有时间调试消息的时候, ...
随机推荐
- MySql中创建用户以及设置其操作权限
以下设置针对MySql8+版本进行测试,低版本暂无测试. 以管理员身份CMD并定位到MySql安装的bin目录,然后执行命令mysql -u root -p登录到MySql,然后输入登录密码,登录成功 ...
- InfluxDB修改数据存储位置(二进制安装版)
InfluxDB修改数据存储位置(二进制安装版) 在二进制安装方式下,修改InfluxDB的数据存储位置通常涉及以下几个步骤.以下步骤以InfluxDB 2.x版本为例进行说明,因为InfluxDB ...
- Luogu P11628 WC2025 猫粮 题解 [ 绿 ] [ 贪心 ] [ adhoc ] [ 鸽巢原理 ]
猫粮:WC 诈骗题.我竟然能切 WC 的 T3 也是逆天了. 话说切了猫粮能变成猫娘吗 qwq. 思路 首先题目里有下面几点关键的性质: 所有猫粮质量总和等于所有猫要吃的质量总和. 优质的有 \(n\ ...
- Net跨平台硬件信息查询库 Hardware.Info:全面获取系统硬件详情
Hardware.Info 是一个基于 .NET Standard 2.0 的跨平台库,提供了硬件信息查询的功能,支持 Windows.Linux 和 macOS 操作系统.该库通过不同平台下的系统接 ...
- 用 C# 插值字符串处理器写一个 sscanf
插值字符串处理器 C# 有一个特性叫做插值字符串,使用插值字符串,你可以自然地往字符串里面插入变量的值,比如:$"abc{x}def",这一改以往通过 string.Format ...
- [开源自荐] Catime 不一样的计时器(番茄时钟),非常欢迎反馈
Catime 一款简洁的 Windows 倒计时工具,具有透明界面和丰富的自定义选项. Github:https://github.com/vladelaina/Catime 特点 极简设计: 透明界 ...
- Typecho弹出find Input author error怎么解决
大多数报错的起因就是因为,有些模板归档页面的评论功能被阉割掉了 于是导致一些评论验证功能的插件爆这个错误. #解决方法有以下三种 1,编辑这些没有评论功能的页面,高级设置,关闭评论,然后发布文章. 2 ...
- PowerShell开发游戏 · 打蜜蜂
可以看到,虽然非常抽象简单,但是基础游戏框架已经搭建,游戏机制完善,就缺美工了,哈哈~~~~ [首先] Powershell不是用来开发游戏的,但是没人规定不能开发.因为它可以调取windo ...
- Flink学习(九) Sink到Kafka
package com.wyh.streamingApi.sink import java.util.Properties import org.apache.flink.api.common.ser ...
- java.lang.IllegalStateException: File name has been re-used with different files. (flume报错)
报错日志: java.lang.IllegalStateException: File name has been re-used with different files. Spooling ass ...