使用redis实现与flink窗口同样的消息聚合处理效果

背景

最近做了一个需求,其中有个业务场景是,当商家店铺配置发生变动时,要刷新整个店铺下的所有相关数据。

实现分析

如果不考虑性能相关的所有因素,实现起来其实没什么,监听各种配置消息变更,然后加锁刷新数据就好。但是在业务需求中,最大的难点就是性能和数据量,一百条数据和一万条数据的处理难度级别是相差非常巨大的。

本需求下,店铺下的相关数据可能很多,超过上千条也有可能(虽然数据上千条,但是逻辑比较重,mysql估计就得读写十万次了),而且变更场景来源非常多,也就导致在某些时刻变更会非常频繁,可能一分钟就有100次变更。基于以上信息,必须要做对处理逻辑进行性能优化。

其实对于数据变更短时间内非常频繁的场景,有一个比较通用的解法,就是用flink转一道,窗口函数聚合一下。比如说设置一分钟的窗口,将一分钟内的所有变更消息聚合成一条再发送个业务代码进行后续处理。这样就可以显著的降低数据库qps,当然缺点就是时效性会比较差,窗口时间需要权衡一下,flink sql示例代码如下

sql 复制代码
GROUP BY TUMBLE(event_time, INTERVAL '1' MINUTE), shop_id

但是flink转一道这个事情还是比较考验公司的基础设施完善性的,排查问题也会多了很多弯路,比如说flink有没有收到我发的消息,flink最终发的消息我有没有收到等等。。所以借这次机会,我使用了redis做了一个轻量级的消息窗口聚合机制,来给大家分享一下。

java 复制代码
	public void handlerMsg() {
		.....
		.....
		
		boolean canProcess = canMsgProcess(shopId, msgTime, topic, channel, msgId);
		if (!canProcess) {
			return;
		}

		// 如果当前时间大于消息时间五分钟,允许放行,否则重试
		if (currentTime > msgTime + 1000 * 300) {
			// 业务操作 业务操作要加锁和做幂等
		} else {
			throw new RequeueException("等待五分钟后执行");
		}
	}
	
	private boolean canMsgProcess(Long shopId, Long timestamp, String topic, String channel, Long msgId) {
		// 消息时间戳转 以五分钟为单位
		Long timePart = timestamp / (1000 * 300);

		String key = "xxxx_" + "业务名称_" +  shopId + "_t" + timePart;
		String value = redisClient.opsForString().get(key);

		// 消息唯一标识
		String msgUniqueKey = msgId + "_" + topic + "_" + channel;
		if (StringUtils.isBlank(value)) {
			// 如果不存在,就把本消息id设置上去,本消息放行
			redisClient.opsForString().set(key, msgUniqueKey);
			return true;
		}

		if (msgUniqueKey.equals(value)) {
			return true;
		} else {
			log.info("已经有消息在等待执行,本消息跳过 existMsg = {}", value);
			return false;
		}
	}

整体来看就是用了redis的String数据结构,key = 消息业务时间的时间段,value = 消息唯一标识。这个key含义就是保存了指定时间间隔内,哪个消息允许执行。

唯一的要求就是消息中必须有发送时间字段,个人建议所有的消息体都应该加上发送时间,这是一个很有用的字段。

而且对redis的操作不需要使用lua保证原子性,不用担心key并发修改,不用担心缓存丢失,非常简单,有redis就行(因为有消息重试在,感兴趣的话可以想一下异常场景会怎么样)


复制代码
                        版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/lvqinglou/article/details/136584954

相关推荐
C雨后彩虹3 小时前
任务最优调度
java·数据结构·算法·华为·面试
heartbeat..3 小时前
Spring AOP 全面详解(通俗易懂 + 核心知识点 + 完整案例)
java·数据库·spring·aop
Jing_jing_X3 小时前
AI分析不同阶层思维 二:Spring 的事务在什么情况下会失效?
java·spring·架构·提升·薪资
元Y亨H5 小时前
Nacos - 服务发现
java·微服务
微露清风5 小时前
系统性学习C++-第十八讲-封装红黑树实现myset与mymap
java·c++·学习
dasi02275 小时前
Java趣闻
java
阿波罗尼亚6 小时前
Tcp SSE Utils
android·java·tcp/ip
susu10830189116 小时前
springboot3.5.8整合minio8.5.9
java·springboot
不知道累,只知道类6 小时前
深入理解 Java 虚拟线程 (Project Loom)
java·开发语言
myzshare7 小时前
实战分享:我是如何用SSM框架开发出一个完整项目的
java·mysql·spring cloud·微信小程序