Redis基础系列(七)——那些优化命令

447 阅读3分钟

这是我参与更文挑战的第19天,活动详情查看:更文挑战

字符串对象的批量获取命令

  获取字符串对象的命令有 get key,如果要获取 n 个健值,则要执行 n 次的 get key 命令,总时间消耗为 nget时间=n次命令执行时间+n次网络时间n 次get时间 = n次命令执行时间 + n次网络时间

n次get执行模型.png

  Redis可以支撑每秒数万次的读写操作,但是这里的读写操作是针对服务端的。对于客户端来说,每条命令,除了执行时间还有网络时间。由于执行命令时间在服务端已经优化到很高效,因此每条命令的网络时间成了更大的开销,对于开发人员来说,网络可能会成为性能的瓶颈。

  使用 mget key [key] 命令,可以批量获取健值,对于获取 n 个健值,时间消耗为 一次mget时间=n次命令执行时间+1次网络时间一次mget时间 = n次命令执行时间 + 1次网络时间。使用mget命令可以有效提高开发效率。

1次mget执行模型.png

  使用批量操作, 有助于提高业务处理效率, 但是要注意的是每次批量操作所发送的命令数不是无节制的, 如果数量过多可能造成Redis阻塞或者网络拥塞。

渐进式遍历命令

  在Redis中,使用keyshgetallsmemberszrange四个遍历型命令时,可能产生阻塞问题。从Redis 2.8 版本之后,提供 scanhscansscanzscan四个命令实现渐进式遍历。

scan命令

## scan命令
scan cursor [match pattern] [count number]
  • cursor是必需参数, 实际上cursor是一个游标, 第一次遍历从0开始, 每次scan遍历完都会返回当前游标的值, 直到游标值为0, 表示遍历结束。
  • match pattern是可选参数, 它的作用的是做模式的匹配, 这点和keys的模式匹配很像。
  • count number是可选参数, 它的作用是表明每次要遍历的键个数, 默认值是10, 此参数可以适当增大。

  和keys命令执行时会遍历所有键不同, scan采用渐进式遍历的方式来解决keys命令可能带来的阻塞问题, 每次scan命令的时间复杂度是O(1) , 但是要真正实现keys的功能, 需要执行多次scan。

  现有一个Redis有26个键(英文26个字母) , 现在要遍历所有的键, 使用scan命令效果的操作如下。 第一次执行scan 0, 返回结果分为两个部分: 第一个部分6就是下次scan需要的cursor, 第二个部分是10个键。

127.0.0.1:6379> scan 0
1) "6"
2) 1) "w"
2) "i"
3) "e"
4) "x"
5) "j"
6) "q"
7) "y"
8) "u"
9) "b"
10) "o"

使用新的cursor="6", 执行scan 6

127.0.0.1:6379> scan 6
1) "11"
2) 1) "h"
2) "n"
3) "m"
4) "t"
5) "c"
6) "d"
7) "g"
8) "p"
9) "z"
10) "a"

这次得到的cursor="11", 继续执行scan 11得到结果cursor变为0, 说明所有的键已经被遍历过了

127.0.0.1:6379> scan 11
1) "0"
2) 1) "s"
2) "f"
3) "r"
4) "v"
5) "k"
6) "l"

hscan、sscan、zscan命令

  这三个命令的使用方式与scan命令相类似。

  • hscan 面向哈希类型,用以解决hgetall命令可能发生的阻塞问题。
  • sscan 面向集合类型,用以解决smembers 命令可能发生的阻塞问题。
  • zscan 面向有序集合类型,用以解决zrange 命令可能发生的阻塞问题。

渐进式遍历命令的缺点

  渐进式遍历可以有效的解决keys等命令可能产生的阻塞问题, 但是渐进式遍历命令并非完美无瑕, 如果在遍历的过程中如果有键的变化(增加、 删除、 修改) ,那么遍历效果可能会碰到如下问题:

  • 新增的键可能没有遍历到,

  • 遍历出了重复的键等情况

    也就是说渐进式遍历命令并不能保证完整的遍历出来所有的键, 这些是我们在开发时需要考虑的。