Skip to content

01-通用命令 ​

查询命令最高效的方法就是去 官网文档 里面查找,因为官网是最权威的。像 AI, 第三方的中文文档可能会更新不及时/有错误的信息 之类的情况

通用命令 ​

get 和 set ​

这两个是 Redis 中最重要的命令。

  • set 是用来存放数据
  • get 是用来获取数据

它们的 key 和 value 类型都是字符串

keys ​

这个命令在生产环境上一般是禁止使用的,尤其是 keys * 这个命令。

因为这很可能会导致一系列问题:Redis 请求超时 - 请求 MySQL 数据 - MySQL 处理不了宕机了。所以只要在线上环境,那么就必须要打起 12 分精神,一定要清楚当前这个步骤会有什么样的后果

keys 是用来获取 key 的值,它有一下几个规则

  • ?: 匹配一个字符
  • \*: 匹配0个或多个字符
  • \[\]:
    • 前面有 ^ 那么就不会匹配区间内的字符
    • 前面没有 ^ 那么就会匹配区间内的字符

scan ​

scan 是渐进式遍历的一个命令,它是用来解决 keys 一次性全局遍历导致 Redis 卡住的问题。

  • count: 表示期望的返回 key 的个数,但是实际返回的个数可能会与 count 不一样
  • type: 类型,表示希望获取到的 key 的类型
  • pattern: 模板,它和 keys 的模板条件一样

exists ​

用来表示 key 是否存在,支持多个 key 一起

多个 key 是可以减少网络请求,从而减少网络开销,提高效率

del ​

删除数据。可以填写多个 key

这个命令危险吗?

  • 如果 Redis 仅仅存放热点数据,一般使用这个删除是关系不大的,因为 MySQL 里面是存放着相关的数据。(删除大量数据除外)
  • 但是如果 Redis 是存放全量数据,那么就有比较大的关系了,删除的时候一定要慎重
  • 如果 Redis 是作为消息队列,删除是要看具体的业务场景:如果涉及到金钱,那么就比较危险,如果是日常的系统通知,那危险性又不会那么高

ttl 和 expire ​

ttl(time to live) 表示存活时间,expire 是设置过期时间,它们一般是配合使用的。

expire 是一个很有用的功能,在许多场景都需要用这个功能

  • 验证码失效时间
  • JWT 令牌过期时间
  • 优惠券有效时间

type ​

type 是用来查询 key 对应的 value 的类型。

一般是在刚开始,不清楚 key 的对应的 value 的类型的时候使用的,因为不同类型的命令是差异很大的

面试题 ​

expire 过期是如何实现的呢? ​

Redis 是采用了定期删除、惰性删除和内存淘汰等策略

  • 定期删除:每隔一段时间,就删除一部分过期的 key。

    不能删除全部,因为 Redis 主要是使用单线程的,删除全部会执行类似 keys * 这样的命令,把整个 Redis 服务器卡住

  • 惰性删除:当获取到这个变量的时候,判断一下当前变量是否过期,如果过期,那么就删除,返回 nil
  • 内存淘汰:TODO

但是可能是由于 Redis 采用单线程的缘故, 它是没有采用定时器的方式来实现。

定时器是有两个比较经典的实现方式:优先级队列(堆)和 时间轮

  • 优先级队列:
    1. 创建一个优先级队列,把它按照时间过期的顺序来排列,距离过期时间越近(时间戳越小),排越上面
    2. 为了防止忙等,会根据最上面的时间来阻塞等待
    3. 当添加新的内容的时候,判断一下时间戳是否小于之前的,如果小于,需要更新一下时间并阻塞等待
  • 时间轮:
    1. 它会把时间划分为几部分,每部分的时间都存储一个链表,链表里面存储的就是一个个将要执行的任务
    2. 每隔一段时间,就会遍历执行一下相关区域的链表,看一下是否到了执行的时间
    3. 如果添加的任务的时间过大,那么就会采用类似 Hash 表这样的算法,把它分配到相关的区域内

为什么 Redis 单线程的情况下速度还快? ​

首先,需要明确的一件事情是快慢是相对的来说,而不是绝对的,要在条件一样的情况下经行比较,在前提条件不一样的情况下讨论这是没有意义的

  1. 相比与 MySQL,Redis 是在内存中的,MySQL 是在硬盘上的
  2. Redis 操作的功能更简单,不需要经行比较复杂的操作
  3. Redis 不是 CPU 密集型的,因此使用单线程,减少了线程竞争的开销
  4. 在网络开销上,Redis 采用了 IO 多路复用,在使用较小的资源的情况下可以有比较高的效率