2.1 通用命令

  因为通用命令会涉及Redis的数据结构操作,而Redis的数据结构操作也会涉及到通用命令,所以这两部分要结合着看。

  不同数据结构的操作内容在下面

1. KEYS

通用命令 KEYS pattern(pattern 为正则表达式)
功能描述 查找所有符合给定模式 pattern 的 key
时间复杂度 O(N),N 为数据库中 key 的数量。

  功能描述方面举例:

  • KEYS * 匹配数据库中所有 key 。
  • KEYS h?llo 匹配 hello,hallo 和 hxllo 等。
  • KEYS h*llo 匹配 hllo 和 heeeeello 等。
  • KEYS h[ae]llo 匹配 hello 和 hallo ,但不匹配 hillo 。

  特殊符号用 \ 隔开。

  示例:

redis> MSET one 1 two 2 three 3 four 4  # 一次设置 4 个 key
OK

redis> KEYS *o*
1) "four"
2) "two"
3) "one"

redis> KEYS t??
1) "two"

redis> KEYS t[w]*
1) "two"

redis> KEYS *  # 匹配数据库内所有 key
1) "four"
2) "three"
3) "two"
4) "one"

  在生产环境中,使用keys命令取出所有key并没有什么意义,而且Redis是单线程应用,如果Redis中存的key很多,使用keys命令会阻塞其他命令执行,所以keys命令一般不在生产环境中使用

2. DBSIZE

通用命令 DBSIZE
功能描述 返回当前数据库的 key 的数量
时间复杂度 时间复杂度: O(1)

示例

redis> DBSIZE
(integer) 5

redis> SET new_key "hello_moto"     # 增加一个 key 试试
OK

redis> DBSIZE
(integer) 6

  Redis内置一个计数器,可以实时更新Redis中key的总数,因此dbsize的时间复杂度为O(1),可以在线上使用。

3. EXISTS

通用命令 EXISTS key
功能描述 检查给定 key 是否存在。若 key 存在,返回 1 ,否则返回 0
时间复杂度 O(1)
redis> SET db "redis"
OK

redis> EXISTS db
(integer) 1

redis> DEL db
(integer) 1

redis> EXISTS db
(integer) 0

4. DEL

通用命令 DEL key [key …]
功能描述 删除给定的一个或多个 key 。不存在的 key 会被忽略。返回值是被删除 key 的数量
时间复杂度 O(N), N 为被删除的 key 的数量,其中删除单个字符串类型的 key ,时间复杂度为O(1);删除单个列表、集合、有序集合或哈希表类型的 key ,时间复杂度为O(M), M 为以上数据结构内的元素数量
#  删除单个 key
redis> SET name huangz
OK

redis> DEL name
(integer) 1


# 删除一个不存在的 key
redis> EXISTS phone
(integer) 0

redis> DEL phone # 失败,没有 key 被删除
(integer) 0


# 同时删除多个 key
redis> SET name "redis"
OK

redis> SET type "key-value store"
OK

redis> SET website "redis.com"
OK

redis> DEL name type website
(integer) 3

5. EXPIRE

通用命令 EXPIRE key seconds
功能描述 为给定 key 设置生存时间,当 key 过期时(生存时间为 0 ),它会被自动删除。设置成功返回 1 。 当 key 不存在或者不能为 key 设置生存时间时(比如在低于 2.1.3 版本的 Redis 中你尝试更新 key 的生存时间),返回 0
时间复杂度 O(1)
redis> SET cache_page "www.google.com"
OK

redis> EXPIRE cache_page 30  # 设置过期时间为 30 秒
(integer) 1

redis> TTL cache_page    # 查看剩余生存时间
(integer) 23

redis> EXPIRE cache_page 30000   # 更新过期时间
(integer) 1

redis> TTL cache_page
(integer) 29996

6. TTL

通用命令 TTL key
功能描述 以秒为单位,返回给定 key 的剩余生存时间(TTL, time to live)
时间复杂度 O(1)
redis> FLUSHDB
OK

redis> TTL key
(integer) -2

# key 存在,但没有设置剩余生存时间
redis> SET key value
OK

redis> TTL key
(integer) -1

# 有剩余生存时间的 key
redis> EXPIRE key 10086
(integer) 1

redis> TTL key
(integer) 10084

7. PERSIST

通用命令 PERSIST key
功能描述 移除给定 key 的生存时间,将这个 key 从“易失的”(带生存时间 key )转换成“持久的”(一个不带生存时间、永不过期的 key )。当生存时间移除成功时,返回 1 . 如果 key 不存在或 key 没有设置生存时间,返回 0
时间复杂度 O(1)
redis> SET mykey "Hello"
OK

redis> EXPIRE mykey 10  # 为 key 设置生存时间
(integer) 1

redis> TTL mykey
(integer) 10

redis> PERSIST mykey    # 移除 key 的生存时间
(integer) 1

redis> TTL mykey
(integer) -1

8. TYPE

通用命令 TYPE key
功能描述 返回 key 所储存的值的类型
时间复杂度 O(1)

值的类型有:

  • none (key不存在)
  • string (字符串)
  • list (列表)
  • set (集合)
  • zset (有序集)
  • hash (哈希表)
  • stream (流)
# 字符串
redis> SET weather "sunny"
OK

redis> TYPE weather
string

# 列表
redis> LPUSH book_list "programming in scala"
(integer) 1

redis> TYPE book_list
list

# 集合
redis> SADD pat "dog"
(integer) 1

redis> TYPE pat
set

9. Del

通用命令 DEL key [key …]
功能描述 删除给定的一个或多个 key 。不存在的 key 会被忽略。返回值是被删除 key 的数量
时间复杂度 O(N), N 为被删除的 key 的数量,其中删除单个字符串类型的 key ,时间复杂度为O(1);删除单个列表、集合、有序集合或哈希表类型的 key ,时间复杂度为O(M), M 为以上数据结构内的元素数量
#  删除单个 key
redis> SET name huangz
OK

redis> DEL name
(integer) 1

# 删除一个不存在的 key
redis> EXISTS phone
(integer) 0

redis> DEL phone # 失败,没有 key 被删除
(integer) 0


# 同时删除多个 key
redis> SET name "redis"
OK

redis> SET type "key-value store"
OK

redis> SET website "redis.com"
OK

redis> DEL name type website
(integer) 3

10. scan

通用命令 SCAN cursor [MATCH pattern] [LIMT count]
功能描述 查找(limit个)(符合给定模式 pattern )的 key ,返回值是符合 条件的key
时间复杂度 增量式迭代命令每次执行的复杂度为 O(1) ,对数据集进行一次完整迭代的复杂度为 O(N),其中 N 为数据集中的元素数量
  刚开始我们已经介绍过了keys,它的缺点非常明显:
  • ⼀次性查出所有满⾜条件的 key,万⼀Redis中有⼏百万个key 满⾜条件,满屏都是输出的结果,眼花缭乱。
  • keys由于走的是遍历算法,复杂度是 O(n),如果Redis中有千万级以上的key,这个指令就会导致 Redis 服务卡顿,所有读写Redis 的其它的指令都会被延后甚⾄会超时报错,因为 Redis是单线程程序,顺序执⾏所有指令,其它指令必须等到当前的keys 指令执⾏完了才可以继续。

  为了解决这个问题,2.8 版本中的Redis加⼊了scan。

  scan 相⽐ keys 具备有以下特点:

  • 复杂度虽然也是 O(n),但是它是通过游标(cursor,相当于位置)分步进⾏的,不会阻塞线程;
  • 提供 limit 参数(可选),可以控制每次返回结果的最⼤条数(实际上是遍历的key的数量);
  • 它也提供模式匹配功能;
  • 服务器不需要为游标(cursor)保存状态,游标(cursor)的唯⼀状态就是 - scan 返回给客户端的游标整数;
  • 返回的结果可能会有重复,需要客户端去重复(重要);
  • 遍历的过程中如果有数据修改,改动后的数据能不能遍历到是不确定的;
  • 单次返回的结果是空的并不意味着遍历结束,⽽要看返回的游标值是否为零;

  scan 参数提供了三个参数,第⼀个是 cursor 整数值,第⼆个是key 的正则模式,第三个是遍历的limit。第⼀次遍历时,cursor 值为 0,然后将返回结果中第⼀个整数值作为下⼀次遍历的cursor。⼀直遍历到返回的 cursor 值为 0 时结束。

127.0.0.1:6379> scan 0 match key99* count 1000
1) "13976"
2) 1) "key9911"
   2) "key9974"
   3) "key9994"
   4) "key9910"
   5) "key9907"
   6) "key9989"
   7) "key9971"
   8) "key99"
127.0.0.1:6379> scan 13976 match key99* count
1000
1) "1996"
2) 1) "key9982"
   2) "key9997" 
   3) "key9963"
   4) "key996"
   5) "key9912"
   6) "key9999"
   7) "key9921"
   8) "key994"
   9) "key9956"
   10) "key9919"
127.0.0.1:6379> scan 1996 match key99* count 1000
1) "12594"
2) 1) "key9939"
   2) "key9941"
   3) "key9967"
   4) "key9938"
   5) "key9906"
   6) "key999"
   7) "key9909"
   ...
127.0.0.1:6379> scan 11687 match key99* count
1000
1) "0"
2) 1) "key9969"
   2) "key998"
   3) "key9986"
   4) "key9968"
   5) "key9965"
   6) "key9990"
   7) "key9915"
   8) "key9928"
   9) "key9908"

  刚才也强调了,limit是遍历的key的个数,从上⾯的过程可以看到虽然提供的 limit 是 1000,但是返回的结果,有的只有10 个。

  scan 指令返回的游标就是第⼀维数组的位置索引,我们将这个位置索引称为槽 (slot)。如果不考虑字典的扩容缩容,直接按数组下标挨个遍历就⾏了。limit 参数就表示需要遍历的槽位数,之所以返回的结果可能多可能少,是因为不是所有的槽位上都会挂接链表,有些槽位可能是空的,还有些槽位上挂接的链表上的元素可能会有多个。每⼀次遍历都会将 limit 数量的槽位上挂接的所有链表元素进⾏模式匹配过滤后,⼀次性返回给客户端。

  scan除了可以遍历所有的key之外,还可以对指定的容器集合进⾏遍历。⽐如zscan遍历zset集合元素,hscan遍历hash字典的元素、sscan遍历set集合的元素。

  常用的通用命令已经介绍完了,下面我们探讨一个Redis总要面临的问题:在 Redis 中有可能会形成很⼤的对象,⽐如⼀个⼀个很⼤的 zset。

  这样的对象对Redis的集群数据迁移带来了挑战,在集群环境下,如果某个key太⼤,可能会导致数据迁移卡顿。另外在内存分配上,如果key太⼤,那么当它需要扩容时,会⼀次性申请更⼤的⼀块内存,这也可能会导致卡顿。如果这个⼤ key被删除,内存会⼀次性回收,卡顿现象也有可能再产⽣。

  在平时的开发中,尽量避免⼤key的产⽣。如果遇到Redis的内存⼤起⼤落的现象,有可能是因为⼤key导致的,这时候你就需要定位这个大key,进⼀步定位出具体的业务来源,然后再改进相关业务代码设计。

  关于大key的寻找,可以通过 scan 指令,对于扫描出来的每⼀个 key,使⽤ type 指令获得 key 的类型,然后使⽤相应数据结构的 size 或者 len ⽅法来得到它的⼤⼩,对于每⼀种类型,保留⼤⼩的前 N 名作为扫描结果展示出来。(需要编写脚本)

  除此之外,Redis官⽅在redis-cli指令中提供了这样的扫描功能

redis-cli -h 127.0.0.1 -p 7001 –-bigkeys

  如果你担⼼这个指令会⼤幅抬升 Redis 的 ops ,还可以增加⼀个休眠参数。

redis-cli -h 127.0.0.1 -p 7001 –-bigkeys -i 0.1
# 每隔 100 条 scan 指令就会休眠 0.1s,ops 就不会剧烈抬升,但是扫描的时间会变⻓。

redis中的OPS 即operation per second 每秒操作次数。意味着每秒对Redis的持久化操作

版权声明: 本文为智客工坊「沉晓」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

results matching ""

    No results matching ""