首页 > 其他分享 >go高并发之路——数据聚合处理

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

时间:2024-07-27 21:17:29浏览次数:8  
标签:直播间 UserList 用户 并发 IM taskId go 聚合 推送

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

举个实际的业务场景:直播间有一个做任务的功能,用户满足购买了多少金额我们就会给该用户发放一些奖励。此时如果有用户在购买了某些商品,那么我们得发送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) + 1
	taskId := int64(randNum)                                    //假数据,1000个任务
	roomId := fmt.Sprintf("room_%d", randNum)                   //假数据,1000个直播间
	userId := fmt.Sprintf("user_%d", randNum)                   //假数据,1000个用户ID
	orderMoney := 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) // 删除key
		res := data.(*UserOrders)       //获取值
		fmt.Println("发送IM消息", res)      //发送IM消息
	}
}

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

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

标签:直播间,UserList,用户,并发,IM,taskId,go,聚合,推送
From: https://www.cnblogs.com/lmz-blogs/p/18327493

相关文章

  • golang 数组转为链表 - 正序和逆序
    有时候,有这样的场景,我们需要就给定数组将其转为一个链表,通常的思路有两种:正序逆序以下是具体的代码实现和测试函数:packagemainimport("fmt""testing")typelistNodestruct{next*listNodevalint}//正序遍历构建链表//通过一个虚拟头结点,不......
  • 【Go】基于 Go 1.19 的站点模板爬虫【实战演练版】
    0.前言Go语言,也被称为Golang,是由Google开发的一种开源编程语言,它在2009年首次发布,并在2012年正式开源。Go语言被设计用来简化大型软件的开发,特别注重并发编程和内存安全。0.1特点静态类型:Go是静态类型语言,这意味着类型在编译时已经确定,有助于在编译阶段捕捉错误......
  • 入门C语言Day18——break&continue&goto语句
    前面的博文中有提到do-while与for循环语句,其中的流程图中有break和continue这两个部分还没解释。所以今天先来解释一下break与continue语句。break和continue两个关键字都被运用在循环中。break的作用是永久的终止循环,只要break被执行,直接就会跳出循环,继续往后执行。......
  • Golang 高性能 Websocket 库 gws 使用与设计(一)
    前言大家好这里是,白泽,这期分析一下golang开源高性能websocket库gws。视频讲解请关注......
  • Python毕业设计基于Django的网上购物销售系统(代码+数据库+文档LW+运行成功)
    文末获取资源,收藏关注不迷路文章目录一、项目介绍二、主要使用技术三、研究内容四、核心代码五、文章目录一、项目介绍随着互联网技术的不断发展和普及,电子商务行业迅速崛起。越来越多的消费者选择在线购物,享受便捷、快速的购物体验。因此,开发一款基于Python的购物......
  • python毕业设计基于Django的电子书阅读系统的设计与实现 爬虫+大屏可视化
    文末获取资源,收藏关注不迷路文章目录一、项目介绍二、主要使用技术三、研究内容+四、核心代码五、文章目录一、项目介绍随着互联网的普及和移动设备的广泛应用,人们获取信息和阅读的方式发生了巨大变化。传统的纸质书籍阅读方式虽然经典,但存在携带不便、更新速度慢等......
  • Pyhton毕业设计基于django的旅游管理系统景点酒店订票和特产购物
    文末获取资源,收藏关注不迷路文章目录一、项目介绍亮点:景点和酒店订票,特色购物商城,在线地图功能二、主要使用技术三、研究内容四、核心代码五、文章目录一、项目介绍随着经济的快速发展和人民生活水平的提高,旅游业在全球范围内迅速发展,成为推动经济增长的重要力量。......
  • 并发容器
    Java的并发集合容器提供了在多线程环境中高效访问和操作的数据结构。这些容器通过内部的同步机制实现了线程安全,使得开发者无需显式同步代码就能在并发环境下安全使用,比如说:ConcurrentHashMap、阻塞队列和CopyOnWrite容器等。java.util包下提供了一些容器类(集合框架),其中Vect......
  • Django 仅发送更改响应而不是完整模板
    如何只发送一条警报消息来响应请求,而不必发送专门为警报制作的模板?我正在使用Javascript异步调用。我只需要警报html响应即可呈现InnerHTML查看@login_required(login_url="/login/")@csrf_protectdefusersave(request):msg=messages.add_message(req......
  • 如何修复 Google Colab 中未安装 Drive 和未正确设置路径的问题?
    我是Python新手,没有GoogleColab高级技术的经验。我一直在尝试编写一个Python代码,我想从我的GoogleDrive读取文本文件或MATLAB变量。然后我会对这些数据进行分析。我按照这个LINK的答案来安装我的驱动器。我在下面提供我的代码和屏幕截图来详细说明。我想要......