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得时候,不知道哪里写的不太合适,客户端消息收到一定程度,剩下的消息收不到,修改了缓冲区大小,还是没有解决问题,后面因为项目结束期比较紧张,没有时间调试消息的时候, ...
随机推荐
- CBR云备份与恢复管控简介
本文分享自天翼云开发者社区<CBR云备份与恢复管控简介>,作者:c****n 1.CBR云备份与恢复介绍 CBR (Cloud Backup & Restore)是一般云厂商提供的 ...
- Apache Camel系列(2)----Hello World
下面创建一个Apache Camel的Hello World程序,该程序使用Maven,Intellij 15,运行环境是JDK 8. 1,创建一个maven工程,在pom.xml文件中添加apa ...
- Luogu P3059 Concurrently Balanced Strings G 题解 [ 紫 ] [ 线性 dp ] [ 哈希 ] [ 括号序列 ]
模拟赛搬的题,dp 思路很明显,但难点就在于找到要转移的点在哪. 暴力 首先我们可以先考虑 \(k=1\) 的情况,这应该很好想,就是对于每一个右括号,找到其匹配的左括号,然后进行转移即可,这个过程可 ...
- 从0搭建Vue3组件库(一): 开篇
前言 这是从0搭建Vue3组件库系列文章第一篇文章,这个系列我曾经写过多篇文章,但是写完之后回过头来再看里面有很多遗漏以及不足之处,所以决定重新梳理这个系列,并从头开始搭建一个完整的Vue3组件库工程 ...
- nginx 强制https
nginx 强制https 通常有如下两种方法强制https推荐第二种,第二种更高效1.使用nginx的rewrite方法 server { listen 80; server_name xxx. ...
- OpenLayers 绘制带箭头的LineString
<!--******************************************************************** * Copyright 2000 - 2022 ...
- 记vue修改数组属性,dom不发生变化的问题
目录: 目录 目录: 开篇 正确的姿势 为什么 $set 开篇 今天在写vue的时候,出现了一个以前可能没遇到的问题.我利用一个数组记录列表下按钮的启用.禁用状态,但我点击某个列表项按钮后,会修改当前 ...
- mac 触控板 三指拖动
1. 打开系统偏好设置 点击屏幕左上角的苹果图标(),选择"系统设置". 2. 打开指针控制 在系统偏好设置窗口左侧栏中,点击"辅助功能",然后在右侧列表中, ...
- 入口函数与包初始化:Go程序的执行次序
前言 我们可能经常会遇到这样一个问题:一个 Go 项目中有数十个 Go 包,每个包中又有若干常量.变量.各种函数和方法,那 Go 代码究竟是从哪里开始执行的呢?后续的执行顺序又是什么样的呢? 事实上, ...
- Django实战项目-学习任务系统-兑换物品管理
接着上期代码框架,开发第5个功能,兑换物品管理,再增加一个学习兑换物品表,主要用来维护兑换物品,所需积分,物品状态等信息,还有一个积分流水表,完成任务奖励积分,兑换物品消耗积分. 要想激励一个人的学习 ...