官方文档
redis的命令很多,一般可以在官方网站获取
redis命令

命令
redis中的命令不区分大小写。
get和set
set :用于存储一个键值对,这里的key和value不需要加上引号,表示的就是字符串,但如果需要加上单引号和双引号也可以。

get :用于通过key查询value,get后边输入key就可以获得value,如果get后输入了一个不存在的key就会返回nil,表示空的意思。

整体上来说,redis是键值对结构,key固定是字符串,而value可以是很多种数据结构,如字符串,哈希表,列表等等,操作不同的数据结构就有不同的命令,全局命令可以搭配任意一个数据结构来使用。
keys
keys命令返回所有满足样式的key。
- h?llo可以匹配hello,hallo和hxllo等等,?匹配的是任意一个字符。
- h*llo可以匹配heeeello和hllo等等,*匹配的是0个或任意多个字符。
- h[ae]llo可以匹配hello和hallo,但不匹配其他的命令,[xxx]可以匹配到方括号里的字母。
- h[^ae]llo可以匹配hpllo,hxllo等等,但不匹配hello和hallo,[ ^xxxx]只有xxxx匹配不了,其他均可以排除。
- h[a-b]llo可以匹配hallo和hbllo,里面指的是一个范围内的字符,是一个闭区间。
bash
keys pattern
exists
exists命令可以判断key是否存在,可以判断一个key是否存在,也可以判断多个key能否存在,时间复杂度为O(1),因为redis组织这些key就是按照哈希表组织的。
bash
exists key[key1 key2 ....]

del
可以删除指定的key,可以删除一个或者多个。
bash
del key[key1 key2 ....]

但redis删除数据并没有像MySQL那样严格,如果redis是作为缓存,其中的数据是热点数据,是在一直在更换的,所以误删数据影响不大,但如果redis作为数据库使用,存的是全量数据,那么误删数据影响就大了。
expire
expire用于给key设置过期时间,当指定的key存储时间超出了规定的时间,就会被删除,这里设置的时间单位是s。
bash
expire key seconds #单位是秒
pexpire key microsecond #单位是毫秒
此处设置过期时间,必须对一个存在的key进行设置,如果设置成功返回1,设置失败返回0。

ttl
bash
ttl key
如果key存在且有设置过期时间,那么会返回剩下的过期时间。
如果key存在但没有设置过期时间,就会返回-1。
如果key不存在,执行此命令的时候就会返回-2。

过期策略 :一个redis可能同时存在很多很多的key,这些key很大一部分都存在过期时间,此时,redis如果要知道key的过期情况,应该怎么做呢。
如果要删除这些过期的key,直接遍历key肯定是行不通的,所以redis中有两个策略,一个是定期删除,一个是惰性删除。
1.惰性删除:假设这个key已经到过期时间了,但暂时还存在服务器上,直到某一次突然查询这个key,redis会发现这个key已经过期,就把这个key给删除掉。
2.定期删除:定期删除是惰性删除的辅助机制,每隔一段时间看一下,抽取一部分key验证过期时间,如果过期了就删除,保证这个抽取检查的时间足够快。
为什么要保证检查时间足够快呢?因为redis是单线程的,执行命令是主要的任务,如果过期检查占据了太多的时间,导致执行命令的任务被阻塞,就有问题了。
3.定时器的实现方案(但redis其实没有采用此方案)
- 基于优先级队列实现的定时器:那我们要怎么实现检查过期key呢?可以引入一个优先级队列,每次只需要检查队首的元素是否过期即可,但我们也不需要检查的太频繁,可以根据队首元素的过期时间设置一个等待,等到时间到了之后,就唤醒这个线程,这样就可以节省cpu的开销。
那如果在检查的时间,突然来了一个新的任务呢?我们可以在新任务添加的时候,唤醒一下刚才阻塞的线程,重新检查一下队首元素,再根据时间重新调整等待时间即可。 - 基于时间轮实现的定时器:把时间划分成很多小段,有一个时间指针指向时间轮上的某一个格子,每一个格子中都挂着一串链表,每个链表都代表一个需要执行的任务,当指针走到某一个格子的时候,就把这个格子上链表的任务尝试执行了。
type
这个指令可以查看一个key对应的value的类型,时间复杂度为O(1)。
bash
type key

数据结构
string类型 :包含raw,int和embstr这几种内部编码,其中raw就是一个字符串,底层就是类似于C++里的char数组,而int用于一些计数的功能,当redis里的value就是一个整数的时候,redis会直接使用int来保存,embstr是针对短字符串进行的特殊优化,而程序员在使用的时候可能感受不到string类型的差异,因为redis在内部会根据当前的情况,自动适应的。
redis中的字符串直接就是按照二进制数据存储的,不会做任何的编码转换(插入的数据是UTF-8编码,取出来就是UTF-8编码,redis自身没有编码,所以出现乱码的概率更低),不仅仅可以存储文本数据,还可以存储整数,文本字符串,json,xml,二进制数据(图片,音频,视频等)。
hash类型 :包含hashtable和ziplist两种内部编码,其中hashtable里就是最基本的hash表,而在元素比较少的时候就优化为ziplist了,因为使用ziplist是压缩列表,可以节省空间,而由于元素比较少,所以遍历一遍用的时间也不慢。
list类型 :list包含linklist和ziplist两种内部编码,其中linklist就是我们平常使用的链表,而ziplist和刚才hash介绍的ziplist一样的,从redis3.2开始,就开始使用quicklist代替前面两种,quicklist就是一个链表,每一个链表的值都是一个ziplist,这样就在空间和时间上都可以兼顾到。
set类型 :set类型包含hashtable和intset,intset主要针对于,集合中都是整数的情况。
zset类型:zset类型包含skiplist和ziplist两种类型,skiplist就是跳表,跳表也是链表,但每个节点上有多个指针域,巧妙搭配这些指针域,就可以实现O(logN)的查询效率。
查看方式
bash
object encoding key
通过以上的命令可以查看key的编码方式。

单线程模型
redis只使用一个线程处理所有的命令请求,但并不代表redis服务器内部只有一个线程,redis服务器内部也存在多个线程,多个线程是用在处理网络IO。
redis是单线程模型,那么参照MySQL数据库来说,redis为什么这么快呢?
- redis访问的是内存,数据库则是访问硬盘。
- redis核心功能比MySQL简单,MySQL对于数据的删除查询,都有更复杂的功能支持,这样的功能势必要花费更多的开销。
- redis是单线程模型,因为redis的请求处理都是比较快的,所以多线程对于redis的性能提升不大,单线程避免了不必要的线程竞争开销。
- redis在底层采用了epoll模型处理网络IO。