大数据量定时超时-精确到秒

2023-10-27

一、背景

开发过程中或多或少会遇到某些场景,要求数据在规定的时间内如果没处理就要失效掉;

如:用户下单,订单在30分钟内没支付就要自动取消,防止长时间占用库存等;

面对这种情况我们来扒拉一下:

  1. 系统启一个定时任务,定时扫库,取出超过30分钟的数据,取消释放库存
  2. 用户下单后将订单放入MQ的延迟队列(比如RocketMQ的延迟消息),依赖于MQ的通知实时触发取消
  3. 将数据放入Redis,定时扫描Redis
  4. 将数据放入收尾相连的环形链路中,依次触发超时

二、实现思路

1、定时任务扫库

在分布式定时任务系统中启动一个定时任务,定时任务时间可根据实际业务定义(1分钟、5分钟)

存在问题:

  1. 如果是单库:通常数据量比较多,如果每秒扫描可能比较耗资源,往往是每分钟或、、、超时有误差
  2. 如果是分库分表:需要扫描全量库表,

好处:

  1. 实现相对简单,就是一次普通的查询

数据量少的情况下可以使用,注意查询条件要配以索引,否则会非常慢

2、依赖MQ的延迟队列实现

以RocketMQ为例:

当Producer端发送延迟消息时,Broker会创建一个SCHEDULE_TOPIC*开头的Topic,然后以该topic持久化

然后给每个topic启动定时任务扫描,将数据放入真正的Topic推送到Consumer端消费

存在问题:有些消息队列不支持延迟队列比如rabbit,需要依赖插件;rocketmq延迟时间只支持配置的枚举时间,有一定局限性

3、基于redis定时--全量扫描实现

这种实现跟第一种基于数据库基本类似,就是将数据库换成redis

存在问题:每次都是全量数据拉取,如果数据量过大会这种资源占用,再说redis单线程处理,要防止过大数据拉取

4、基于redis--将数据放入List数据结构

放数据的时候使用rightPush函数从右测逐个放入

启动定时任务(每秒)取(index(0)函数)List第一个,判断是否超时

如果没超时:结束本次

如果超时:获取前100个(按业务自定义数量)判断是否超时,如果全部超时再取100判断,如果循环遇到未超时的结束本次,并将超时的从reids删除leftPop()

好处:相对上种来说,避免了全量拉取数据

存在问题:可能出现多次网络交互,每次拉取数量要按照自己业务来调整

5、基于redis--将数据存入map

本地启动一个定时任务(每秒),redis维护一个变量

订单入库时:先取reids里的变量,然后以该变量命名新建map,将数据放入map

每跑一次定时任务变量++,然后拉取该map下的订单,判断超时的对应删除

变量==到达(超时时间秒数)个数时,将变量赋值1

这样就生成了一个收尾相连的环形List<Map>

好处:数据精确到秒级失效,每次从redis拉取的数据最多是2秒内的数据,数据量可空

存在问题:如果超时时间相对较长,Redis里将创建过多的map

三、代码实现

针对第5种实现

1、订单进入时的操作

private static final String ANNULAR_NUM ="ORDER:INDEX_NUM";
public void annularAdd(String orderNo){
    //ANNULAR_NUM,自增变量(如:1-120)
	Object obj = redisTemplate.opsForValue().get(ANNULAR_NUM);
	if (obj!=null){
	    //num 当前的自增变量值(1-120)
		Integer num = Integer.valueOf(obj.toString());
		redisTemplate.opsForHash().put("ORDER:MAP:"+num,
                                        orderNo,
            LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli()+"");
	}
}

查询reids自增变量,如果不为空就将订单放入对应的map

2、启动定时任务(每秒)

private static final String ANNULAR_NUM ="ORDER:INDEX_NUM";
public void annularAddSchedule() {
	Object obj = redisTemplate.opsForValue().get(ANNULAR_NUM);
	int num=obj!=null ? Integer.valueOf(obj.toString()) : 0;
	Long increment=1L;
	//如果当前redis自增数值大于等于超时时间秒数,就置为初始值
	if (num >= 120) {
		redisTemplate.opsForValue().set(ANNULAR_NUM,increment+"");
	}else {
		increment = redisTemplate.opsForValue().increment(ANNULAR_NUM);
	}
	System.out.println("当前map"+increment);
	Map map = redisTemplate.opsForHash().entries("ORDER:MAP:" + increment);
	List<String> orders = new ArrayList<>();
	long timeout = LocalDateTime.now().plusSeconds(-119).toInstant(ZoneOffset.of("+8")).toEpochMilli();
	map.forEach((key, value) -> {
		Long aLong = Long.valueOf(value.toString());
		//如果当前时间-超时时间>订单的超时时间,说明订单已超时
		if (timeout > aLong) {
			orders.add(key.toString());
		}
	});
	System.out.println("超时的orders=========" + orders.size());
	if (orders != null && orders.size() > 0) {
		Long delete = redisTemplate.opsForHash().delete("ORDER:MAP:" + increment, orders.toArray());
        //使用线程池处理自己业务逻辑
		executorService.execute(() -> {
			userInterface.getUser(JSON.toJSONString(orders));
		});
		System.out.println("delete=========" + delete);
	}
}

公众号主要记录各种源码、面试题、微服务技术栈,帮忙关注一波,非常感谢

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

大数据量定时超时-精确到秒 的相关文章

  • 在 sidekiq 上配置 redis 身份验证

    我想我错过了一些东西 因为我在文档中找不到如何编写 redis 实例的用户名和密码以与 sidekiq 一起使用 有没有办法做到这一点 或者是通过 ENV 变量 Sidekiq 将无法识别的 Redis 选项直接传递给 Redis 驱动程序
  • 使用Redis从有限范围内生成唯一ID

    我有一些数据库项目 除了主键之外 还需要项目所属组的唯一索引 我们来调用属性nbr 以及将项目分组在一起并定义唯一范围的属性nbr 我们会打电话group This nbr必须在 1 N 范围内 并且may从外部源导入项目时进行设置 由于所
  • 无法启动redis.service:单元redis-server.service被屏蔽

    我在 ubuntu 16 04 上安装了 Redis 服务器 但是当我尝试使用启动redis服务时 sudo systemctl start redis 我收到消息 Failed to start redis service Unit re
  • Redis Docker compose无法处理RDB格式版本10

    我无法在 docker compose 文件中启动 redis 容器 我知道docker compose文件没问题 因为我的同事可以成功启动项目 我读到有一个删除 dump rdb 文件的解决方案 但我找不到它 我使用Windows机器 任
  • 如何设置和获取Redis中存储的对象?

    我试图在 redis 中存储一个对象 当我获取该对象时 它似乎不起作用 I tried u User new u name blankman redis set test u x redis get test x name error 我想
  • 2 个具有共享 Redis 依赖的 Helm Chart

    目前 我有 2 个 Helm Charts Chart A 和 Chart B Chart A 和 Chart B 对 Redis 实例具有相同的依赖关系 如Chart yaml file dependencies name redis v
  • redis 2.8.7 Linux Sentinel环境配置问题,如何使其自启动,应该订阅什么?

    现在我们尝试使用 redis 2 8 7 作为缓存存储 来自使用 booksleeve 客户端的 NET Web 应用程序 目前看来这是一个非常有趣和令人兴奋的任务 redis 文档非常好 但由于缺乏真正的实践经验 我确实有几个关于如何正确
  • 使用redis进行树形数据结构

    我需要为基于树的键值开发一个缓存系统 与Windows注册表编辑器非常相似 其中缓存键是字符串 表示树中到值的路径 可以是原始类型 int string bool double 等 或子树本身 例如 key root x y z w val
  • 如何将“.csv”数据文件导入Redis数据库

    如何将 csv 数据文件导入 Redis 数据库 csv 文件中包含 id 时间 纬度 经度 列 您能否向我建议导入 CSV 文件并能够执行空间查询的最佳方法 这是一个非常广泛的问题 因为我们不知道您想要什么数据结构 您期望什么查询等等 为
  • 节点应用程序之间共享会话?

    我目前有两个独立的节点应用程序在两个不同的端口上运行 但共享相同的后端数据存储 我需要在两个应用程序之间共享用户会话 以便当用户通过一个应用程序登录时 他们的会话可用 并且他们似乎已登录到另一个应用程序 在本例中 它是一个面向公众的网站和一
  • 在 Spring 4 中干掉通用的 RedisTemplate

    我读到你可以拥有 Autowired从 Spring 4 开始泛型 这太棒了 我有一个摘要RedisService我想参加的课程 Autowired一个通用的 RestTemplate 如下所示 public abstract class
  • docker-compose:容器之间的 Redis 连接被拒绝

    我正在尝试设置一个 docker compose 文件 该文件旨在替换运行多个进程 RQ 工作线程 RQ 仪表板和 Flask 应用程序 的单个 Docker 容器解决方案导师 http supervisord org 主机系统是 Debi
  • 批量将Dictionary中的数据设置到Redis中

    我正在使用 StackExchange Redis DB 插入键值对字典Batch如下 private static StackExchange Redis IDatabase database public void SetAll
  • 在redis中存储多个嵌套对象

    我想在redis中存储多个复杂的json数据 但不知道如何 这是我的 json 结构 users user01 username ally email email protected cdn cgi l email protection u
  • 在 Rails 应用程序上将 HASH 保存到 Redis

    我刚刚开始使用 Redis 和 Rails 所以这可能是一个愚蠢的问题 我试图将哈希值保存到 Redis 服务器 但是当我检索它时 它只是一个字符串 IE hash field gt value field2 gt value2 redis
  • .NET Core 依赖注入中的“StackExchange.Redis.ConnectionMultiplexer”应该是“AddSingleton”还是“AddScope”?

    我正在使用以下命令将 Redis 连接添加到 NET CoreStackExchange Redis 目前看起来像这样 public static IServiceCollection AddRedisMultiplexer this IS
  • JedisPoolConfig 不可分配给 GenericObjectPoolConfig

    我有一个基于 Spring 的 Java Web 应用程序托管在 Heroku 上 我正在尝试使用 Redis 实现来利用 Spring 缓存抽象 当服务器启动时 我收到一条错误消息 Type redis clients jedis Jed
  • Redis AOF fsync(始终)与 LSM 树

    我对日志结构化合并树 LSM 树 的理解是 它利用了附加到磁盘非常快 因为它不需要查找 这一事实 只需将更新附加到预写日志并返回到客户端即可 我的理解是 这仍然提供了立即的持久性 同时仍然非常快 我不认为 Redis 使用 LSM 树 它似
  • memcache、redis 和 ehcache 作为分布式缓存框架的比较 [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我需要做出的决定之一是在我的系统中使用什么缓存框架 有这么多可供选择 我目前正在研究 redis ehcache 和 memcached
  • 在 Redis 中存储 IP 范围

    我有很多不同提供商的 IP 范围 例如 P1 192 168 1 10 192 168 1 50 192 168 2 16 192 168 2 49 P2 17 36 15 34 17 36 15 255 P3 我将此 IP 转换为 int

随机推荐