分布式锁

需求

实现一个分布式锁

问题

  1. 分布式锁与传统的锁有和区别
    关于这个问题相关的解释不是很多,没看到官方解释和对比;民间的解释是这样的,我们所说的传统的锁,一般指的是线程锁,而分布式锁指的是进程锁。
    个人对民间的这种称呼,不是很认同。单主机下的进程锁,和多主机下的进程锁(分布式锁)应该还是区别,至少实现上来说多主机锁,需要比单主机进程所多考虑一点跨主机的网络通信问题。这个网络通信是对进程锁的设计,在不同的场景下,还是有不同的区别的。

我的思路

  1. 其实我开始想到的第一个点就是,我们现在使用的锁,利用python的fcntl库(文件锁)实现的一种锁,支持区分读写锁、阻塞锁、非阻塞锁;文件锁属于进程锁。
  2. 我们的web程序是多进程的,Apache开的多个httpd进程,多个进程竞争自愿。使用文件锁能够满足普通的需求。
  3. 当我被别人问起,分布式锁的时候,我就很诧异,那我用这个本身不就能当作一个分布式锁来用么,不过需要加一些网络接口(比如restful api),读完接下来下面业界常用的实现方法,再来看我自己的这个疑问。

业界常用做法

今天只说一种最常用的,利用redis实现的分布式锁,redis本身(redis操作)的原子性,对锁的支持是天然的。
(1)获取锁的时候,使用setnx加锁,并使用expire命令为锁添加一个超时时间,超过该时间则自动释放锁,锁的value值为一个随机生成的UUID,通过此在释放锁的时候进行判断。
(2)获取锁的时候还设置一个获取的超时时间,若超过这个时间则放弃获取锁。
(3)释放锁的时候,a.通过UUID判断是不是该锁,若是该锁,b.则执行delete进行锁释放。(注意ab操作要保证原子性,否则,可能存在这样的情况,执行步骤a------>锁超时释放--------->另一个任务加锁成功----------->执行步骤b;这样的后果,就是锁的添加释放错乱了;可以利用redis的事务实现多个操作的原子性)

redis分布式锁参考
锁参考

代码实现
#连接redis
import time
import uuid
from threading import Thread

import redis

redis_client = redis.Redis(host="localhost",
                           port=6379,
                           # password=123,
                           db=10)

#获取一个锁
# lock_name:锁定名称
# acquire_time: 客户端等待获取锁的时间
# time_out: 锁的超时时间
def acquire_lock(lock_name, acquire_time=10, time_out=10):
    """获取一个分布式锁"""
    identifier = str(uuid.uuid4())
    end = time.time() + acquire_time
    lock = "string:lock:" + lock_name
    while time.time() < end:
        if redis_client.setnx(lock, identifier):
            # 给锁设置超时时间, 防止进程崩溃导致其他进程无法获取锁
            redis_client.expire(lock, time_out)
            return identifier
        elif not redis_client.ttl(lock):
            redis_client.expire(lock, time_out)
        time.sleep(0.001)
    return False

#释放一个锁
def release_lock(lock_name, identifier):
    """通用的锁释放函数"""
    lock = "string:lock:" + lock_name
    pip = redis_client.pipeline(True)
    while True:
        try:
            pip.watch(lock)
            lock_value = redis_client.get(lock)
            if not lock_value:
                return True

            if lock_value.decode() == identifier:
                pip.multi()
                pip.delete(lock)
                pip.execute()
                return True
            pip.unwatch()
            break
        except redis.excetions.WacthcError:
            pass
    return False
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值