概述
Redis是一个基于内存的k-v键值对数据库,底层使用C语言进行编写。
基础知识
- Redis是单线程进行工作。
redis 5.xx
一个worker工作线程,当有不同客户端的请求过来时,会串行的进行执行,每个请求有read,计算,write三个过程。如果是由两个客户端的请求,相当于会用6个时间片。
redis 6.xx
一个worker工作线程,当有不同的客户端请求过来时,比如客户端A和B,这时会创建两个IO子进程,每个IO子进程负责不同请求的read,然后在worker线程中进行串行的计算,再由子线程进行write。两个客户端的请求,相当于只会用4个时间片。
- Redis默认有16个(0 - 15)数据库,select (编号)可以选择数据库。
- Redis默认端口是 6379 。
数据类型
Redis的key都是string类型的。常见的命令:
get key // 获取对应key的value
keys * //查看当前数据所有的key
flushdb //清空当前数据库
flushall //清空所有数据库
expire key time //设置key的过期时间
type key //返回value的类型
value有以下5大数据类型
- String
字符串,最基础的数据类型。如:
set name jojo
get name // jojo
- Hash
类似于java中的map。如:
hset map name jojo
hget map name // jojo
hset map age 18
hkeys map //name, age
- list
列表,分为左插和右插,可以用作阻塞队列(lpush + brpop)。如:
lpush arr 1 // 1
lpush arr 2 // 2 1
rpush arr 5 // 2 1 5
rpush arr 6 // 2 1 5 6
llen arr // 4
lindex arr 0 // 2
- set
集合
sadd set jojo
sadd set pinkman
sadd set jennie
sadd set rice
smembers set // jojo pinkman jennie rice
srandmember set count //从集合中随机获取指定个数的元素
spop set count //从集合中移除指定个数的随机元素并返回
- zset
有序集合
zadd k1 2 v1
zadd k1 4 v2
zadd k1 3 v3
zrange k1 0 -1 // v1 v3 v2
持久化
RDB
在指定的时间间隔内将内存中的数据集快照写入磁盘。每次Redis启动时,都会自动读取dump.rdb文件。
默认有三种场景:
- 900 1 // 900秒有1个key发生改变
- 300 10 // 300秒有10个key发生改变
- 60 10000 // 60秒有10000个key发生改变
Redis会单独创建(fork)一个子进程来进行持久化,会先将数据写入到一个临时文件中,待持久化过程都结束了,再用这个临时文件替换上次持久化好的文件。整个过程中,主进程是不进行任何IO操作的,这就确保了极高的性能如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是非常敏感,那RDB方式要比AOF方式更加的高效。RDB的缺点是最后一次持久化后的数据可能丢失。
优势
- 适合大规模的数据恢复
- 对数据完整性和一致性要求不高
劣势
- 在一定间隔时间做一次备份,可能丢失最后一次快照后的所有修改
- Fork的时候,内存中的数据被克隆了一份,大致2倍的膨胀性需要考虑
AOF
以日志的形式来记录每个写操作,将Redis执行过的所有写指令记录下来(读操作不记录),只许追加文件但不可以改写文件,redis启动之初会读取该文件重新构建数据,换言之,redis重启的话就根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作。
三种场景:
- appendfsync always // 每次发生改变就追加
- appendfsync everysec // 每秒进行追加,可能丢失一秒的数据
- appendfsync no // 将持久化交给操作系统
优势
- appendfsync always: 每次发生数据变更会被立即记录到磁盘,性能较差但数据完整性比较好
- appendfsync everysec:每秒记录,可能丢失1秒的数据
劣势
- 相同数据集的数据而言aof文件要远大于rdb文件,恢复速度慢于rdb
- aof运行效率要慢于rdb
如果同时开启,Redis会读取aof文件
事物
可以一次执行多个命令,本质是一组命令的集合。一个事务中的所有命令都会序列化,按顺序地串行化执行而不会被其它命令插入,不许加塞,一个队列中,一次性、顺序性、排他性的执行一系列命令。
multi // 开启事物
exec // 执行事物里的所有操作
discard // 取消事物
watch key... //监视一个或多个key
unwatch //取消对key的watch
Watch指令
Watch指令,类似乐观锁,事务提交时,如果Key的值已被别的客户端改变,比如某个list已被别的客户端push/pop过了,整个事务队列都不会被执行。通过WATCH命令在事务执行之前监控了多个Keys,倘若在WATCH之后有任何Key的值发生了变化,EXEC命令执行的事务都将被放弃,同时返回Nullmulti-bulk应答以通知调用者事务执行失败。
发布和订阅
//客户端1订阅channel1频道
subscribe channel1
//客户端2在channel1频道发送消息
publish channel1 helloworld
//客户端会显示 channel1 helloworld的信息
缓存雪崩和缓存穿透
缓存雪崩
指在某段时间内大量的热点key失效,而导致请求直接到达后端数据库,造成后端数据库压力突然增大。或Redis宕机。
解决方案
- 搭建集群
- 对热点数据不设置过期时间
- 设置多级缓存
- 设置key的失效时间尽可能分散
缓存穿透
大量并发请求的数据(key)对应的数据在缓存和数据库中都不存在,导致尽管数据不存在但还是每次都会查询后端数据库,从而后端数据库增大。
解决方案
- 布隆过滤器
- 对空对象进行缓存