【Redis笔记】基于Redis的Stream结构作为消息队列,实现异步任务

使用redis命令创建消息队列

在redis-cli中执行如下指令

XGROUP CREATE key groupName ID [MKSTREAM]

key:队列名称
groupName:消费者组名称
ID:起始ID标示,$代表队列中最后一个消息,0代表队列中第一个消息
MKSTREAM:队列不存在时自动创建队列

示例:

XGROUP CREATE streams.orders g1 0 MKSTREAM

编写Lua脚本,向redis消息队列中发送消息

-- lua脚本中其他事项处理部分-- 获取调用的参数列表
-- 优惠卷id
local voucherId = ARGV[1]
-- 用户id
local userId = ARGV[2]
-- 订单id
local orderId = ARGV[3]-- key
-- 库存key
local stockKey = 'seckill:stock:' .. voucherId
-- 订单key
local orderKey = 'seckill:order:' .. voucherId-- 业务
-- 判断库存是否充足
if(tonumber(redis.call('get', stockKey)) <= 0) then-- 库存不足return 1
end
-- 判断用户是否已经下单 SISMEMBER orderKey userId
if(redis.call('sismember', orderKey, userId) == 1) then-- 存在说明重复下单return 2
end
-- 扣库存,下单
redis.call('incrby', stockKey, -1)
redis.call('sadd', orderKey, userId)
-- 发消息到队列, XADD stream.orders * k1 v1 k2 v2 ...
redis.call('xadd', 'stream.orders', '*', 'userId', userId, 'voucherId', voucherId, 'id', orderId)return 0

业务代码——执行Lua脚本

	private static final DefaultRedisScript<Long> SECKILL_SCRIPT;static {SECKILL_SCRIPT = new DefaultRedisScript<>();// 从resources目录下加载脚本SECKILL_SCRIPT.setLocation(new ClassPathResource("seckill.lua"));// lua脚本执行返回值SECKILL_SCRIPT.setResultType(Long.class);}@Overridepublic Result seckillVoucher(Long voucherId) {// 获取用户Long userId = UserHolder.getUser().getId();// 订单Idlong orderId = redisIdWorker.nextId("order");// 执行lua脚本int result = stringRedisTemplate.execute(SECKILL_SCRIPT,Collections.emptyList(),voucherId.toString(),userId.toString(),String.valueOf(orderId)).intValue();// 判断结果为0if (result != 0) {// 不为0,没有购买资格return Result.fail(result == 1 ? "库存不足" : "不能重复下单");}// 获取代理对象(事务)proxy = (IVoucherOrderService) AopContext.currentProxy();// 返回订单信息return Result.ok(orderId);}

业务代码——从消息队列获取消息并处理

	// 线程池private static final ExecutorService SECKILL_ORDER_EXECUTOR = Executors.newSingleThreadExecutor();// 注解含义,在Bean被创建完毕后执行@PostConstructprivate void init() {// SECKILL_ORDER_EXECUTOR.submit(new VoucherOrderHandler());}// 从消息队列中获取消息,异步下单private class VoucherOrderHandler implements Runnable {String queueName = "stream.orders";@Overridepublic void run() {while (true) {try {// 获取消息队列中的订单信息 XREADGROUP GROUP g1 c1 count 1 block 2000 STREAMS stream.order >List<MapRecord<String, Object, Object>> list = stringRedisTemplate.opsForStream().read(Consumer.from("g1", "c1"),StreamReadOptions.empty().count(1).block(Duration.ofSeconds(2)),StreamOffset.create(queueName, ReadOffset.lastConsumed()));// 判断消息是否获取成功if (list == null || list.isEmpty()) {// 如果获取失败,说明没有消息,继续下一次循环continue;}// 解析消息中的订单消息MapRecord<String, Object, Object> record = list.get(0);Map<Object, Object> values = record.getValue();VoucherOrder voucherOrder = BeanUtil.fillBeanWithMap(values, new VoucherOrder(), true);// 如果获取成功,执行下单handleVoucherOrder(voucherOrder);// ACK确认,SACK stream.orders g1 idstringRedisTemplate.opsForStream().acknowledge(queueName, "g1", record.getId());} catch (Exception e) {log.error("订单处理异常", e);// 发生异常后去pending-list中处理消息handlePendingList();}}}private void handlePendingList() {while (true) {try {// 获取pending-list中的订单信息 XREADGROUP GROUP g1 c1 count 1 STREAMS stream.order 0List<MapRecord<String, Object, Object>> list = stringRedisTemplate.opsForStream().read(Consumer.from("g1", "c1"),StreamReadOptions.empty().count(1),StreamOffset.create(queueName, ReadOffset.from("0")));// 判断消息是否获取成功if (list == null || list.isEmpty()) {// 如果获取失败,说明pending-list没有异常消息,结束循环break;}// 解析消息中的订单消息MapRecord<String, Object, Object> record = list.get(0);Map<Object, Object> values = record.getValue();VoucherOrder voucherOrder = BeanUtil.fillBeanWithMap(values, new VoucherOrder(), true);// 如果获取成功,执行下单handleVoucherOrder(voucherOrder);// ACK确认,SACK stream.orders g1 idstringRedisTemplate.opsForStream().acknowledge(queueName, "g1", record.getId());} catch (Exception e) {log.error("处理pending-list订单处理异常", e);}}}}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/731271.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

一篇了解电感的使用

一、电感理论基础 1.电感的定义 当电流通过线圈后&#xff0c;会产生磁场&#xff0c;磁感线穿过线圈&#xff0c;产生的磁通量与电流 i有如下关系&#xff1a; 将漆包线、纱包线或塑皮线等在绝缘骨架或磁心、铁心上绕制而成的器件&#xff0c;当线圈通过电流后&#xff0c;在…

linux应用程序需要编写的脚本

每一个程序都按照下面的要求进行脚本编写 多个应用之间联合安装采用编写外围脚本&#xff0c;依次调用多个应用的脚本的方式实现

负载均衡 dubbo

1 自定义负载均衡 dubbo 在 Dubbo 中&#xff0c;用户可以自定义负载均衡策略以满足特定场景的需求。Dubbo 提供了扩展接口 com.alibaba.dubbo.rpc.cluster.LoadBalance 来支持自定义负载均衡算法。 要实现自定义的负载均衡策略&#xff0c;需要完成以下步骤&#xff1a; 创建…

MyBatis Oracle 批量插入数据

MyBatis Oracle 批量插入数据 1.需求描述2.实现方案2.1 循环 insert 插入2.2 insert all 插入2.3 insert union all 插入 3.分析总结 系统&#xff1a;Win10 JDK&#xff1a;1.8.0_351 IDEA&#xff1a;2022.3.3 1.需求描述 在一次项目中实施过程中&#xff0c;后台需要将地区…

给一篇word注音可不可以只要拼音不要汉字 word中如何只保留拼音不要汉字

word中如何只保留拼音不要汉字&#xff0c;如果你想要只保留拼音而去除汉字&#xff0c;可以通过一系列步骤来实现。以下是一个详细的教程&#xff0c;帮助你完成这个任务。 首先&#xff0c;确保你的电脑已经安装了“汇帮注音大师”软件。如果没有&#xff0c;你需要安装一下…

云计算 3月8号 (wordpress的搭建)

项目wordpress 实验目的&#xff1a; 熟悉yum和编译安装操作 锻炼关联性思维&#xff0c;便于以后做项目 nginx 编译安装 1、安装源码包 [rootlinux-server ~]# yum -y install gcc make zlib-devel pcre pcre-devel openssl-devel [rootlinux-server ~]# wget http://nginx.…

安卓7原生相机切到视频崩溃

目录 1、查看日志 2、分析日志、提取重点 3、寻找解决方法 author daisy.skye的博客_CSDN博客-嵌入式,Qt,Linux领域博主 daisy.skye_嵌入式,Linux,Qt-CSDN博客daisy.skye擅长嵌入式,Linux,Qt,等方面的知识https://blog.csdn.net/qq_40715266?typeblog 1、查看日志 由于安…

Java实战:利用Redis实现每周热评

本文将详细介绍如何利用Redis实现每周热评的功能。我们将深入探讨Redis的相关概念&#xff0c;如键值对、数据结构、过期时间等&#xff0c;以及如何使用Java语言结合Jedis库进行Redis操作。 1. 引言 在现代的互联网应用中&#xff0c;实时统计和展示热门内容是一种常见的需求…

C语言知识点总结-10.共用体、结构体、宏定义、位运算等

第十章、共用体、结构体、宏定义、位运算 10.1 共用体 在进行某些算法的C语言编程的时候,需要使几种不同类型的变量存放到同一段内存单元中。也就是使用覆盖技术,几个变量互相覆盖。这种几个不同的变量共同占用一段内存的结构,在C语言中,被称作“共用体”

vscode setting.json 全局设置 工作区设置 位置 优先级

vscode中setting.json有两种配置权限 一、全局配置&#xff1a;setting.json文件位于C:\Users\Administrator\AppData\Roaming\Code\User\settings.json 二、工作区配置&#xff1a;setting.json文件位于工作区的.vscode\settings.json 当两种配置同时存在时&#xff0c;工作区…

深入理解nginx一致性哈希负载均衡模块[下]

上接 深入理解nginx一致性哈希负载均衡模块[上] 3. 源码分析 nginx的一致性哈希功能是通过ngx_http_upstream_hash_module来提供的,下面来整体通过ngx_http_upstream_hash_module来学习一下一致性哈希算法的实现原理。 3.1 配置指令分析 要启用Nginx的一致性哈希负载均衡算法…

生成对抗网络 (GAN)

生成对抗网络&#xff08;Generative Adversarial Networks&#xff0c;GAN&#xff09;是由Ian Goodfellow等人在2014年提出的一种深度学习模型。GAN由两部分组成&#xff1a;一个生成器&#xff08;Generator&#xff09;和一个判别器&#xff08;Discriminator&#xff09;&…

一文学会搭建 cli 脚手架工具

文章目录 设置工具命令package.json bin 字段注释&#xff1a;#!/usr/bin/env node设置环境变量 接收命令选项参数process 实现commander 命令行交互&#xff1a;inquirer下载项目模板&#xff1a;download-git-repo执行额外命令&#xff1a;自动安装依赖child_processexeca 体…

取证工作:如何提取和破解网络浏览器用户密码

ElcomSoft 系列软件专注于破解及恢复广泛的应用环境&#xff08;Office、数据库、归档文件、iOS等&#xff09;、系统 (EFS加密等)、磁盘&#xff08;BitLocker、FileVault 2、PGP Disk、TrueCrypt 和 VeraCrypt 加密&#xff09;及网络浏览器的加密保护&#xff0c;是数据恢复…

基于卷积神经网络的野外可食用植物分类系统

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长 QQ 名片 :) 1. 项目简介 本文详细探讨了一基于深度学习的可食用植物图像识别系统。采用TensorFlow和Keras框架&#xff0c;利用卷积神经网络&#xff08;CNN&#xff09;进行模型训练和预测&#xff0c;并引入迁移学习模型…

Mac测试环境搭建

1 下载pycharm 下载地址&#xff1a;PyCharm&#xff1a;JetBrains 出品的用于数据科学和 Web 开发的 Python IDE 2 安装python3.6.8 下载地址&#xff1a;Index of /ftp/python/3.6.8/ 安装后提示错误 换一种方式&#xff1a;用conda 下载地址&#xff1a;Free Download | …

python 远程执行windows上的程序

在Python中远程执行Windows上的程序&#xff0c;可以使用pywinrm库通过WinRM协议与Windows服务器进行通信。以下是一个基本示例&#xff1a; import winrm# 创建WinRM连接参数 username your_username password your_password endpoint http://remote_host:5985/wsman # 使…

代码随想录算法训练营第五十五天|583. 两个字符串的删除操作、72. 编辑距离。

583. 两个字符串的删除操作 题目链接&#xff1a;两个字符串的删除操作 题目描述&#xff1a; 给定两个单词 word1 和 word2 &#xff0c;返回使得 word1 和 word2 相同所需的最小步数。 每步 可以删除任意一个字符串中的一个字符。 解题思路&#xff1a; 1、确定dp数组&#x…

Oracle数据库参数文件

导读 Oracle参数文件&#xff1a;数据库配置和性能调优的关键 Oracle参数文件是数据库管理中至关重要的组成部分&#xff0c;它包含了一系列数据库配置参数的设置&#xff0c;可以影响数据库的性能、安全性和可用性。参数文件允许管理员对数据库进行定制化配置&#xff0c;以满…

ipad协议847最新版

ipad协议其实就是模拟ipad端微信的人工操作&#xff0c;跟微信服务器通信。协议的关键点主要是PB协议、mmtls、07加密算法、rqt算法、aes加密、rsa加密等&#xff0c;只要把这些点拿下&#xff0c;就可以模拟官方微信的所有功能了&#xff0c;还可以模拟android、pc、mac端的登…