redis分布式锁

  1. redis分布式锁要解决的问题:为了保证一个方法或属性在高并发情况下的同一时间只能被同一个线程执行,在传统单体应用单机部署的情况下,可以使用并发处理相关的功能进行互斥控制。但是,随着业务发展的需要,原单体单机部署的系统被演化成分布式集群系统后,由于分布式系统多线程、多进程并且分布在不同机器上,这将使原单机部署情况下的并发控制锁策略失效,单纯的应用并不能提供分布式锁的能力。为了解决这个问题就需要一种跨机器的互斥机制来控制共享资源的访问,这就是分布式锁要解决的问题!(可以保证在分布式部署的应用集群中,同一个方法在同一操作只能被一台机器上的一个线程执行,在传统的基于数据库的架构中,对于数据的抢占问题往往是通过数据库事务(ACID)来保证的。在分布式环境中,出于对性能以及一致性敏感度的要求,使得分布式锁成为了一种比较常见而高效的解决方案)
  2. 分布式锁应该具备哪些条件:
    1. 高可用的获取锁与释放锁
    2. 高性能的获取锁与释放锁
    3. 具备可重入特性
    4. 具备锁失效机制,防止死锁
    5. 具备非阻塞锁特性,即没有获取到锁将直接返回获取锁失败
  3. 选用Redis实现分布式锁原因:
    1. Redis有很高的性能
    2. Redis命令对此支持较好,实现起来比较方便
  4. redis分布式锁常见命令
    1. setnx: SETNX key val:当且仅当key不存在时,创建一个kv的字符串锁,返回1;若key存在,则什么都不做,返回0
    2. expire:expire key timeout:为key设置一个超时时间,单位为second,超过这个时间锁会自动释放,避免死锁
    3. delete:delete key:删除key
  5. 设计思想:
    1. 获取锁的时候,使用setnx加锁,并使用expire命令为锁添加一个超时时间,超过该时间则自动释放锁,锁的value值为一个随机生成的UUID,通过value在释放锁的时候进行判断
    2. 获取锁的时候还设置一个获取的超时时间,若超过这个时间则放弃获取锁
    3. 释放锁的时候,通过UUID判断是不是该锁,若是该锁,则执行delete进行锁释放
  6. 代码(50个用户或线程抢10张票):
import time
import uuid
from threading import Thread

import redis

redis_client = redis.Redis(host="localhost",
                           port=6379,
                           db=0)

#获取一个锁
# 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)  # 对key进行监视,监视一个(或多个) key ,如果在事务执行之前这个(或这些) key 被其他命令所改动,那么事务将被打断
            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


count = 10
def seckill(i):
    identifier=acquire_lock('resource')
    print("线程:{}--获得了锁".format(i))
    time.sleep(1)
    global count
    if count < 1:
        print("线程:{}--没抢到,票抢完了".format(i))
        return
    count-=1
    print("线程:{}--抢到一张票,还剩{}张票".format(i,count))
    release_lock('resource',identifier)


for i in range(50):
    t = Thread(target=seckill,args=(i,))
    t.start()
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值