zoukankan      html  css  js  c++  java
  • 高并发-Redis分布式锁setnx,setex连用

    Lua在Redis中的使用方式

    ​ redis中内嵌了Lua脚本的解释器,并提供了执行Lua脚本的入口“eval”命令,

    ​ 格式为 EVAL script numkeys key [key ...] arg [arg...] .

    ​ 其中eval 为命令, script为执行的命令脚本, numkeys 为脚本中共涉及到的key的数量,后续接收若干个key的输入和若干个arg的输入.

    整个脚本中使用KEYS[index],和ARGS[index]来获取实际的输入有点类似于SQL的占位符。另外一层原因由于Redis集群的固有模式导致EVAL在集群中涉及多个KEY的操作时要求所有的KEY都在同一个Hash Solt上,集群环境中调用EVAL Redis会对脚本先做一个的校验。
    KEYS[1] KEYS[2],是要操作的键,可以指定多个,在lua脚本中通过KEYS[1], KEYS[2]获取。【特别注意】这些键要现在redis中存在,不然就获取不到对应的值。
    ARGV[1] ARGV[2],参数在lua脚本中通过ARGV[1], ARGV[2]获取。

    redis 执行Lua的保证

    ​ Redis中保证对一个Lua脚本执行的完整性,也就是说一个Lua脚本的执行只会有成功和失败,且保证在Redis Server端同时只会有一个Lua脚本在运行,这样就意味着Lua脚本中的操作是一个完整的原子操作,不会伴随中间状态和资源竞争,同时也意味着在Lua脚本中不适合进行一些耗时长的操作.由于有以上的保证,使用Redis来进行一些复杂的原子操作就在合适不过了,setNx方法的局限性也被Redis Lua进行了弥补.

    ​ Redis对嵌入的Lua做了若干的限制,包保证脚本不对Redis 造成破坏.不提供访问系统状态的库,禁止使用loadfile函数,禁止带有随机性质的命令或者带有副作用的命令, 对随机读命令的结果进行排序,替换math原有的random方法,不允许定义函数,不允许声明全局变量等等.

    要注意的是Lua中 0 为 true。
    

    在脚本中调用redis命令
    在脚本中可以使用redis.call函数调用Redis命令

      redis.call('set', 'foo', 'bar')
      local value=redis.call('get', 'foo') --value的值为bar
    

    redis.call函数的返回值就是Redis命令的执行结果

    Redis命令的返回值有5种类型,redis.call函数会将这5种类型的回复转换成对应的Lua的数据类型。

    Redis Setnx(SET if Not eXists) 命令在指定的 key 不存在时,为 key 设置指定的值。

    Redis分布式锁

    • 分布锁满足两个条件,一个是加有效时间的锁,一个是高性能解锁

    • 采用redis命令setnx(set if not exist)、setex(set expire value)实现

    【千万记住】解锁流程不能遗漏,否则导致任务执行一次就永不过期

    分布式锁setnx、setex的缺陷,在setnx和setex中间发生了服务down机

    • 从Redis宕机讲解分布式锁执行的异常场景流程

    • 从Server服务宕机讲解分布式锁执行的异常场景流程

    • 在setnx和setex中间发生了服务down机 那么key将没有超时时间 会一直存在,新的请求永远进不来

    解决方案:

    由于setnx与setex是分步进行,那么我们将两步合成一步,放在同一个原子中即可

    • 怎么一次性执行过一条命令而不会出现问题,采用Lua脚本

    • Redis从2.6之后支持setnx、setex连用

    Lua简介

      从 Redis 2.6.0 版本开始,通过内置的 Lua 解释器,可以使用 EVAL 命令对 Lua 脚本进行求值。
      * Redis 使用单个 Lua 解释器去运行所有脚本,并且, Redis 也保证脚本会以原子性(atomic)的方式执行:当某个脚本正在运行的时候,不会有其他脚本或 Redis 命令被执行。这和使用 MULTI / EXEC 包围的事务很类似。在其他别的客户端看来,脚本的效果(effect)要么是不可见的(not visible),要么就是已完成的(already completed)。
    在 Lua 脚本中,可以使用redis.call()来执行 Redis 命令

    Lua脚本配置流程

      1、在resource目录下面新增一个后缀名为.lua结尾的文件
      2、编写lua脚本

          local lockKey = KEYS[1]
          local lockTime = KEYS[2]
          local lockValue = KEYS[3]
    
          -- setnx info
          local result_1 = redis.call('SETNX', lockKey, lockValue)
          if result_1 == 1
          then
          local result_2= redis.call('SETEX', lockKey,lockTime, lockValue)
          return result_2
          else
          return 'faild'
          end
    

    3、传入lua脚本的key和arg
    4、调用redisTemplate.execute方法执行脚本

  • 相关阅读:
    面板评分太低会算两次
    没有使用大漩涡传送门没有杀死大法师瓦格斯
    win10创建本地用户
    延迟着色
    GPU 优化总结
    UE4 减少APK包的大小
    UE4 性能优化方法(工具篇)
    Unreal Engine 4的常见Tips
    虚幻引擎4设置Visual Studio
    模型导入的单位问题
  • 原文地址:https://www.cnblogs.com/caibaotimes/p/14415351.html
Copyright © 2011-2022 走看看