内容简介:1、Redis命令行执行Lua脚本01 、redis.call() 和 redis.pcall() 两个函数的参数可以是任意的 Redis 命令
01 、redis.call() 和 redis.pcall() 两个函数的参数可以是任意的 Redis 命令
127.0.0.1:6379> EVAL "return redis.call('SET','Name','Tinywan')" 0
OK
127.0.0.1:6379> get Name
"Tinywan"
说明: EVAL 和 EVALSHA 命令是从 Redis 2.6.0 版本开始的,使用内置的 Lua 解释器,可以对 Lua 脚本进行求值。
EVAL的第一个参数是一段 Lua 5.1 脚本程序。 这段Lua脚本不需要(也不应该)定义函数。它运行在 Redis 服务器中。
EVAL的第二个参数是参数的个数,后面的参数(从第三个参数),表示在脚本中所用到的那些 Redis 键(key),这些键名参数可以在 Lua 中通过全局变量 KEYS 数组,用 1 为基址的形式访问( KEYS[1] , KEYS[2] ,以此类推)。
在命令的最后,那些不是键名参数的附加参数 arg [arg …] ,可以在 Lua 中通过全局变量 ARGV 数组访问,访问的形式和 KEYS 变量类似( ARGV[1] 、 ARGV[2] ,诸如此类)。
02、使用KEYS和ARGV
127.0.0.1:6379> EVAL "return redis.call('SET',KEYS[2],ARGV[3])" 3 name01 name02 name03 Tinywan01 Tinywan02 Tinywan03
OK
127.0.0.1:6379> keys *
1) "name02"
127.0.0.1:6379> get name02
"Tinywan03"
说明:返回结果是Redis multi bulk replies的Lua数组,这是一个Redis的返回类型,您的客户端库可能会将他们转换成数组类型。
03 、redis.call() 和 redis.pcall() 的区别
redis.call() 执行一个不存在的Redis命令: SETNGX
127.0.0.1:6379> EVAL "redis.call('SETNGX',KEYS[1],ARGV[1]);redis.call('SET',KEYS[3],ARGV[1])" 3 name01 name02 name03 Tinywan01 Tinywan02 Tinywan03
(error) ERR Error running script (call to f_0adfcdb3f740b2aabfe19f0e80de7cda7ce6262f): @user_script:1: @user_script: 1: Unknown Redis command called from Lua script
127.0.0.1:6379> keys *
(empty list or set)
127.0.0.1:6379>
说明:当 redis.call() 在执行命令的过程中发生错误时,脚本会停止执行,并返回一个脚本错误,错误的输出信息会说明错误造成的原因。由于第一个执行错误,导致后面的也没有执行,设置不成功。
redis.pcall() 执行一个不存在的Redis命令: SETNGX
127.0.0.1:6379> EVAL "redis.pcall('SETNGX',KEYS[1],ARGV[1]);redis.call('SET',KEYS[3],ARGV[1])" 3 name01 name02 name03 Tinywan01 Tinywan02 Tinywan03
(nil)
127.0.0.1:6379> keys *
1) "name03"
127.0.0.1:6379> get name03
"Tinywan01"
127.0.0.1:6379>
说明: redis.pcall() 出错时并不引发(raise)错误,而是返回一个 nil,后面的命令任然可以执行成功。
redis.call() 与 redis.pcall()很类似, 他们唯一的区别是当redis命令执行结果返回错误时, redis.call()将返回给调用者一个错误,而redis.pcall()会将捕获的错误以Lua表的形式返回。
redis.call() 和 redis.pcall() 两个函数的参数可以是任意的 Redis 命令
2、Redis中Lua脚本命令介绍
01、SCRIPT 命令
命令用于将脚本 script 添加到脚本缓存中,但并不立即执行这个脚本。
127.0.0.1:6379> SCRIPT LOAD "return redis.call('set',KEYS[1],ARGV[1])"
"c686f316aaf1eb01d5a4de1b0b63cd233010e63d"
02、EVALSHA 命令
根据给定的 SHA1 校验码(也就是 SCRIPT LOAD 执行脚本生成的哈希值),对缓存在服务器中的脚本进行求值。 将脚本缓存到服务器的操作可以通过 SCRIPT LOAD 命令进行。
127.0.0.1:6379> EVALSHA c686f316aaf1eb01d5a4de1b0b63cd233010e63d 2 Github Blog github.tinywan blog.tinywan OK 127.0.0.1:6379> keys * 1) "Github" 2) "name03" 127.0.0.1:6379> get Github "github.tinywan"
03、 SCRIPT FLUSH 命令
清空Lua脚本缓存 Flush the Lua scripts cache.
127.0.0.1:6379> SCRIPT FLUSH
OK
127.0.0.1:6379> EVALSHA c686f316aaf1eb01d5a4de1b0b63cd233010e63d 2 Github Blog github.tinywan blog.tinywan
(error) NOSCRIPT No matching script. Please use EVAL.
127.0.0.1:6379> SCRIPT LOAD "return redis.call('set',KEYS[1],ARGV[1])"
"c686f316aaf1eb01d5a4de1b0b63cd233010e63d"
127.0.0.1:6379> EVALSHA c686f316aaf1eb01d5a4de1b0b63cd233010e63d 2 Github Blog github.tinywan blog.tinywan
OK
127.0.0.1:6379>
04、SCRIPT EXISTS
命令用于校验指定的脚本是否已经被保存在缓存当中
127.0.0.1:6379> SCRIPT EXISTS c686f316aaf1eb01d5a4de1b0b63cd233010e63d 1) (integer) 1 127.0.0.1:6379> SCRIPT FLUSH OK 127.0.0.1:6379> SCRIPT EXISTS c686f316aaf1eb01d5a4de1b0b63cd233010e63d 1) (integer) 0 127.0.0.1:6379>
05、SCRIPT KILL
杀死当前正在运行的 Lua 脚本
3、调试
script.lua脚本
local foo = redis.call("ping")
return foo
执行脚本
$ redis-cli --eval script.lua PONG
loop.lua脚本
local i = 0
while true do
i = i + 1
redis.debug(i)
end
return "OK"
进入调试模式
$ redis-cli --ldb --eval loop.lua set set , wet set Lua debugging session started, please use: quit -- End the session. restart -- Restart the script in debug mode again. help -- Show Lua script debugging commands. * Stopped at 1, stop reason = step over -> 1 local i = 0 ^C
打开另外一个 shell 窗口
www@iZ2zec3dge6rwz2uw4tveuZ:~$ redis-cli 127.0.0.1:6379> keys * (error) BUSY Redis is busy running a script. You can only call SCRIPT KILL or SHUTDOWN NOSAVE. 127.0.0.1:6379> keys * (error) BUSY Redis is busy running a script. You can only call SCRIPT KILL or SHUTDOWN NOSAVE. 127.0.0.1:6379> keys * (error) BUSY Redis is busy running a script. You can only call SCRIPT KILL or SHUTDOWN NOSAVE. 127.0.0.1:6379> SCRIPT KILL OK 127.0.0.1:6379> keys * 1) "REDIS_CACHE:RESTY_VOD_DETAIL:55"
4、实现分布式锁
使用 PHP 实现分布式锁
<?php
/**.-------------------------------------------------------------------------------------------------------------------
* | Github: https://github.com/Tinywan
* | Blog: http://www.cnblogs.com/Tinywan
* |--------------------------------------------------------------------------------------------------------------------
* | Author: Tinywan(ShaoBo Wan)
* | DateTime: 2018/9/13 22:28
* | Mail: 756684177@qq.com
* | Desc: 使用Redis实现分布式锁
* '------------------------------------------------------------------------------------------------------------------*/
class RedisLock
{
/**
* 获取锁
* @param string $lock_name 锁名
* @param int $acquire_time 重复请求次数
* @param int $lock_timeout 请求超时时间
* @return bool|string
*/
public static function acquireLock($lock_name, $acquire_time = 3, $lock_timeout = 120)
{
$identifier = md5($_SERVER['REQUEST_TIME'] . mt_rand(1, 10000000));
$lock_name = 'LOCK:' . $lock_name;
$lock_timeout = intval(ceil($lock_timeout));
$end_time = time() + $acquire_time;
while (time() < $end_time) {
$script = <<<luascript
local result = redis.call('setnx',KEYS[1],ARGV[1]);
if result == 1 then
redis.call('expire',KEYS[1],ARGV[2])
return 1
elseif redis.call('ttl',KEYS[1]) == -1 then
redis.call('expire',KEYS[1],ARGV[2])
return 0
end
return 0
luascript;
$result = location_redis()->evaluate($script, array($lock_name, $identifier, $lock_timeout), 1);
if ($result == '1') {
return $identifier;
}
usleep(100000); // 函数延迟代码执行若干微秒
}
return false;
}
/**
* 释放锁
* @param string $lock_name 锁名
* @param string $identifier 获取锁返回的标识
* @return bool
*/
public static function releaseLock($lock_name, $identifier)
{
$lock_name = 'LOCK:' . $lock_name;
while (true) {
$script = <<<luascript
local result = redis.call('get',KEYS[1]);
if result == ARGV[1] then
if redis.call('del',KEYS[1]) == 1 then
return 1;
end
end
return 0
luascript;
$result = location_redis()->evaluate($script, array($lock_name, $identifier), 1);
if ($result == 1) {
return true;
}
break;
}
//进程已经失去了锁
return false;
}
}
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 【分布式锁】07-Zookeeper实现分布式锁:Semaphore、读写锁实现原理
- 原 荐 分布式锁与实现(二)基于ZooKeeper实现
- 分布式实现原理
- 实现分布式锁
- SOFAJRaft 实现原理:SOFAJRaft-RheaKV 分布式锁实现剖析
- RedLock 实现分布式锁
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
HTTP Essentials
Stephen A. Thomas、Stephen Thomas / Wiley / 2001-03-08 / USD 34.99
The first complete reference guide to the essential Web protocol As applications and services converge and Web technologies not only assume HTTP but require developers to manipulate it, it is be......一起来看看 《HTTP Essentials》 这本书的介绍吧!