使用redis的setnx实现分布式锁(python实现)

背景:

在实际开发场景中,可能会出现多个服务可能会同时调用同一个方法的情况,但是想要保证在一定的时间内该方法只能被一个服务调用。

实现原理:

1.单线程:首先redis本身是单线程的,当有多个线程同时访问redis的时候,一定是一个一个线程的按照顺序的访问redis,因此这是使用redis实现分布式锁的一个原因。

2.原子性:setnx具有原子性,当有多个线程时,只会有一个线程可以使用setnx设置成功。

3.特点:当有重复的锁key的时候setnx查询缓存就会返回false或者空,那我们可以利用它的这种机制去实现多个服务的同时调用一个方法的时候让所有的服务都有互斥的效果。

具体实现代码:

import redis

class LockerException(Exception):
    pass

r = redis.Redis(host=REDIS_HOST, port=6379, decode_responses=True)
key_prefix = '项目名'

def set_nx(key, ex=60):
    if r.setnx(key_prefix+key, 1):
        r.expire(key_prefix+key, ex)
        return True
    elif r.ttl(key_prefix+key) == -1:
        r.expire(key_prefix + key, ex)
    return False

#  获取⼀个分布式锁
def acquire_lock(lock_name, ex):
    return set_nx(lock_name, ex)


# 释放锁
def release_lock(lock_name):
    del_(lock_name)

# 定义一个锁
def lock(lock_key, func, ex=60*5):
    locked = False
    try:
        locked = acquire_lock(lock_key, ex)
        if locked:
            func()
    except Exception as e:
        raise LockerException(e)
    finally:
        if locked:
            release_lock(lock_key)

# 使用分布式锁调用函数func_name
def run():
    lock('任务名称',func_name)
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
是的,Redis可以使用setnx命令来实现分布式setnx命令是Redis中的一个原子性操作,用于设置一个键值对,当键不存在时才会设置成功,如果键已经存在则设置失败。我们可以利用这个特性来实现分布式,比如可以将一个键作为名称,将当前时间作为的值,然后使用setnx命令来尝试获取,如果获取成功,则说明获取了,否则说明已经被其他进程占用。 为了避免死,我们还需要给设置过期时间,这样即使某个进程在获取之后发生了意外导致没有及时释放,也不会一直占用资源。 下面是使用setnx命令实现分布式的示例代码: ``` import redis import time class RedisLock: def __init__(self, redis_client, name, expire=60): self.redis_client = redis_client self.name = name self.expire = expire def acquire(self): while True: now = time.time() expires = now + self.expire if self.redis_client.setnx(self.name, expires): return expires else: value = self.redis_client.get(self.name) if value and now > float(value): old_value = self.redis_client.getset(self.name, expires) if old_value and old_value == value: return expires time.sleep(0.1) def release(self): self.redis_client.delete(self.name) ``` 在上面的代码中,我们定义了一个RedisLock类,它的构造函数接收一个Redis客户端对象、名称和过期时间。acquire方法用来获取,如果获取成功则返回的过期时间,否则阻塞等待。release方法用来释放,它会删除的键值对。在acquire方法中,我们不断循环尝试获取,直到获取成功为止。如果获取失败,则检查是否已经过期,如果过期则尝试用getset命令更新的值,并检查更新前后的值是否相等,如果相等则说明获取到了,否则继续重试。为了避免过多的CPU消耗,我们在尝试获取时加上了一个短暂的等待时间。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值