一、脚本管理命令实现



### --- 使用redis-cli直接执行lua脚本。
~~~     test.lua

~~~     # 脚本文件
[root@hadoop bin]# vim test.lua
return redis.call('set',KEYS[1],ARGV[1])

~~~     # 执行脚本
[root@hadoop bin]# ./redis-cli -h 127.0.0.1 -p 6379 --eval test.lua name:6 , caocao   #最后一个逗号两边有空格
OK



### --- list.lua
~~~     利用Redis整合Lua,主要是为了性能以及事务的原子性。因为redis帮我们提供的事务功能太差。

[root@hadoop bin]# vim list.lua
local key=KEYS[1]
local list=redis.call("lrange",key,0,-1);
return list;

[root@hadoop bin]# ./redis-cli --eval list.lua list
(empty list or set)



二、脚本复制



### --- 脚本复制

~~~     Redis 传播 Lua 脚本,在使用主从模式和开启AOF持久化的前提下:
~~~     当执行lua脚本时,Redis 服务器有两种模式:脚本传播模式和命令传播模式。



### --- 脚本传播模式

~~~     脚本传播模式是 Redis 复制脚本时默认使用的模式
~~~     Redis会将被执行的脚本及其参数复制到 AOF 文件以及从服务器里面。



### --- 执行以下命令:

127.0.0.1:6379> eval "redis.call('set',KEYS[1],ARGV[1]);redis.call('set',KEYS[2],ARGV[2])" 2 n1  n2 zhaoyun1 zhaoyun2
(nil)



### --- 那么主服务器将向从服务器发送完全相同的 eval 命令:
~~~     # 注意:
~~~     在这一模式下执行的脚本不能有时间、内部状态、随机函数(spop)等。
~~~     执行相同的脚本以及参数必须产生相同的效果。在Redis5,也是处于同一个事务中。

127.0.0.1:6379> eval "redis.call('set',KEYS[1],ARGV[1]);redis.call('set',KEYS[2],ARGV[2])" 2 n1 n2 zhaoyun1 zhaoyun2
(nil)



### --- 命令传播模式
~~~     处于命令传播模式的主服务器会将执行脚本产生的所有写命令用事务包裹起来,然后将事务复制到 AOF文件以及从服务器里面。
~~~     因为命令传播模式复制的是写命令而不是脚本本身,所以即使脚本本身包含时间、内部状态、随机函数等,主服务器给所有从服务器复制的写命令仍然是相同的。
~~~     为了开启命令传播模式,用户在使用脚本执行任何写操作之前,需要先在脚本里面调用以下函数:

redis.replicate_commands()



~~~     # redis.replicate_commands()只对调用该函数的脚本有效:
~~~     在使用命令传播模式执行完当前脚本之后,服务器将自动切换回默认的脚本传播模式。
~~~     如果我们在主服务器执行以下命令:

127.0.0.1:6379> eval "redis.replicate_commands();redis.call('set',KEYS[1],ARGV[1]);redis.call('set',KEYS[2],ARGV[2])" 2 n1 n2 zhaoyun11 zhaoyun22
(nil)



### --- 那么主服务器将向从服务器复制以下命令:

EXEC
*1
$5
MULTI
*3
$3
set
$2
n1
$9
zhaoyun11
*3
$3
set
$2
n2
$9
zhaoyun22
*1
$4
EXEC



三、管道(pipeline),事务和脚本(lua)三者的区别



### --- 三者都可以批量执行命令

~~~     管道无原子性,命令都是独立的,属于无状态的操作
~~~     事务和脚本是有原子性的,
~~~     其区别在于脚本可借助Lua语言可在服务器端存储的便利性定制和简化操作脚本的原子性要强于事务,
~~~     脚本执行期间,另外的客户端 其它任何脚本或者命令都无法执行,
~~~     脚本的执行时间应该尽量短,不能太耗时的脚本