简介
Redis 从 2.6 版本开始引入应用 Lua 编程语言进行的服务器端脚本编程性能,这个性能能够让用户间接在 Redis 外部执行各种操作,从而达到简化代码并进步性能的作用。P248
在不编写 C 代码的状况下增加新性能 P248
通过应用 Lua 对 Redis 进行脚本编程,咱们能够防止一些减慢开发速度或者导致性能降落对常见陷阱。P248
将 Lua 脚本载入 Redis P249
SCRIPT LOAD
命令能够将脚本载入 Redis,这个命令承受一个字符串格局的 Lua 脚本为参数,它会把脚本存储起来期待之后应用,而后返回被存储脚本的 SHA1 校验和EVALSHA
命令能够调用之前存储的脚本,这个命令接管脚本的 SHA1 校验和以及脚本所需的全副参数EVAL
命令能够间接执行指定的脚本,这个命令接管脚本字符串以及脚本所需的全副参数。这个命令除了会执行脚本之外,还会将被执行的脚本缓存到 Redis 服务器外面
因为 Lua 的数据传入和传出限度,Lua 与 Redis 须要进行互相转换。因为脚本在返回各种不同类型的数据时可能会产生含糊不清的后果,所以咱们应该尽量显式的返回字符串。P250
咱们能够在 官网文档 中找到 Redis 和 Lua 不同类型之间的转换表:
Redis 类型转换至 Lua 类型
Redis | Lua |
---|---|
integer reply | number |
bulk reply | string |
multi bulk reply | table (may have other Redis data types nested) |
status reply | table with a single ok field containing the status |
error reply | table with a single err field containing the error |
Nil bulk reply | false boolean type |
Nil multi bulk reply | false boolean type |
Lua 类型转换至 Redis 类型
Lua | Redis |
---|---|
number | integer reply (the number is converted into an integer) |
string | bulk reply |
table (array) | multi bulk reply (truncated to the first nil inside the Lua array if any) |
table with a single ok field | status reply |
table with a single err field | error reply |
boolean false | Nil bulk reply |
boolean true | integer reply with value of 1 |
创立新的状态音讯 P251
- Lua 脚本跟单个 Redis 命令以及
MULTI
/EXEC
事务一样,都是原子操作 -
曾经对构造进行了批改的 Lua 脚本将无奈被中断
- 不执行任何写命令对只读脚本:能够在脚本对运行工夫超过
lua-time-limit
选项指定的工夫之后,执行SCRIPT KILL
命令杀死正在运行对脚本 - 有写命令的脚本:杀死脚本将导致 Redis 存储的数据进入一种不统一的状态。在这种状况下
- 不执行任何写命令对只读脚本:能够在脚本对运行工夫超过
应用 Lua 重写锁和信号量 P254
如果咱们当时不晓得哪些键会被读取和写入,那么就应该应用 WATCH
/MULTI
/EXEC
事务或者锁,而不是 Lua 脚本。因而,在脚本外面对未被记录到 KEYS
参数中的键进行读取或者写入,可能会在程序迁徙至 Redis 集群的时候呈现不兼容或者故障。P254
获取锁在目前已不须要应用 Lua 脚本实现,能够间接应用 SET
,并用 PX
和 NX
选项即可在键不存在的时候设置带过期工夫的值。开释锁时为了保障开释的时本人获取的锁,须要应用 Lua 脚本实现。相干代码已在 实现主动补全、分布式锁和计数信号量 中实现。
移除 WATCH
/MULTI
/EXEC
事务 P258
一般来说,如果只有少数几个客户端尝试对被 WATCH
命令监督对数据进行批改,那么事务通常能够在不产生显著抵触或重试的状况下实现。然而,如果操作须要进行好几次通信往返,或者操作发生冲突的概率较高,又或者网络提早较大,那么客户端可能须要重试很屡次能力实现操作。P258
应用 Lua 脚本代替事务不仅能够保障客户端尝试的执行都能够胜利,还能升高通信开销,大幅提高 TPS。同时因为 Lua 脚本没有屡次通信往返,所以执行速度也会显著快于细粒度锁的版本。
Lua 脚本能够提供微小的性能劣势,并且能在一些状况下大幅地简化代码,但运行在 Redis 外部但 Lua 脚本只能拜访位于 Lua 脚本之内或者 Redis 数据库之内的数据,而锁或者 WATCH
/MULTI
/EXEC
事务并没有这一限度。P263
应用 Lua 对列表进行分片 P263
分片列表的形成 P263
为了可能对分片列表的两端执行推入操作和弹出操作,在构建分片列表时除了须要存储组成列表的各个分片之外,还须要记录列表第一个分片的 ID 以及最初一个分片的 ID。当分片列表为空时,这两个字符串存储的分片 ID 将是雷同的。P263
组成分片列表的每个分片都会被命名为 <listname>:<shardid>
,并依照程序进行调配。具体来说,如果程序总是从左端弹出元素,并从右端推入元素,那么最初一个调配的索引就会逐步增大,并且新分片的 ID 也会变得越来越大。如果程序总是从右端弹出元素,并从左端推入元素,那么第一个分片的索引就会逐步缩小,并且新分片的 ID 也会变得越来越小。P264
当分片列表蕴含多个列表时,位于分片两端的列表可能是被填满的,但位于两端之间的其余列表总是被填满的。P264
将元素推入分片列表 P265
Lua 脚本依据命令 LPUSH
/RPUSH
找到列表的第一个分片或者最初一个分片,而后将元素推入分片对应的列表中,若分片已达个数下限(能够取配置中的 list-max-ziplist-entries
的值 – 1 作为下限),则会主动产生一个新的分片,持续推入,并更新第一个分片或者最初一个分片的分片 ID。当推入操作执行结束后,它会返回被推入元素的数量。P265
从分片外面弹出元素 P266
Lua 脚本依据命令 LPOP
/RPOP
找到列表的第一个分片或者最初一个分片,而后在分片非空的状况下,从分片外面弹出一个元素,如果列表在执行弹出操作之后不再蕴含任何元素,那么程序就对记录着列表两端分片信息的字符串键进行批改(留神只有列表端分片为空时才批改对应的字符串键,而整个列表为空时,不做调整)P267
对分片列表执行阻塞弹出操作 P267
这一段书上讲得看不懂,也不晓得为什么须要书中的花式操作能力实现。
集体感觉分片列表的阻塞弹出其实并不需要列表本身的阻塞弹出,咱们能够一直执行上述 Lua 脚本实现的弹出元素的操作,若弹出胜利,则间接返回,若弹出失败,则睡 1 ms 后继续执行弹出操作,直至弹出胜利或者达到超时工夫。这样咱们对 Redis 对操作只在 Lua 脚本中,原子性保障了肯定会弹出分片列表两端的元素。
本文首发于公众号:满赋诸机(点击查看原文)开源在 GitHub:reading-notes/redis-in-action