(三)延时任务篇——通过redis的zset数据结构,实现延迟任务实战

前言

在前一篇内容中我们介绍了如何使用redis key过期失效的监控,完成任务延时关闭的功能,同时官方并不支持使用此种方式实现,由于其安全性较低,存在数据丢失的情况。本节内容是对延迟任务的又一实现方案,通过redis zset的数据结构完成延迟任务。使用一个常量order作为key,订单id作为value值,任务的过期时间作为score值,通过定时任务取前100名的数据,比较score值和当前时间的大小,如果该值小于当前时间,则证明该订单已过期,完成关单的操作,并将该订单数据在redis中删除。

正文

  • 项目集成redis,可参考上一节内容
  • 引入redis的pom依赖

    <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis-reactive</artifactId> </dependency>
  • 在application.yml中添加redis的配置信息

    spring:
    data:
    redis:
    host: 127.0.0.1
    port: 6379
    database: 0
    connect-timeout: 30000
    timeout: 30000
    lettuce:
    pool:
    enabled: true
    max-active: 200
    max-idle: 50
    max-wait: -1
    min-idle: 10
    shutdown-timeout: 100

  • 创建订单测试接口
java 复制代码
    @Operation(summary = "创建订单-redis-zset")
    @PostMapping("saveOrderByRedisZet")
    public ApiResponse saveOrderByRedisZet() {
        String orderId = String.valueOf(IdWorker.getId());
        stringRedisTemplate.opsForZSet().add("order", orderId, System.currentTimeMillis() + 60000);
        return ApiResponse.ok();
    }
  • 开启定时任务,监控订单的状态
java 复制代码
package com.yundi.xyxc.tps.job;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.util.Set;


@Slf4j
@EnableScheduling
@Component
public class OrderJob {
    @Autowired
    private StringRedisTemplate stringRedisTemplate;


    /**
     * 注意:如果是分布式架构,这里需要使用分布式任务的方式,例如xxl-job或者使用分布式锁+定时任务
     */
    @Scheduled(cron = "0/5 * * * * ?")
    public void createOrder() {
        ZSetOperations<String, String> operations = stringRedisTemplate.opsForZSet();
        //查询过期排名前100的订单
        Set<ZSetOperations.TypedTuple<String>> top100 = operations.rangeWithScores("order", 0, 99);
        assert top100 != null;
        for (ZSetOperations.TypedTuple<String> tuple : top100) {
            log.info("Member: {}, Score: {}", tuple.getValue(), tuple.getScore());
            //订单小于当前时间,订单过期,删除该订单
            if (tuple.getScore() < System.currentTimeMillis()) {
                log.info("订单过期,删除订单:{}", tuple.getValue());
                operations.remove("order", tuple.getValue());
            }
        }
        log.info("--------------------------------------------------------------");

    }

}

**PS:**此处需要注意的是,如果是分布式系统,此处需要使用分布锁+@Scheduled定时任务,保证数据的安全性,以免产生并发问题。同时需要保证定时任务的执行时间合理根据任务的实际完成时间。

  • 启动项目,通过接口调用订单创建接口
  • 查看关单输出,过期的订单被关单并删除

结语

使用redis的zset数据结构完成延迟任务,相较于监控key失效更加安全,不会出现数据的丢失,同时相较于某些mq消息中间件的延迟对列,更加灵活,可以设置任意时间的延迟过期任务。关于使用redis的zset数据结构,实现延迟任务的内容到这里就结束了。。。

相关推荐
qq_318121595 小时前
互联网大厂Java面试故事:从Spring Boot到微服务架构的技术挑战与解答
java·spring boot·redis·spring cloud·微服务·面试·内容社区
计算机毕设VX:Fegn08955 小时前
计算机毕业设计|基于springboot + vue医院设备管理系统(源码+数据库+文档)
数据库·vue.js·spring boot·后端·课程设计
Mr__Miss5 小时前
保持redis和数据库一致性(双写一致性)
数据库·redis·spring
Knight_AL6 小时前
Spring 事务传播行为 + 事务失效原因 + 传播行为为什么不用其他模式
数据库·sql·spring
倔强的石头_6 小时前
时序数据时代的“存储与分析困局”解析及金仓解决方案
数据库
计算机毕设VX:Fegn08956 小时前
计算机毕业设计|基于springboot + vue小型房屋租赁系统(源码+数据库+文档)
数据库·vue.js·spring boot·后端·课程设计
倔强的石头_7 小时前
场景化落地指南——金仓时序数据库在关键行业的应用实践
数据库
SelectDB8 小时前
驾驭 CPU 与编译器:Apache Doris 实现极致性能的底层逻辑
运维·数据库·apache
zbguolei8 小时前
MySQL根据身份证号码计算出生日期和年龄
数据库·mysql
马克学长8 小时前
SSM校园图书借阅服务系统jd2z8(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面
数据库·图书管理系统·ssm 框架·ssm 校园图书借阅系统