redis:多节点上的线程锁[python]

cig3rfwq  于 2021-06-08  发布在  Redis
关注(0)|答案(1)|浏览(380)

使用Python3时, Redis (实际上 Flask 以及 Flask-Redis ),我经常发现自己处于这样一种情况:我用

data = redis_client.hgetall(id)

更改一些值,然后使用

redis_client.hset(id, data)

这显然不是线程安全的,所以我使用我在这里找到的实现添加了线程锁:
基于值的线程锁

import threading

namespace_lock = threading.Lock()
namespace = {}
counters = {}

def aquire_lock(value):
    with namespace_lock:
        if value in namespace:
            counters[value] += 1
        else:
            namespace[value] = threading.Lock()
            counters[value] = 1

    namespace[value].acquire()

def release_lock(value):
    with namespace_lock:
        if counters[value] == 1:
            del counters[value]
            lock = namespace.pop(value)
        else:
            counters[value] -= 1
            lock = namespace[value]

    lock.release()

# sample usage

def foo(id):
    aquire_lock(id)
    data = redis_client.hgetall(id)
    # ...
    redis_client.hset(id, data)
    release_lock(id)

当在一个节点上运行多个线程时,这种方法工作得很好,但是当在一个节点平衡器后面运行多个节点时,锁的信息不会在它们之间共享。
锁定访问权限的通常策略是什么 Redis 资源,当多个节点访问同一个数据库时?
到目前为止我已经试过了 Redlock (实际上 Flask-Redlock ),是什么导致了这样的代码:

from flask_redlock import RedisLock

redis_lock = RedisLock()
redis_lock.init_app(app)

with redis_lock.lock(f'{id}.lock', 3000, retry=10, interval=0.2) as lock:
    if not lock:
        return 'busy!'

    # Code Execution Part
    time.sleep(10)

但这允许我在 sleep 第一道螺纹的加工方法。因此,我得出结论,它可能只保护与 Redis .

b1zrtrql

b1zrtrql1#

好吧,你用错了红瓶。3000是ttl,这意味着锁将在3秒后自动过期,而您的睡眠时间是10秒。
如果测试代码,您会发现其他线程无法在3秒内获得锁。如果执行需要n秒,则总是锁定n+delta(delta>0)秒。在我看来,你应该加上至少2秒作为增量,2秒是锁定/解锁组合的往返时间,甚至你可以采取更多的假设你会解锁锁一旦你完成使用。

相关问题