zset实现延时队列
一、zset相关操作
zrangebyscore:从zset拿出区间在[n,m]内的元素值
zadd:往zset添加一个元素
zrem:删除一个元素
多消费者异步消费数据的时候,先从zset拿到数据,然后删除数据,最后再去消费数据,这样可以确保任务不被其他消费者消费到
package delayqueue import ( "fmt" "log" "math/rand" "time" "github.com/garyburd/redigo/redis" "Project_A/json" ) type redisClient struct { cli redis.Conn } func NewRedis() *redisClient{ conn,err:=redis.Dial("tcp","127.0.0.1:6379") if err!=nil{ log.Println("redis err:%v",err) panic(err) } return &redisClient{cli: conn} } type TaskMsg struct { Name string DelayTime int64 } func (c *redisClient)AddTask(msg *TaskMsg, dealTime int64) { key := "DelayQueue" data,err:=json.Marshal(msg) if err!=nil{ fmt.Errorf("AddTask err:%v",err) return } // 将延期的时间作为score,写进zset ret,err:=c.cli.Do("zadd", key, dealTime,data ) if err!=nil{ fmt.Errorf("%v",err) return } if ret!=0{ fmt.Errorf("%v msg:%v",ret,msg) } } func (c *redisClient)DelTask(value string) int{ key := "DelayQueue" ret, err := redis.Int(c.cli.Do("zrem", key, value)) if err != nil { panic(err) } return ret } func (c *redisClient)GetTask() []string{ key := "DelayQueue" nowTime := time.Now().Unix() // zrangebyscore 从zset拿出score在[0,nowTime]的元素 ret, err := redis.Strings(c.cli.Do("zrangebyscore", key, 0, nowTime, "limit", 0, 1)) if err != nil { fmt.Errorf("GetTask err:%v",err) } return ret } func (c *redisClient)producer(count int) { for i:=0;i<count;i++ { dealTime := int64(rand.Intn(5)) + time.Now().Unix() taskName := fmt.Sprintf("task_%v",i) task:=&TaskMsg{ Name: taskName, DelayTime: dealTime, } c.AddTask(task,dealTime) fmt.Printf("%v\n",task) } } // 消费者 func (c *redisClient) consumer() { for { tasks := c.GetTask() if len(tasks) <= 0 { time.Sleep(time.Second * 1) continue } fmt.Printf("now time:%v,get task:%v",time.Now().Unix(),tasks[0]) // 如果当前抢redis队列成功, if c.DelTask(tasks[0]) > 0 { task:=&TaskMsg{} err:=json.Unmarshal([]byte(tasks[0]),task) if err!=nil{ fmt.Errorf("unmarshal err:%v",err) return } handleMessage(task) } } } // 处理任务用函数 func handleMessage(msg *TaskMsg) { fmt.Printf("handleMessage: %s, now time:%v,require time: %d \n", msg.Name,time.Now().Unix(), msg.DelayTime) } func Test(){ //https://juejin.cn/post/6844904003810099208 svr:=NewRedis() svr.producer(10) svr.consumer() }
等风起的那一天,我已准备好一切