使用RabitMQ解决 论坛用户评论并发抢楼问题
前言:
本篇文章分享如何在用户评论高并发数据写入的情况下通过使用消息队列来保证评论服务。
问题引入:为何使用消息队列?
在我遇到的场景中是一个关于论坛在短时间内用户对同一个帖子进行评论遇到的并发楼层抢占问题,如果这里不做任何限制那么在同一时刻多个用户共同对帖子留言就会导致数据表Floor存储的数据不准确,进而导致数据不一致,而解决这个办法有三种选择:1.加锁控制、2.开始事务、3.使用消息队列。
1.加锁控制
使用互斥锁是解决并发问题的常用手段,但是相对来说,我们想要完美的解决问题 需要对 锁的粒度、锁的时机、以及放锁的时机。把握的非常精妙,大多数情况下复杂的业务场景会导致业务代码的层级较深,而互斥锁穿插在这种复杂的层级关系中一不留神就会导致诸如:琐失效、死锁……而且业务中引入了锁之后也会对我们的QPS造成影响。
2. 开启事务
使用Gorm 事务也能够保证数据的原子性,这个相对来说也是较为方便和容易的,但是在开启事务时我们应该考虑如何简化dao操作尽量缩小粒度,让事务内的过程尽量简化但又能达到效果即可。
3. 使用消息队列
它的优点是解耦、高可用、高并发;缺点是存在消息丢失、消息重复处理等问题,且实现较为复杂,需要考虑多种因素。这里使用RabbitMQ (如何保证消息队列消息不丢失这里不做说明)
业务代码分析
数据表
1 |
|
业务逻辑部分
daomain/comment.go
1 |
|
dao/comment.go
1 |
|
cache/comment.go
1 |
|
repo/comment.go
1 |
|
功能详解:
上述代码基本代表了有关评论业务操作的repository层操作,我们从最上层接口开始逐层拆分介绍。
repo/comment.go
下的ConsumerMQ(ctx context.context)
方法在我们路由注册的时候进行依赖注入,使用协程启动评论消费端,等待接收生产者的信号,当用户发表评论的时候就会走CreateAndCached(ctx,comment)
接口方法将用户的评论信息写入消费队列,经过消费者消费成功后,把本篇文章的评论信息追加到ZSet
中进行评论缓存。ConsumerMQ
方法中每次从消费队列获取用户评论后对该评论的所属文章进行最新楼层查询,这样保证评论的顺序性,同时也保证了写入数据库的评论楼层数也是具备原子性的。- 在ApiPost 提供的并发测试接口中 并发数 5000* 5 轮的情况下,整体API接口的平均延迟在 300MS左右,可见效果还是非常不错的。
使用RabitMQ解决 论坛用户评论并发抢楼问题
http://yoursite.com/2023/07/11/Golang-使用RabitMQ解决-论坛用户评论并发抢楼问题/