背景是任务派发系统,咱们咱们的任务落地在mysql, 而后有经过redis 的list 作队列,由于任务是幂等的,因此,超时任务和失败重试任务会从新入队。这里出现了一个状况,就是咱们的任务,好比,视频转码,是极其耗时的,任务出现重复入队的状况,这不是咱们所指望的,因此咱们须要对任务进行去重。python
该文章后续仍在不断的更新修改中, 请移步到原文地址http://dmwan.ccmysql
由于redis 对lua 脚本是执行的,因此咱们的思路是 list + set ,来保证队列去重。lua 脚本以下:golang
SCRIPT_PUSH = ` local q = KEYS[1] local q_set = KEYS[1] .. "_set" local v = redis.call("SADD", q_set, ARGV[1]) if v == 1 then return redis.call("RPUSH", q, ARGV[1]) and 1 else return 0 end ` SCRIPT_POP = ` local q = KEYS[1] local q_set = KEYS[1] .. "_set" local v = redis.call("LPOP", q) if v ~= "" then redis.call("SREM", q_set, v) end return v `
在push 任务以前,先看任务是否在set 中,在pop以后,马上从set中删除,由于lua 脚本的原子性,因此,能起到去重的做用。redis
在python 中调用的方式以下: sql
import redis SCRIPT_PUSH = ''' local q = KEYS[1] local q_set = KEYS[1] .. "_set" local v = redis.call("SADD", q_set, ARGV[1]) if v == 1 then return redis.call("RPUSH", q, ARGV[1]) and 1 else return 0 end ''' SCRIPT_POP = ''' local q = KEYS[1] local q_set = KEYS[1] .. "_set" local v = redis.call("LPOP", q) if v ~= "" then redis.call("SREM", q_set, v) end return v ''' pool = redis.ConnectionPool(host='localhost', port=6379, db=0) r = redis.Redis(connection_pool=pool) script1 = r.register_script(SCRIPT_PUSH) script2 = r.register_script(SCRIPT_POP) print r.get("mykey") print script1( keys=["mykey"], args = [1,0] ) print r.get("mykey"), "ok" print r.get("mykey") print script2( keys=["mykey"], args = [1] ) print r.get("mykey")
golang 等其余语言,使用方式同样,没什么好说的。lua