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

相關文章
相關標籤/搜索