Redis的基於互斥我想實現一個基於內存的多進程共享互斥體,它支持超時,使用Redis的。紅寶石 - 與到期實現
我需要該互斥鎖是非阻塞的,這意味着我只需要能夠知道我是否能夠獲取互斥鎖,如果沒有,只需繼續執行後備代碼即可。
東西沿着這些路線:
if lock('my_lock_key', timeout: 1.minute)
# Do some job
else
# exit
end
的未到期互斥可以採用以下方式實現的Redis的setnx mutex 1
:
if redis.setnx('#{mutex}', '1')
# Do some job
redis.delete('#{mutex}')
else
# exit
end
但是如果我需要一個超時機制互斥(在爲了避免在命令redis.delete
之前ruby代碼失敗的情況,導致該互斥鎖永遠被鎖定,例如,但不僅僅是這個原因)。
做這樣的事情顯然是行不通的:
redis.multi do
redis.setnx('#{mutex}', '1')
redis.expire('#{mutex}', key_timeout)
end
因爲我的到期重新設置爲互斥即使我無法設置互斥(setnx
返回0)。
當然,我會預料會有類似於setnxex
的東西,它會以到期時間自動設置密鑰的值,但前提是密鑰不存在。不幸的是,據我所知,Redis並不支持這一點。
我也不過,找到renamenx key otherkey
,它可以讓你重新命名一個關鍵的一些其他關鍵,只有在其他關鍵已不存在。
我想出了這樣的事情(用於演示目的,我把它寫下來單片,並沒有打破它的方法):
result = redis.multi do
dummy_key = "mutex:dummy:#{Time.now.to_f}#{key}"
redis.setex dummy_key, key_timeout, 0
redis.renamenx dummy_key, key
end
if result.length > 1 && result.second == 1
# do some job
redis.delete key
else
# exit
end
在這裏,我設置了過期假鑰匙,並嘗試將其重命名爲真鑰匙(在一次交易中)。
如果renamenx
操作失敗,那麼我們無法獲取互斥鎖,但是沒有造成任何損害:虛擬關鍵字將到期(可以通過添加一行代碼立即刪除),並且真正的密鑰到期時間將保持不變。
如果renamenx
操作成功,那麼我們就能夠獲得互斥體,和互斥將獲得所需的到期時間。
任何人都可以看到與上述解決方案的任何缺陷?這個問題是否有更加標準的解決方案?我真的很討厭使用一個外部的寶石,以解決這個問題...