zoukankan      html  css  js  c++  java
  • 《Redis深度历险》二(分布式锁)

    分布式锁

    redis命令积累

    • expire key 600; 设置超时时间
    • ttl key 查看超时时间

    本质上就是在redis里面占一个坑,别的进程要进来时,发现已经有人在了,只好放弃或稍后再试。

    1. setnx

      setnx lock true
      do sth
      del lock
      

      问题:如果中间逻辑出现异常,del将会无法执行,会陷入死锁

    2. setnx lock true
      expire 5
      do sth
      del lock
      

      问题:如果setnx和expire之间断掉,没有执行expre,陷入死锁

    3. 解决:setnx和expire组合的原子指令,也是分布式锁的奥义

      set lock true ex 5 nx
      do sth
      del lock
      

    超时问题

    redis分布式锁不能解决超时问题,如果在加锁和释放锁之间的逻辑执行的太长,以至于超出了锁的超时限制,就会有问题。

    解决:使用delifequals释放锁,而不是expire,可以传入key和一个随机数来保证释放锁的正确性。

    tag = random.nextint() // random tag
    if redis.set(key,tag,nx=True,ex=5):
    	do_sth
    	redis.delifequals(key,tag) 
    

    可重入性

    可重入性是指线程在持有锁的情况下再次请求加锁,如果一个锁支持同一个线程的多次加 锁,那么这个锁就是可重入的。Redis 分 布式锁如果要支持可重入,需要对客户端的 set 方法进行包装,使用线程的 Threadlocal 变量 存储当前持有锁的计数。

    import redis import threading
    locks = threading.local()
    locks.redis = {}
    
    def key_for(user_id):
      return "account_{}".format(user_id)
    
    def _lock(client,key):
      return bool(client.set(key,True,nx=True,ex=5))
    
    def _unlock(client,key):
      client.delete(key)
      
    def lock(client,user_id):
      key = key_for(user_id)
      if key in locks.redis:  # 若存在则锁的数量+1
        locks.redis[key] += 1
        return True
      ok = _lock(client,key)  # 若不存新增锁,数量设为1
      if not ok:
        retrun False
      locks.redis[key] = 1
      return True
    
    def unlock(client,user_id):
      key = key_for(user_id)
      if key in locks.redis:
        locks.redis[key] -= 1   # 释放锁,数量-1
        if locks.redis[key] <= 0: # 判断若小于0,则完全释放锁
          del locks.redis[key]
        return True
      return False              
    
    client = redis.StrictRedis()
    lock(client,"codehole")    # 第一次加锁,返回True
    lock(client,"codehole")    # 第二次,锁的数量+1,返回True
    
    unlock(client,"codehole")  # 释放一把锁
    unlock(client,"codehole")  # 完全释放锁
    
  • 相关阅读:
    C++中用Int转成bool时,只有0是false,其他都是true。这个和其他语言很不一样,注意不要掉坑里了。
    C# 获取动态验证码?
    Silverlight单元格事件
    LDAPHelper
    Perl内部保留变量(系统变量)
    WebSphere MQ基础命令
    老鼠, 老虎傻傻分不清楚之Double.NaN
    TextBlock or Label?
    如何阅读代码
    EDID
  • 原文地址:https://www.cnblogs.com/jimmyhe/p/13976135.html
Copyright © 2011-2022 走看看