赞
踩
lua是一种轻量小巧的脚本语言,用标准C语言编写并以源代码形式开放, 其设计目的是为了嵌入应用 程序中,从而为应用程序提供灵活的扩展和定制功能。 Lua应用场景:游戏开发、独立应用脚本、Web应用脚本、扩展和数据库插件。
OpenRestry:一个可伸缩的基于Nginx的Web平台,是在nginx之上集成了lua模块的第三方服务器
OpenResty是一个通过Lua扩展Nginx实现的可伸缩的Web平台,内部集成了大量精良的Lua库、第三方 模块以及大多数的依赖项。 用于方便地搭建能够处理超高并发(日活千万级别)、扩展性极高的动态Web应用、Web服务和动态网关。 功能和nginx类似,就是由于支持lua动态脚本,所以更加灵活,可以实现鉴权、限流、分流、日志记 录、灰度发布等功能。 OpenResty通过Lua脚本扩展nginx功能,可提供负载均衡、请求路由、安全认证、服务鉴权、流量控 制与日志监控等服务。 类似的还有Kong(Api Gateway)、tengine(阿里)
从Redis2.6.0版本开始,通过内置的lua编译/解释器,可以使用EVAL命令对lua脚本进行求值。
脚本的命令是原子的,RedisServer在执行脚本命令中,不允许插入新的命令
脚本的命令可以复制,RedisServer在获得脚本后不执行,生成标识返回,Client根据标识就可以随时执行
通过执行redis的eval命令,可以运行一段lua脚本。
EVAL script numkeys key [key ...] arg [arg ...]
命令说明:
eval "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}" 2 key1 key2 first second
eval "return redis.call('set',KEYS[1],ARGV[1])" 1 n1 zhaoyun
EVAL 命令要求你在每次执行脚本的时候都发送一次脚本主体(script body)。
传送脚本主体并不是最佳选择。 为了减少带宽的消耗, Redis 实现了 EVALSHA 命令,它的作用和 EVAL 一样,都用于对脚本求值,但 它接受的第一个参数不是脚本,而是脚本的 SHA1 校验和(sum)
SCRIPT FLUSH :清除所有脚本缓存
SCRIPT EXISTS:根据给定的脚本校验和,检查指定的脚本是否存在于脚本缓存
SCRIPT LOAD: 将一个脚本装入脚本缓存,返回SHA1摘要,但并不立即运行它
192.168.24.131:6380> script load "return redis.call('set',KEYS[1],ARGV[1])"
"c686f316aaf1eb01d5a4de1b0b63cd233010e63d"
192.168.24.131:6380> evalsha c686f316aaf1eb01d5a4de1b0b63cd233010e63d 1 n2
zhangfei
OK
192.168.24.131:6380> get n2
SCRIPT KILL :杀死当前正在运行的脚本
https://redis.io/commands/eval/
使用redis-cli直接执行lua脚本。
test.lua
return redis.call('set',KEYS[1],ARGV[1])
./redis-cli -h 127.0.0.1 -p 6379 --eval test.lua name:6 , 'caocao' #,两边有空
list.lua
local key=KEYS[1]
local list=redis.call("lrange",key,0,-1);
return list;
./redis-cli --eval list.lua list
利用Redis整合Lua,主要是为了性能以及事务的原子性。因为redis帮我们提供的事务功能太差。
Redis 传播 Lua 脚本,在使用主从模式和开启AOF持久化的前提下:
当执行lua脚本时,Redis 服务器有两种模式:脚本传播模式和命令传播模式。
脚本传播模式是 Redis 复制脚本时默认使用的模式 Redis会将被执行的脚本及其参数复制到 AOF 文件以及从服务器里面。
执行以下命令:
eval "redis.call('set',KEYS[1],ARGV[1]);redis.call('set',KEYS[2],ARGV[2])" 2 n1 n2
zhaoyun1 zhaoyun2
那么主服务器将向从服务器发送完全相同的 eval 命令:
eval "redis.call('set',KEYS[1],ARGV[1]);redis.call('set',KEYS[2],ARGV[2])" 2 n1 n2
zhaoyun1 zhaoyun2
注意:在这一模式下执行的脚本不能有时间、内部状态、随机函数(spop)等。执行相同的脚本以及参数 必须产生相同的效果。在Redis5,也是处于同一个事务中。
处于命令传播模式的主服务器会将执行脚本产生的所有写命令用事务包裹起来,然后将事务复制到 AOF 文件以及从服务器里面。
因为命令传播模式复制的是写命令而不是脚本本身,所以即使脚本本身包含时间、内部状态、随机函数 等,主服务器给所有从服务器复制的写命令仍然是相同的。
为了开启命令传播模式,用户在使用脚本执行任何写操作之前,需要先在脚本里面调用以下函数:
redis.replicate_commands()
redis.replicate_commands() 只对调用该函数的脚本有效:在使用命令传播模式执行完当前脚本之后, 服务器将自动切换回默认的脚本传播模式。
如果我们在主服务器执行以下命令:
eval
"redis.replicate_commands();redis.call('set',KEYS[1],ARGV[1]);redis.call('set',KEYS[2],ARGV[2])" 2 n1 n2 zhaoyun11 zhaoyun22
那么主服务器将向从服务器复制以下命令:
EXEC *1 $5 MULTI *3 $3 set $2 n1 $9 zhaoyun11 *3 $3 set $2 n2 $9 zhaoyun22 *1 $4 EXEC
三者都可以批量执行命令
管道无原子性,命令都是独立的,属于无状态的操作
事务和脚本是有原子性的,其区别在于脚本可借助Lua语言可在服务器端存储的便利性定制和简化操作
脚本的原子性要强于事务,脚本执行期间,另外的客户端其它任何脚本或者命令都无法执行,脚本的执行时间应该尽量短,不能太耗时的脚本
但是测试环境的redis是单机版的,而线上服务器确是集群版。导致同样的代码在线上服务器一直报错,经过测试发现集群版lua脚本的使用并不同于单机版。
command keys must in same slot
为了保持事务,同一个lua脚本访问应该访问同一个slot,但是redis集群会根据KEY进行hash并取模,因此如果采用默认hash的话,那么就会产生下面的错误。
redis支持写法,可以实现对KEY的部分字符串进行hash,这样就能保证同一个lua脚本被同一个slot执行,从而保持事务的一致性。
如下图 三个key {top}_turnover_rate
,{top}_rank
,coin_{top}_coin
会按 crc16(top) % 16384 的方式取模
以上是关于lua在redis集群中的解决方案-- command keys must in same slot的主要内容
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。