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 采用单线程的缘故, 它是没有采用定时器的方式来实现。
定时器是有两个比较经典的实现方式:优先级队列(堆)和 时间轮
优先级队列:
- 创建一个优先级队列,把它按照时间过期的顺序来排列,距离过期时间越近(时间戳越小),排越上面
- 为了防止忙等,会根据最上面的时间来阻塞等待
- 当添加新的内容的时候,判断一下时间戳是否小于之前的,如果小于,需要更新一下时间并阻塞等待
时间轮:
- 它会把时间划分为几部分,每部分的时间都存储一个链表,链表里面存储的就是一个个将要执行的任务
- 每隔一段时间,就会遍历执行一下相关区域的链表,看一下是否到了执行的时间
- 如果添加的任务的时间过大,那么就会采用类似 Hash 表这样的算法,把它分配到相关的区域内
为什么 Redis 单线程的情况下速度还快?
首先,需要明确的一件事情是快慢是相对的来说,而不是绝对的,要在条件一样的情况下经行比较,在前提条件不一样的情况下讨论这是没有意义的
- 相比与
MySQL,Redis是在内存中的,MySQL是在硬盘上的 Redis操作的功能更简单,不需要经行比较复杂的操作Redis不是CPU密集型的,因此使用单线程,减少了线程竞争的开销- 在网络开销上,
Redis采用了IO多路复用,在使用较小的资源的情况下可以有比较高的效率