zoukankan      html  css  js  c++  java
  • redis分布式锁

    通过setnx(set if not exists) 指令设置锁,调用 del 指令释放锁。

    // 这里的冒号:就是一个普通的字符,没特别含义,它可以是任意其它字符,不要误解
    > setnx lock:codehole true
    OK
    ... do something critical ...
    > del lock:codehole
    (integer) 1
     
    但是有个问题,如果逻辑执行到中间出现异常了,可能会导致 del 指令没有被调用,这样
    就会陷入死锁,锁永远得不到释放。
    于是我们在拿到锁之后,再给锁加上一个过期时间,比如 5s,这样即使中间出现异常也
    可以保证 5 秒之后锁会自动释放。
    > setnx lock:codehole true
    OK
    > expire lock:codehole 5
    ... do something critical ...
    > del lock:codehole
    (integer) 1
    但是以上逻辑还有问题。如果在 setnx 和 expire 之间服务器进程突然挂掉了,可能是因
    为机器掉电或者是被人为杀掉的,就会导致 expire 得不到执行,也会造成死锁。因为setnx 和 expire 是两条指令而不是原子指令。
     
    Redis 2.8 版本中作者加入了 set 指令的扩展参数,使得 setnx 和expire 指令可以一起执行
    > set lock:codehole true ex 5 nx
    OK ... do something critical ...
    > del lock:codehole
     
    超时问题
    Redis 的分布式锁不能解决超时问题,如果在加锁和释放锁之间的逻辑执行的太长,以至
    于超出了锁的超时限制,就会出现问题。因为这时候锁过期了,第二个线程重新持有了这把锁,
    但是紧接着第一个线程执行完了业务逻辑,就把锁给释放了,第三个线程就会在第二个线程逻
    辑执行完之间拿到了锁。
    为了避免这个问题,Redis 分布式锁不要用于较长时间的任务。如果真的偶尔出现了,数
    据出现的小波错乱可能需要人工介入解决。
    tag = random.nextint() # 随机数
    if redis.set(key, tag, nx=True, ex=5):
    do_something()
    redis.delifequals(key, tag) # 假象的 delifequals 指令
    有一个更加安全的方案是为 set 指令的 value 参数设置为一个随机数,释放锁时先匹配
    随机数是否一致,然后再删除 key。但是匹配 value 和删除 key 不是一个原子操作,Redis 也
    没有提供类似于 delifequals 这样的指令,这就需要使用 Lua 脚本来处理了,因为 Lua 脚本可
    以保证连续多个指令的原子性执行。
    # delifequals
    if redis.call("get",KEYS[1]) == ARGV[1] then
    return redis.call("del",KEYS[1])
    else
    return 0
    end
     
     
     
     
  • 相关阅读:
    TQJson序列和还原clientdataset.data
    BPL插件框架的二种实现
    数据序列的本质论
    MSGPACK(一)
    内存数据库和关系数据库之间的数据同步原理
    redis神器
    从Cell的视图推出一个新的界面
    iOS -- DES算法
    Base64---加密
    iOS -- MD5加密
  • 原文地址:https://www.cnblogs.com/wuwuyong/p/11738396.html
Copyright © 2011-2022 走看看