目录
- 1.命令
- 1.最核心的两个命令
- 1.SET
- 2.GET
- 3.说明
- 2.基本全局命令
- 0.前言
- 1.KEYS
- 2.EXISTS
- 3.DEL
- 4.EXPIRE
- 5.TTL
- 6.TYPE
- 2.数据结构和内部编码
- 3.单线程架构
- 1.单线程模型
- 2.单线程还效率高?(重点)
- 3.注意
1.命令
1.最核心的两个命令
1.SET
- 语法:
SET key value
- 功能:设置
key
以保存字符串value
- 如果
key
已持有一个值,则无论其类型如何,它都会被覆盖 - 在成功的
SET
操作中,将与密钥关联的任何先前生存时间都被丢弃
- 如果
2.GET
- 语法:
GET key
- 功能:获取
key
的值- 如果键不存在,则返回特殊值
nil
-> 和NULL
一个意思 - 如果存储在
key
处的值不是字符串,则返回错误,因为GET
仅处理字符串值
- 如果键不存在,则返回特殊值
3.说明
- Redis中,命令是不区分大小写的
- 上述的
Key
和Value
,不需要加上引号,就是字符串类型- 如果加上引号(单双引号都行),也没问题
2.基本全局命令
0.前言
- Redis的命令有上百个,如果纯靠死记硬背⽐较困难,但是如果理解Redis的⼀些机制,会发现这 些命令有很强的通⽤性
- Redis不是万⾦油,有些数据结构和命令必须在特定场景下使⽤,⼀旦使⽤不当可能对Redis本⾝ 或者应⽤本⾝造成致命伤害
1.KEYS
- 语法:
KEYS pattern
- 功能:返回满足所有样式(
pattern
)的key
- 支持的通配符样式如下:
?
:匹配一个字符*
:匹配任意多个字符[ab]
:只能匹配括号内的字符,此处为只能匹配a b[^a]
:排除括号内的字符,此处为只有a匹配不了,其他都能匹配[a-b]
:匹配a - b这个范围内的字符,包含两侧边界
- 返回值:匹配
pattern
的所有key
- 注意:时间复杂度
O
(
N
)
O(N)
O(N),在生产环境上,一般都会禁用
KEYS
命令,尤其是KEYS *
- 生产环境上的
key
可能会非常多,而Redis是一个单线程服务器,执行KEYS *
的时间非常长,就会使Redis服务器被阻塞,无法给其他客户端提供服务 - 此时其他的查询Redis操作超时了,就直接会去查数据库,突然一大波数据突然来了,MySQL可能措手不及,就直接挂了
- 生产环境上的
2.EXISTS
- 语法:
EXISTS key [key...]
- 功能:判断某个
key
是否存在 - 返回值:
key
存在的个数- 针对多个
key
而言,是非常有用的
- 针对多个
- 时间复杂度: O ( 1 ) O(1) O(1)
EXISTS key1 key2
和分开写EXISTS key1
、EXISTS key2
有什么区别?- 分开的写法,会产生更多的轮次的网络通信
- 此时跟直接操作内存相比,效率比较低,成本比较高
3.DEL
- 语法:
DEL key [key...]
- 功能:删除指定的
key
- 返回值:删除掉的
key
的个数 - 时间复杂度: O ( 1 ) O(1) O(1)
- Redis 的删除操作没有像MySQL那样危险,但依然要小心
- Redis的主要应用场景是缓存,并且存的都是热点数据
- 如果只是误删了几个数据,一般来说,问题不大
- 但是如果一下误删了一大半,此时影响还是会很大,因为Redis本是帮MySQL负重前行,但此时Redis没数据了,大部分的请求就直接打给MySQL了,此时就很容器把MySQL搞挂
- 相比之下,如果是MySQL这样的数据,哪怕误删一个,问题都可能很大
- Redis如果作为数据库,那误删的数据影响就肯定很大了
- Redis如果作为消息队列,此时的影响,就要具体分析了
- Redis的主要应用场景是缓存,并且存的都是热点数据
4.EXPIRE
- 语法:
EXPIRE key seconds
- 功能:为指定的
key
添加秒级的过期时间(Time To Live TTL)- 毫秒单位版本:
PEXPIRE
- 毫秒单位版本:
- 返回值:1表⽰设置成功,0表⽰设置失败
- 时间复杂度: O ( 1 ) O(1) O(1)
5.TTL
- 语法:
TTL key
- 功能:获取指定
key
的过期时间,秒级- 毫秒单位版本:
PTTL
- 毫秒单位版本:
- 返回值:剩余过期时间,-1表⽰没有关联过期时间,-2表⽰
key
不存在 - 时间复杂度: O ( 1 ) O(1) O(1)
- 键过期机制:定期删除 + 惰性删除 + 内存淘汰策略
- 惰性删除:一个
key
已经过期,但是暂时还没删除,此时key
还存在,后面来了一个访问,正好用到了这个key
,此时该访问就会让Redis服务器触发删除key
的操作 - 定期删除:每次抽取一部分,进行验证过期时间,保证这个抽取检查的过程足够快
- 因为Redis是单线程程序,如果扫描过期
key
消耗的时间太多了,会导致其他正常处理请求命令被阻塞
- 因为Redis是单线程程序,如果扫描过期
- 惰性删除:一个
6.TYPE
- 语法:
TYPE key
- 功能:返回
key
对应的value
的数据类型 - 返回值:
none, string, list, set, zset, hash, stream
- 时间复杂度: O ( 1 ) O(1) O(1)
2.数据结构和内部编码
-
TYPE
命令实际返回的就是当前键的数据结构类型,但这些只是Redis对外的数据结构 -
实际上Redis针对每种数据结构都有⾃⼰的底层内部编码实现,⽽且是多种实现,这样Redis会在合适的场景选择合适的内部编码
-
可以通过
object encoding key
来查看对应的value
的实际编码方式 -
Redis这样设计的好处:
- 可以改进内部编码,⽽对外的数据结构和命令没有任何影响,这样⼀旦开发出更优秀的内部编码, ⽆需改动外部数据结构和命令
- 例如:Redis3.2提供了
quicklist
,结合了ziplist
和linkedlist
两者的优势,为列表类型提供了⼀种更为优秀的内部编码实现,⽽对⽤⼾来说基本⽆感知
- 例如:Redis3.2提供了
- 多种内部编码实现可以在不同场景下发挥各⾃的优势
- 例如:
ziplist
⽐较节省内存,但是在列表元素⽐较多的情况下,性能会下降,这时候Redis会根据配置选项将列表类型的内部实现转换为linkedlist
,整个过程⽤⼾同样⽆感知
- 例如:
- 可以改进内部编码,⽽对外的数据结构和命令没有任何影响,这样⼀旦开发出更优秀的内部编码, ⽆需改动外部数据结构和命令
3.单线程架构
1.单线程模型
-
Redis只使用一个线程处理所有的请求,但并不代表Redis服务器进程内部真的就只有一个线程
- 事实上,Redis内部也有多个线程,多个线程都是在处理网络IO
-
Redis采⽤单线程模型执⾏命令的是指:虽然以下三个客⼾端看起来是同时要求Redis去执⾏命令的,但微观⻆度,这些命令还是采⽤线性⽅式去执⾏的,只是原则上命令的执⾏顺序是不确定的,但⼀定不会有两条命令被同步执⾏
-
感性理解:
- 虽然多个客户端是"并发"的发起了请求,但是Redis实际上处理请求时是单线程模型,保证了当前收到的多个请求,在Redis内部,依然是串行执行的
- 多个请求同时到达Redis服务器,也要先在队列中排队,再等待Redis服务器一个一个地取出里面的命令再执行
-
Redis采用单线程模型地原因:Redis核心业务逻辑都是短平快的,不太消耗CPU资源,也就不太吃多核
-
注意:正因为Redis是单线程模型,所以要特别小心,如果某个操作占用时间长,就会阻塞其他命令的执行
2.单线程还效率高?(重点)
- 首先明确,说Redis快,是以数据库为参照的,没有参照,单纯说快,就是耍流氓 😛
- Redis纯内存访问,数据库则是访问硬盘
- Redis核心功能,比数据库的核心功能简单
- 单线程模型,避免了一些不必要的线程竞争开销
- Redis每个基本操作,都是短平快的,简单操作一下内存,并不是很消耗CPU,即使搞了多线程,提升也不大
- 单线程可以简化数据结构和算法的实现,
- 处理网络IO地时候,使用了
epoll
这样的IO多路复用机制 --> 非阻塞IO
3.注意
- Redis有⼀个致命的问题:对于单个命令的执⾏时间都是有要求的
- 如果某个命令执⾏过⻓,会导致其他命令全部处于等待队列中,迟迟等不到响应,造成客⼾端的阻塞,对于Redis这种⾼性能的服务来说是⾮常严重的
- 所以Redis是⾯向快速执⾏场景的数据库