分布式锁介绍

分布式锁介绍

分布式锁: 在分布式的环境中加锁,通俗点就是在集群环境下加锁

用途: 用在抢购,预售等用途,用来保证多台机器上的数据并发安全

在这里插入图片描述

mysql中的悲观锁,乐观锁就是分布式锁的一种,但是mysql的性能很低,在高并发的环境下,一般不用mysql的锁,而使用其他的分布式锁。
使用可以基于redis实现,并且非常简单,官方提供了Redlock模块调用,

from redlock import RedLock

lock = RedLock('distribted_lock')
lock.acquire()   # 获取锁
# 抢到锁之后的逻辑
do_something()
lock.release()   # 释放锁

内部逻辑

  1. 使用命令介绍
    (1)SETNX
    SETNX key val:当且仅当key不存在时,set一个key为val的字符串,返回1;若key存在,则什么都不做,返回0。
    (2)expire
    expire key timeout:为key设置一个超时时间,单位为second,超过这个时间锁会自动释放,避免死锁。
    (3)delete
    delete key:删除key
    在使用Redis实现分布式锁的时候,主要就会使用到这三个命令。

  2. 实现思想

​ (1)获取锁的时候,使用setnx加锁,并使用expire命令为锁添加一个超时时间,超过该时间则自动释放锁,锁的value值为一个随机生成的UUID,通过此在释放锁的时候进行判断。

​ (2)获取锁的时候还设置一个获取的超时时间,若超过这个时间则放弃获取锁。

​ (3)释放锁的时候,通过UUID判断是不是该锁,若是该锁,则执行delete进行锁释放。

demo

# 连接redis
redis_client = redis.Redis(host="localhost",
                           port=6379,
                           password=password,
                           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

补充

分布式id的选择

  1. 选择mysql的自增类型,性能不高
  2. 使用当前时间戳,多台机器,同一个时刻,id会重复
  3. 使用uuid,数据量大,也可能会重复
  4. 多台服务器生成不重复id: 推荐使用雪花算法,并且python有现成的模块可以实现

分布式锁还可以通过ZooKeeper实现

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

go&Python

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值