脚本之家,脚本语言编程技术及教程分享平台!
分类导航

Python|VBS|Ruby|Lua|perl|VBA|Golang|PowerShell|Erlang|autoit|Dos|bat|

服务器之家 - 脚本之家 - Golang - golang实现redis的延时消息队列功能示例

golang实现redis的延时消息队列功能示例

2020-05-31 11:29菜菜jjj Golang

这篇文章主要介绍了golang实现redis的延时消息队列功能,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

前言

在学习过程中发现redis的zset还可以用来实现轻量级的延时消息队列功能,虽然可靠性还有待提高,但是对于一些对数据可靠性要求不那么高的功能要求完全可以实现。本次主要采用了redis中zset中的zadd, zrangebyscore 和 zdel来实现一个小demo。

提前准备 安装redis, redis-go

因为用的是macOS, 直接

?
1
2
$ brew install redis
$ go get github.com/garyburd/redigo/redis

又因为比较懒,生成任务的唯一id时,直接采用了bson中的objectId,所以:

?
1
$ go get gopkg.in/mgo.v2/bson

唯一id不是必须有,但如果之后有实际应用需要携带,便于查找相应任务。

生产者

通过一个for循环生成10w个任务, 每一个任务有不同的时间

?
1
2
3
4
5
6
7
8
9
10
11
12
13
func producer() {
 count := 0
 //生成100000个任务
 for count < 100000 {
 count++
 dealTime := int64(rand.Intn(5)) + time.Now().Unix()
 uuid := bson.NewObjectId().Hex()
 redis.Client.AddJob(&job.JobMessage{
 Id: uuid,
 DealTime: dealTime,
 }, + int64(dealTime))
 }
}

其中AddJob函数在另一个包中, 将上一个函数中随机生成的时间作为需要处理的时间戳.

?
1
2
3
4
5
6
7
8
// 添加任务
func (client *RedisClient) AddJob(msg *job.JobMessage, dealTime int64) {
 conn := client.Get()
 defer conn.Close()
 
 key := "JOB_MESSAGE_QUEUE"
 conn.Do("zadd", key, dealTime, util.JsonEncode(msg))
}

消费者

消费者处理流程分为两个步骤:

  • 获取小于等于当前时间戳的任务
  • 通过删除当前任务来判断谁获得了当前任务

因为在获取小于等于当前时间戳的任务时,可能有多个go routine同时读到了当前任务,而只有一个任务可以来处理当前任务。因此我们需要通过一个方案来判断究竟由谁来处理这个任务(当然如果只有一个消费者可以读到就直接处理):这个时候可以通过redis的删除操作来获取,因为删除指定value时只有成功的操作才会返回不为0,所以我们可以认为删除当前队列成功的那个go routine拿到了当前的任务。

下面是代码:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// 消费者
func consumer() {
 // 启动10个go routine一起去拿
 count := 0
 for count < 10 {
 go func() {
 for {
 jobs := redis.Client.GetJob()
 if len(jobs) <= 0 {
  time.Sleep(time.Second * 1)
  continue
 }
 currentJob := jobs[0]
 // 如果当前抢redis队列成功,
 if redis.Client.DelJob(currentJob) > 0 {
  var jobMessage job.JobMessage
  util.JsonDecode(currentJob, &jobMessage) //自定义的json解析函数
  handleMessage(&jobMessage)
 }
 
 }
 
 }()
 count++
 }
}
 
// 处理任务用函数
func handleMessage(msg *job.JobMessage) {
 fmt.Printf("deal job: %s, require time: %d \n", msg.Id, msg.DealTime)
 go func() {
 countChan <- true
 }()
}

redis部分的代码,获取任务和删除任务

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// 获取任务
func (client *RedisClient) GetJob() []string {
 conn := client.Get()
 defer conn.Close()
 
 key := "JOB_MESSAGE_QUEUE"
 timeNow := time.Now().Unix()
 ret, err := redis.Strings(conn.Do("zrangebyscore", key, 0, timeNow, "limit", 0, 1))
 if err != nil {
 panic(err)
 }
 return ret
}
 
// 删除当前任务, 用来判断是否抢到了当前任务
func (client *RedisClient) DelJob(value string) int {
 conn := client.Get()
 defer conn.Close()
 
 key := "JOB_MESSAGE_QUEUE"
 ret, err := redis.Int(conn.Do("zrem", key, value))
 if err != nil {
 panic(err)
 }
 return ret
}

代码大抵如此。最后跑起来之后,大概每3-4秒钟能够处理掉1w个任务,速度上确实是...

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。

原文链接:https://studygolang.com/articles/24925

延伸 · 阅读

精彩推荐
  • GolangGo语言基础单元测试与性能测试示例详解

    Go语言基础单元测试与性能测试示例详解

    这篇文章主要为大家介绍了Go语言基础单元测试与性能测试示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助祝大家多多进步...

    枫少文7812021-12-05
  • GolangGo语言range关键字循环时的坑

    Go语言range关键字循环时的坑

    今天小编就为大家分享一篇关于Go语言range关键字循环时的坑,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来...

    benben_20154202020-05-23
  • GolangGO语言字符串处理Strings包的函数使用示例讲解

    GO语言字符串处理Strings包的函数使用示例讲解

    这篇文章主要为大家介绍了GO语言字符串处理Strings包的函数使用示例讲解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步早日升职加...

    Jeff的技术栈6882022-04-14
  • GolangGolang实现四种负载均衡的算法(随机,轮询等)

    Golang实现四种负载均衡的算法(随机,轮询等)

    本文介绍了示例介绍了Golang 负载均衡的四种实现,主要包括了随机,轮询,加权轮询负载,一致性hash,感兴趣的小伙伴们可以参考一下...

    Gundy_8442021-08-09
  • GolangGo语言实现自动填写古诗词实例代码

    Go语言实现自动填写古诗词实例代码

    这篇文章主要给大家介绍了关于Go语言实现自动填写古诗词的相关资料,这是最近在项目中遇到的一个需求,文中通过示例代码介绍的非常详细,需要的朋...

    FengY5862020-05-14
  • GolangGolang 语言极简类型转换库cast的使用详解

    Golang 语言极简类型转换库cast的使用详解

    本文我们通过 cast.ToString() 函数的使用,简单介绍了cast 的使用方法,除此之外,它还支持很多其他类型,在这没有多多介绍,对Golang 类型转换库 cast相关知...

    Golang语言开发栈6112021-12-02
  • Golanggo语言获取系统盘符的方法

    go语言获取系统盘符的方法

    这篇文章主要介绍了go语言获取系统盘符的方法,涉及Go语言调用winapi获取系统硬件信息的技巧,具有一定参考借鉴价值,需要的朋友可以参考下 ...

    无尽海3862020-04-24
  • Golang深入浅析Go中三个点(...)用法

    深入浅析Go中三个点(...)用法

    这篇文章主要介绍了深入浅析Go中三个点(...)用法,需要的朋友可以参考下...

    踏雪无痕SS6472021-11-17