zoukankan      html  css  js  c++  java
  • redis 正确实现分布式锁的正确方式

    前言

    最近在自己所管理的项目中,发现redis加锁的方式不对,在高并发的情况有问题。故在网上找搜索了一把相关资料。发现好多都是互相抄袭的,很多都是有缺陷的。好多还在用redis 的 setnx命令来实现分布式锁。其实redis 中的set命令本身就已经集成了setnx命令的功能了,而且比其还强大。这里,我使用 redis-cli 客户端 结合lua脚本 原生 的实现redis 分布式锁。

    准备材料

    • redis-server
    • redis-cli

    LUA 与 REDIS 的关系

    从 redis2.6.0 开始, redis 内部就内置了lua解释器。lua也就是成了redis扩展的一种解决方案了。
    格式:

    eval scripts num [keys ...] [argv ...]
    
    • eval : redis中执行lua脚本的命令
    • scripts : lua脚本,不必一定得是lua函数
    • num : keys 的个数,用于区分 keys 和 argv ;没有keys,则写0
    • keys: 可变数组,一般用于表示redis 的键,下标从1 开始
    • argv: 可变数组,一般用于表示redis 的值,下标从1 开始

    redis 与 lua 的交互

    分两种情况:

    • redis 执行 lua 脚本 : 使用 redis中的 eval命令 即可
    • lua & redis
      • lua 接收 redis 发送过来的数据 , 在 SCRIPTS中使用 KEYS[] 与 ARGV[]
      • lua 调用redis 命令, 在SCRIPTS中使用 call() 或者 pcall()
      • lua 将结果返回给redis , 使用return

    案例解析

    1.利用lua 打印参数
    127.0.0.1:6379> eval "return {KEYS[1],ARGV[1],ARGV[2]}" 3 key1 key2 first second threed
    1) "key1"
    2) "second"
    3) "threed"
    

    2.通过lua 设置变量
    # 设置一个 foo='hello' 键值对
    127.0.0.1:6379> eval "return redis.call('set','foo','hello')" 0
    OK
    127.0.0.1:6379> scan 0
    1) "0"
    2) 1) "foo"
    127.0.0.1:6379> get foo
    "hello"
    127.0.0.1:6379>
    
    3.通过lua 传参的方式 设置变量
    127.0.0.1:6379> eval "return redis.call('set',KEYS[1],ARGV[1])" 1 name Bob
    OK
    127.0.0.1:6379> keys *
    1) "name"
    127.0.0.1:6379> get name
    "Bob"
    127.0.0.1:6379>
    
    4. 利用redis-cli 设置分布式锁
    # 加锁 , 直接使用 set nx模式 【生产环境中123456 是一个唯一的随机数】
    127.0.0.1:6379> set lock 123456 EX 40 NX
    OK
    
    # 解锁 , 结合 lua脚本
    127.0.0.1:6379> eval "if redis.call('get','lock') == ARGV[1] then return  redis.call('del','lock') else return 0 end" 0 123456
    (integer) 1
    
    127.0.0.1:6379> get lock
    (nil)
    

    上面的lua脚本格式化后的样子如下:

    if redis.call('get','lock') == ARGV[1]
    then
        return redis.call('del','lock')
    else
        return 0
    end
    
  • 相关阅读:
    关于windows客户端网络编程 WSAAsyncSelect函数
    阻塞模式和非阻塞模式
    SRP6协议分析
    普通二叉树转换成二叉查找树方法
    使用openssl库进行开发
    类型转化,网络开发中常见的类型转化
    到底还能够称多久
    权限子系统小结
    使用ASP.NET AJAX开发服务器端事件通知器
    通用权限相关文档的下载
  • 原文地址:https://www.cnblogs.com/yinguohai/p/11414779.html
Copyright © 2011-2022 走看看