lua + redis 的去重队列

    背景是任务派发系统,咱们咱们的任务落地在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

相关文章
相关标签/搜索