go高并发之路——数据聚合处理

news/2024/10/18 17:54:27/文章来源:https://www.cnblogs.com/lmz-blogs/p/18327493

数据聚合处理,指的是在某个请求或者脚本处理中,我们不会把这个数据立刻响应给前端或者立刻发送给下游,而是对数据先进行聚合处理一下,等到达某个阈值(时间或者量级),再响应给前端或者发送给下游。

举个实际的业务场景:直播间有一个做任务的功能,用户满足购买了多少金额我们就会给该用户发放一些奖励。此时如果有用户在购买了某些商品,那么我们得发送IM消息实时告知用户,该任务还差多少金额。那么这种情况下我们是不是每个用户下了一笔订单,我们就往直播间推送一次消息呢?

很显然不是,先讲一个直播间常用的IM消息推送逻辑:一般我们不会用户下了一笔订单,我们就往直播间推送一次消息,因为消息IM推送是有频率限制的。想想看,一个直播间如果有30w用户,下单QPS如果有1W,那么那一秒就要往直播间推送1w次,那肯定是不行的,量太大了,等下把IM服务都打爆了。那么如何解决这个问题呢?

答案就是要对数据做聚合处理了,我们一般一个直播间都会生成一个RoomId,然后推送消息推送到直播间。这时候我们可以以任务ID为key值(假设一个任务ID只属于一个直播间),将某段时间比如1秒钟内的用户订单数据进行聚合,然后再一起发送IM给直播间。最后直播前端根据实际登录的UserId,校验是否在推送的IM消息中存在对应的信息,存在就展示和处理该用户的IM消息。

上面的方案已定,那我们去实现了,下面是使用go实现的一个简单的demo:

type UserOrders struct {RoomId   string      `json:"room_id"`TaskId   int64       `json:"task_id"`UserList []*UserList `json:"user_list"`
}
//用户list
type UserList struct {UserId     string `json:"user_id"`OrderMoney int    `json:"order_money"`
}var UserOrdersMap sync.Map //定义sync.Map,存储每个任务的用户订单信息const cacheKey = "TaskIm-%d" //sync.Map键值//入口
func main() { ctx := context.Background()rand.Seed(time.Now().UnixNano()) // 设置随机数种子randNum := rand.Intn(1000) + 1taskId := int64(randNum)                                    //假数据,1000个任务roomId := fmt.Sprintf("room_%d", randNum)                   //假数据,1000个直播间userId := fmt.Sprintf("user_%d", randNum)                   //假数据,1000个用户IDorderMoney := randNum                                       //假数据,用户的购买金额数SendUserOrderMoney(ctx, taskId, roomId, userId, orderMoney) //往直播间发送IM消息}//往直播间发送IM消息
func SendUserOrderMoney(ctx context.Context, taskId int64, roomId string, userId string, orderMoney int) {key := fmt.Sprintf(cacheKey, taskId)userInfo := &UserList{UserId:     userId,OrderMoney: orderMoney,}if v, ok := UserOrdersMap.Load(key); ok { // key存在userOrders := v.(*UserOrders)userOrders.UserList = append(userOrders.UserList, userInfo) //往用户列表中追加用户订单信息UserOrdersMap.Store(key, userOrders)if len(userOrders.UserList) > 100 { //用户list大于100个用户时,发送IM消息SendOrder(ctx, taskId) //发送IM消息return}} else { // key不存在userOrders := &UserOrders{RoomId:   roomId,TaskId:   taskId,UserList: []*UserList{userInfo},}UserOrdersMap.Store(key, userOrders)}go func() {_ = TimerDeal(ctx, taskId)}()}//定时器
func TimerDeal(ctx context.Context, taskId int64) (err error) {t := time.NewTimer(time.Second * 1) // 设置定时器1秒钟后执行for {select {case <-t.C:SendOrder(ctx, taskId)return}}
}//发送IM消息
func SendOrder(ctx context.Context, taskId int64) {key := fmt.Sprintf(cacheKey, taskId)if data, ok := UserOrdersMap.Load(key); ok {defer UserOrdersMap.Delete(key) // 删除keyres := data.(*UserOrders)       //获取值fmt.Println("发送IM消息", res)      //发送IM消息}
}

上面这段demo是使用了sync.Map来存储任务维度的IM数据,主要是考虑到有多个协程或线程在往Map里面写数据。当然,我们也可以考虑使用其它方式,比如Redis当存储介质。然后这段代码实现的逻辑就是当某个任务的用户list大于100或者时间大于1s时,我们就开始发送IM消息给直播间前端

这就是一个数据聚合的一个简单案例,当然数据聚合还有很多的应用场景,比如我们要往表里插入数据,如果高并发的场景下,一条条插入会对DB造成较大的压力,这时候也可以考虑使用这种聚合方式,将数据聚合起来(比如到100条),再一起insert。

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

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

相关文章

Fenwick Tree

看这篇题解 解释一下是为什么 看蓝书的图,比如\(a_3\)对\(c_8\)的贡献,操作一次,贡献系数为\(1\),然后将\(a_8\)中\(a_3\)的贡献次数改为\(1\),考虑一下操作第二次在干什么,我们是先更新了\(a_3\)对\(c_4\)的贡献,然后让\(c_8\)为\(c_4\)和\(a_8\)(注意这里的\(a_8\)已…

04HTML+CSS

今天开始学了CSS,CSS叫做-层叠样式表。主要是来美化界面的。今日学习内容有 1.CSS的引入方式,CSS的引入方式有三种 内部样式表:学习使用 CSS 代码写在 style 标签里面 l 外部样式表:开发使用 l CSS 代码写在单独的 CSS 文件中(.css)在 HTML 使用 link 标签引入 ,在.CSS文…

ssy中学暑假集训向量学习笔记(完结)

今天模拟赛T4是个极其恶心的东西,用到了许多高中数学知识,md,先引入前置知识。 复数 定义虚数单位\(i\) 满足\(i^2=-1\),复数域\(C\),形如\(a+bi,(a,b\in \mathbb{R})\)的数叫做复数。 复数\(a+bi\)可以在坐标系中表示为\((a,b)\)的向量。 同时复数的加减法满足向量的加减法…

ssy中学暑假集训向量学习笔记(应该能完结)

今天模拟赛T4是个极其恶心的东西,用到了许多高中数学知识,md,引入前置知识。 向量 定义 顾名思义,向量就是有方向的量,在平面直角坐标系上可以用\((a,b)\)表示,图如下:图像上即为由\(A\)指向\(B\)的一条向量。 投影 投影不好解释,拿图吧。\(AC\)在\(AB\)上的投影就是\(…

2023.7.2-3-4Mssql xp_cmdshell提权

1.概念 Mssql和SQL sever的一个产品的不同名称。都属于微软公司旗下。而上述Mssql xp_cmdshell提权也属于数据库提权的一种。 主要依赖于sql server自带的存储过程。 1.1xp_cmdshell提权 扩展存储过程中xp_cmdshell是一个开放接口,可以让sql sever调用cmd命令。 此过程在 SQL …

第二次测试部分题解 (c,d,g)

c-一个欧拉函数模板题1 #include<iostream>2 using namespace std;3 4 int main()5 {6 int n;7 cin >> n;8 int r = n;9 for (int i = 2; i * i <= n; i++) 10 { 11 if (n % i == 0) 12 { 13 r = r / i * (i -…

[随笔]我的创作纪念日

今天,是我开始创作的第256天,哈哈...这刚好是8位无符号二进制的“模”,一个“轮回”。 一些心得和感悟、一些历程与经历、一些收获与体会,大家感兴趣可以看看。历程 我最开始接触这个平台大约是在2020年10月份的时候,那时我正直大三上期,我已经开始备研。附言:黎老师(我…

搭建极狐GitLab(基于Docker): 步骤整合汇总记录

执行背景: (1) CentOS7(虚拟机ISO映像文件=CentOS-7-x86_64-DVD-2009.iso); (2) repo(yum)源已切换为国内源;命令汇总:1. 安装Docker 相关命令: # 查看仓库源中可使用版本 yum list docker-ce --showduplicates | sort -r# 安装指定版本 yum install docker-ce-docker完整版本号…

【待做】【攻防技术系列+权限提升】Windows提权

Windows提权思维导图Windows提权工具 vulmap vulmon开发的一款开源工具,原理是根据软件的名称和版本号来确定,是否有CVE及公开的EXP。这款Linux的工具挺好用,但是对于Windows系统层面不太适用。 windows-exp-suggester 这款和本工具的原理一样,尝试使用了之后,发现它的CVE…

[随笔]创作4天的心得感悟

随笔。【版权声明】未经博主同意,谢绝转载!(请尊重原创,博主保留追究权) https://www.cnblogs.com/cnb-yuchen/p/18327364 出自【进步*于辰的博客】今天,3月14日,和往常一样,也不是什么节日,就是看到博友们发的动态,也有所感慨。 算一算,我接触此平台已经327天了。虽…

【待做】【攻防技术系列+网络协议】ICMP协议

ICMP协议简介 ICMP(Internet Control Message Protocol)因特网控制报文协议。它是IPv4协议族中的一个子协议,用于IP主机、路由器之间传递控制消息。控制消息是在网络通不通、主机是否可达、路由是否可用等网络本身的消息。这些控制消息虽然不传输用户数据,但是对于用户数据…

C141 线段树分治+线性基 P3733 [HAOI2017] 八纵八横

视频链接:C141 线段树分治+线性基 P3733 [HAOI2017] 八纵八横_哔哩哔哩_bilibili P3733 [HAOI2017] 八纵八横 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)// 线段树分治+线性基 O(q*logq*logL*logL) #include <iostream> #include <cstring> #include <a…