> 文章列表 > redis 教程 6(Redis 的Pipeline , Lua)

redis 教程 6(Redis 的Pipeline , Lua)

redis 教程 6(Redis 的Pipeline , Lua)

Redis 的Pipeline, Lua

  • Pipeline
    • Pipeline简介
    • 为什么需要Pipeline
    • Pipeline 性能测试
    • 与原生批量命令对比
  • Lua
    • Lua 与事物
    • Lua 的用法
    • Redis 如何管理Lua脚本

Pipeline

Pipeline简介

Pipeline(流水线) 能够将一组redis命令进行组装, 通过一次RTT(Round Trip Time) 传输给redis, 然后再将这组命令的执行结果按照顺序返回给redis客户端

为什么需要Pipeline

下图为redis 客户端对redis的n次请求过程
redis 教程 6(Redis 的Pipeline , Lua)

注意: redis客户端执行一次命令分为四个步骤,

  • 发送命令
  • 命令排队
  • 命令执行
  • 返回结果
    整个过程称之为Round Trip Time (RTT, 往返时间), 那在redis的所有操作命令里面, 提供了很多批量的操作, 能够有效的节省RTT 时间, 但是像hgetall, 没有批量命令, 如果要执行n次的话, 那就跟上图一样, 会有n次的RTT消耗, 这个时候Pipeline就刚好改善了这个问题。

redis 教程 6(Redis 的Pipeline , Lua)

注意: 上图这个过程就是使用PIpeline针对redis客户端多次命令发送的优化过程,极大的减少了RTT。

Pipeline 性能测试

对于Pipeline是能够改善RTT, 但是性能到底如何, 我们来分析下, 假设我们有10000次set命令需要执行, 分别在没有Pipeline的情况下, 在有Pipeline的情况下, 对比使用的时间。

注意: 下表是在10000条set命令, 不通的网络情况下, 在不使用Pipeline, 和使用Pipeline的情况所耗时间, 从表可以很直观的看出, Pipeline的性能很强

网络 延迟 非Pipeline Pipeline
本级 0.17ms 573ms 134ms
内网服务器 0.41ms 1610ms 240ms
异地机房 7ms 78499ms 1104ms

与原生批量命令对比

Pipeline 的性能我们已经能够清楚, 那对于批量的redis命令有什么优缺点呢?

  1. 原生的批量命令是原子的, Pipeline是非原子的
  2. 原生批量命令是一个命令多个key, Pipeline是两次(来回)网络传输, 对应多个命令, 多个key
  3. 原生批量命令是redis服务端支持实现的, 而Pipeline需要服务端, 客户端共同配合实现。

注意: Pipeline的使用也要建立在调试的结果上, 不能一味的组装命令,

Lua

Pipeline可以组装多个redis命令, 但是是非原子性的, 是不安全的, 那如果即想组装命令, 又可以做到原子性呢? 这个时候Lua就出现了。
Lua 就是能够保证多条命令组合的原子性

Lua 与事物

Lua 保证了多条命令的组合是原子性的
事物, 即一批操作要么都执行成功, 要么都执行失败, 保证数据的一致性
redis 提供了multi 和exec 两个命令的组合, 在这两个命令之间的一组redis命令按照原子顺序执行, multi代表食物的开始, exec代表食物的结束。

multi
sadd user:a:follow  user:b
sadd user:b:fans user:a
// 这时命令并没有真整执行, 知识保存在redis里面
// 此时如果执行
sismember user:a:follow user:b 返回0
exec
返回1
再执行 sismember user:a:follow user:b 返回1

Lua 的用法

  1. eval

eval 脚本内容 key 个数 key 列表 参数列表

redis 127.0.0.1:6379> eval "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}" 2 key1 key2 key3 key4
1) "key1"
2) "key2"
3) "key3"
4) "key4"

redis 教程 6(Redis 的Pipeline , Lua)

  1. evalsha

evalsha 脚本 SHA1 值 key个数 key列表 参数列表
sha1 : 通过 SCRIPT LOAD 生成的 sha1 校验码。
numkeys: 用于指定键名参数的个数。
key [key …]: 从 EVAL 的第三个参数开始算起,表示在脚本中所用到的那些 Redis 键(key),这些键名参数可以在 Lua 中通过全局变量 KEYS 数组,用 1 为基址的形式访问( KEYS[1] , KEYS[2] ,以此类推)。
arg [arg …]: 附加参数,在 Lua 中通过全局变量 ARGV 数组访问,访问的形式和 KEYS 变量类似( ARGV[1] 、 ARGV[2] ,诸如此类)。

redis 127.0.0.1:6379> SCRIPT LOAD "return 'hello moto'"
"232fd51614574cf0867b83d384a5e898cfd24e5a"redis 127.0.0.1:6379> EVALSHA "232fd51614574cf0867b83d384a5e898cfd24e5a" 0
"hello moto"

redis 教程 6(Redis 的Pipeline , Lua)

  1. lua 的Redis Api

Lua 可以使用redis.call函数实现对Redis 的访问
redis.call(“set”, “hello”, “world”)
redis.call(“get”, “hello”)
在redis 的执行效果如下:

redis 127.0.0.1:6379> eval 'return redis.call("get", KEY[1])'  1 hello
"word"

Lua 还可以使用redis.pcall 函数实现对redis的调用, redis.call执行失败,脚本执行结束回返回错误, redis.pcall 会忽略错误继续执行。

Lua 可以用redis.log函数将Lua脚本的日志输出到redis 的日志文件中, 需要控制日志级别。

Redis 如何管理Lua脚本

  1. script load

script load 是将Lua脚本加载到Redis 内存中

  1. script exists

script exists sha1 {sha1 …}
判断sha1 是否已经加载到redis 内存中

  1. script flush

script flush
次命令用于清除Redis内存已经加载的所有Lua脚本

  1. script kill

script kill
杀掉正在执行的Lua脚本, 杀掉一些一直阻塞的lua脚本