文章目录
- 一、基础命令
- SET 和 GET
- 二、全局命令
- KEYS
- EXISTS
- DEL
- EXPIRE 和 TTL
- 经典面试题:Redis 中 key 的过期策略是怎么实现的
- TYPE
Redis 有许多种数据结构,但是这些数据结构的 key 的类型都是字符串类型的(所以说,Redis 不同的数据结构都是针对于 value 而言的)。正因如此,对应相同类型的 key 来说,就有一些通用的来操作 Redis 的命令。
一、基础命令
SET 和 GET
SET 和 GET 可以说是 Redis 中最基础也是最核心的两个命令了,Redis 是以键值对的形式来储存数据的,因此对于 Redis 中数据的存取就如同在操作一个哈希表一样。SET的作用就是 把 key 和 value 设置进 Redis,而 GET 则是通过 key 将 value 从 Redis 中取出。
例如下面的操作:
- 上述操作中,使用 SET 命令向 Redis 中添加了一个 key 为
key1
,value 为12345
和 key 为key2
,value 为hello
的两个键值对; - 然后再使用 GET key 这样的语法的命令获取到 key 对应的 value 值。
- 如果使用 GET 获取一个不存在的 key 对应的值则会返回
nil
(即相当于null)。
注意事项:
通过上述操作可以发现,在 Redis 中 key 和 value 其实都是字符串,但是不需要加上引号。当然如果想要加的话,单引号和双引号都可以。
二、全局命令
Redis 有许多种数据结构,但是这些数据结构的 key 的类型都是字符串类型的(所以说,Redis 不同的数据结构都是针对于 value 而言的)。正因如此,对应相同类型的 key 来说,就有一些全局通用的来操作 Redis 的命令。
KEYS
KEYS 命令的作用是用来查询当前 Redis 服务器上匹配的所有的 key 的,可以通过一些特殊的通配符来描述 key 的模式,然后就可以查询出 Redis 中所有匹配这个模式的 key 。
keys pattern
在 Redis 的官方文档中给出 KEYS 的模式类型如下:
a)?
符号的作用是匹配一个字符
例如:当 pattern 为 h?llo
的时候,就能匹配到如:hello
、hallo
、hxllo
这样的 key。
b)*
符号的作用是匹配 0 个或多个任意字符
例如:当 pattern 为 h*llo
的时候,就能匹配到如:hllo
、heeeello
这样的 key。
c)[ae]
符号的意思只匹配 a 或 e 这样的
例如:当 pattern 为 h[ae]llo
的时候,就能匹配到 hallo
、hello
,但是不会匹配到 hillo
。
d)[^e]
符号的意思是匹配非 e 的
例如:当 pattern 为 h[^e]llo
的时候,就不会到 hello
,但能匹配到其他的如 hallo
、hbllo
这样的。
f)[a-b]
符号的意思是匹配 a ~ b 之间的
例如:当 pattern 为 h[a-e]llo
的时候,就能匹配到 hallo
、hello
这样的。
关于 KEYS 命令的注意事项:
在实际生产环境中,要谨慎使用命令
keys *
,因为这条命令会查询出当前 Redis 中储存的所有 key,其时间复杂度为 O(N)。如果使用了该命令,可能会造成一些严重的后果:
- 由于 Redis 是用单线程处理命令的,如果使用
keys *
命令的话,就可能导致 Redis 会执行很长时间,而在此期间无法为其他用户提供服务了。- Redis 常作为 MySQL 这样的数据库的挡箭牌(缓存),一旦因为
keys *
导致数据无法从 Redis 中获取(Redis 阻塞),累计的大量的其他请求超时后就会从数据库中去查询数据,此时 MySQL 这样的数据库可能就会措手不及了,非常有可能造成数据库崩溃。
EXISTS
exists 命令的作用是判断某个 key 是否存在。如果存在则返回 1, 不存在则返回 0。
其语法格式为:
exists key [key ...]
那么就意味着 exists 命令可以单独查询一个 key,也可以同时查询多个 key:
使用 EXISTS 命令的注意事项:
- Redis 查询某个 key 是否存在的时间复杂度是 O(1),因为 Redis 组织这些 key 是以哈希表这样的数据结构来组织的。
- 尽管 Redis 查询某个 key 是否存在的时间复杂度是 O(1),但是由于 Redis 是以单线程来处理命令的,并且 Redis 的客户端与服务器是通过网络进行通信的,因此同时查询多个 key 的效率比分开查询单个 key 时的效率要高得多。
DEL
DEL 命令的功能是删除指定的 key,删除成功返回 1,失败则返回 0。
使用语法:
del key [key ...]
和 EXISTS 命令一样,执行 DEL 命令的时间复杂度也是 O(1),可以单独删除一个 key,也可以同时删除多个 key,但注意应该同时删除多个 key 以避免影响 Redis 的性能。
EXPIRE 和 TTL
EXPIRE 命令的作用是为 key 指定一个秒级的过期时间,当然还有一个命令 PEXPIER,其指定的是毫秒级别的过期时间,当 key 过期之后则会删除这个 key。而 TTL 命令的作用是获取某个 key 剩余的过期时间,如果没有设置过期时间则返回 - 1,已经超时了则返回 - 2。
EXPIRE 的使用语法:
expire key seconds
TTL 的使用语法:
ttl key
使用例子:
经典面试题:Redis 中 key 的过期策略是怎么实现的
如下图所示,展示了 key 设置了超时时间然后到过期的整个过程:
在实际生成环境中,Redis 存在了大量的 key,并且大多数的 key 都是设置了超时时间的。对于 Redis 来说,内存空间是极其宝贵的资源,如果不及时清理过期的 key,就会浪费大量的内存空间。
那么如何清理这些随时会过期的 key 呢?
可能一拍脑门就会想到定时在所有的 key 里面去找出过期的 key 并清除,乍一看实现起来非常简单,但是别忘了,Redis 是使用多线程来处理任务的,如果以这样的方式去清理 key 的话,那么 Redis 的生命周期早就结束了。
实际上,简单来说 Redis 中 key 的过期策略是 定期删除与惰性删除
相结合:
1. 定期删除
定期删除是 Redis 中的一种主动过期检查机制。
Redis 定期地(默认每秒钟10次,可以在配置文件中进行调整)随机选择一些已设置过期时间的键,并检查它们的过期时间是否已到。如果键已经过期,Redis 会将其删除。
并且,Redis 会在每次执行定期删除操作时,随机选择一部分键进行检查和清理。这样做是为了分散定期删除操作对性能的影响,以免在某一刻集中删除大量过期键。
2. 惰性删除
惰性删除是 Redis 中的被动过期检查机制。
当客户端尝试读取一个键的值时,Redis 会首先检查该键的过期时间。如果键已经过期,Redis 不会返回它的值,而是立即将其删除。惰性删除确保了在键被访问时,如果已经过期,会立即删除。这降低了过期键在内存中积累的可能性。
综合使用这两种方法,Redis 实现了高效的键过期策略,但仍然可能存在一些过期键没有及时清理的情况,特别是在大量过期键堆积时。为了确保过期键的及时清理,还可以考虑以下方法:
-
设置适当的过期时间: 在配置文件中,为键设置合理的过期时间,以确保不会在内存中积累大量过期键。
-
使用内存淘汰策略: Redis 提供了不同的内存淘汰策略,如LRU(最近最少使用)、LFU(最不经常使用)等。通过选择适当的淘汰策略,可以在内存不足时主动删除一些键,包括过期键。
-
定期扫描和清理: 可以定期执行自定义脚本或任务来扫描和清理过期键。这样可以确保即使 Redis 主线程繁忙,也有一个独立的任务负责清理过期键。
-
使用 Redis 的 Pub/Sub 功能: 可以使用 Redis 的发布/订阅功能来实现一个过期键的监控系统。当键过期时,Redis 可以发布一个消息,然后订阅者可以处理这些消息来执行清理操作。
综合使用这些方法,可以确保 Redis 中的过期键得到及时清理,从而维护内存的稳定和性能。
TYPE
TYPE 命令的作用是返回指定 key 对应 value 的数据类型。
其语法为:
type key
例如: