一.预备知识
1.基本全局命令
set key value 将key的值设置成value
get key 得到key的值
keys [pattern] 查看匹配pattern的所有key
比如h?llo匹配hallo,hbllo,hcllo……只要用一个符号将?代替即可
比如h*llo匹配hllo,heeeello……用0个1个或多个字符将*代替即可
比如h[ae]llo匹配hallo,hello只有这两个
比如h[a-e]llo匹配hallo,hbllo,hcllo,hdllo,hello这五个
比如h[^e]llo表示除e之外的字母都匹
那keys * 则可以获取到任何key
exists key [key……] 判断指定的key是否存在
返回值是存在的key的个数
这个命令的时间复杂度是O(1),因为Redis组织这些key-value键值对是按照hash表的方式来组织的,每次找一个key都是O(1),所以当key特别多时,时间复杂度就成了O(N),N指的是key的个数。
del key [key^] 删除指定的key
返回值是成功删除掉的key的个数
时间复杂度是O(1)。其实还是和exists一样,有几个key就是O几的时间复杂度
expire key seconds 为指定的key添加过期时间
ttl key 查看当前key剩余的时间
如上,过期时间的单位是秒级,当到期时ttl的返回值就是-2
expire的应用场景有很多:比如点外卖,优惠券在指定时间内有效;比如手机验证码的有效时间;比如分布式锁的实现,有多种实现方式,其中redis就是一种(所谓redis实现分布式锁,其实就是给redis加一个特殊的key-value,把它删了就是解锁),为了避免不能正确解锁的情况,redis就会给锁设置过期时间。
pexpire key也是设定过期时间,不过它的单位是毫秒
注意,当expire和pexpire后面的key不存在时,返回值就是0
ttl key 查看当前key剩余的时间
ttl获取指定key的过期时间,它的单位也是秒级,ttl即Time To Live
当没有关联过期时间时,它的返回值就是-1,当key不存在时,它的返回值就是-2
Redis的过期策略如何实现?
一个Redis中存在很多key,这些key中可能大部分都有过期时间,此时redis服务器咋知道那些key过期了?
redis的整体策略就是定期删除和惰性删除。惰性删除就是当key到期时,先不删,紧接着后面又访问到的时候redis就发现这个key过期了,再把它删了,同时返回nil;而上述过程也要结和定期删除,就是每次抽取一小部分key,看看有没有到期的,有的话就删了。(只取一小部分就能够保证这个抽取检查的过程足够快,防止redis线程阻塞)。
为啥对于定期删除的时间有明确规定?因为redis时单线程程序,它主要的任务(处理命令,扫描过期的key……)都是在一个线程中执行的,如果扫描key这个操作消耗的时间太多或这个操作太频繁,就会影响其他命令执行,就可能达到和keys*一样的效果.
虽然有了上述两种策略,但整体效果还是一般,仍然会有key没能及时删除。因此redis也提供了一系列内存淘汰策略(这个以后会讲到)
注意,redis没有使用定时器的策略来实现过期key的删除。但这里我们也简单复习一下定时器的实现
type key 查看指定key对应的value的数据类型
key不存在时返回null
lpush,sadd,hset等命令会在后面讲到
2.Redis数据结构及内部编码
Redis支持很多数据结构,指的是一个value可以是一些复杂的结构,然而它的这些键值对都是通过hash表的形式来组织的,而且key的类型只能是string类型。在redis官方文档上,列出了12中数据结构,如下,不过我们常用的就是5种:String,List,Set,Hash,Zset(有序集合).
通过 object encoding key 的命令可以查看指定key的内部编码方式
3.redis的单线程架构
redis只是用一个线程来处理所有的命令和请求,但不是说redis真的只有一个线程,其实它也有多个线程,只不过其他的线程都是在处理网络IO罢了。
假设有两个请求同时要求key自增,那么key最终的结果是加一还是加二呢?
首先回顾一下:在多线程中,自增操作存在线程安全问题,因为自增操作在cpu角度是分成三个指令执行的,它不是原子的,因此可能当两个线程(两个cpu核,共用同一个内存空间)同时要求key自增时,key只自增一次。
redis这里,两个请求同时要求key自增,这也相当于“并行”发起。但是redis服务器这里不会有线程安全问题。因为reids是单线程模型,而不是多线程,这两个请求看似是同时到达redis服务器,但最终还是得在队列里排队,一个一个进行。
redis能使用单线程模型很好的工作,主要是因为redis的核心业务逻辑都是短平快的,不太消耗cpu资源,不太吃多核cpu。
但这样的弊端就是:redis必须要特别小心,若某个操作占用时间特别长,那么就会阻塞其他命令的执行