Redis面试题
安装步骤:
1、下载redis安装包,放到Linux的/opt文件夹下
2、解压、使用make命令编译文件(报错可百度查看这里)
3、然后到/usr/local/bin目录下可以看到redis的相关文件,启动命令:redis-server /opt/redis-3.2.9/myredis/redis.conf(即指定要使用的redis配置文件)
4、使用redis-cli -p 6379命令即可开始操作redis
5、使用SHUTDOWN命令退出控制台,然后exit
1、redis的数据类型
-
key的常用命令
keys *:查看所有的key
exists key:判断某个key是否存在
move key db:移动某个key到指定的库(切换库:select 1/2/3/4/……)
expire key 秒钟:为给定的key设置过期时间
ttl key:查看还有多少秒过期,-1表示永不过期,-2表示已过期
type key:查看key的类型
-
string(字符串,key-value模式)
1、可以包含任何数据类型,包括图片和序列化对象
2、value最大支持512MB
3、常用的命令
set/get/del/append/strlen
incr key:key的值+1
decr:key的值-1
incrby key 2:key的值每次+2
decrby key 2:key的值每次-2
getrange key 0 3:获取key的下标为0-3的值
setrange key 0 xxx:设置key的值,从key的0位开始
setex key 秒值:设置key的过期时间
setnx key value:只有当key不存在时才设置key为value
mset k1 v1 k2 v2 k3 v3:同时设置多个值
mget k1 k2 k3:同时获取多个值
-
list(列表)
1、底层实现是链表
2、常用的命令
lpush list01 1 2 3 4 5:创建list01的同时赋值为12345
lrange list01:0 -1:获取list01的所有值
lpop list01:从list的左边取一个值
-
set(集合)
1、无序集合,通过HashTable实现
2、常用命令
sadd set01 1 1 2 2 3 3:创建set01并赋值给1 2 3。相同的过滤掉
smembers set01:列出set01的值
scard set01:获取集合里面的元素个数
srandmembers set01 3;从set01中随机选出3个数
-
zset(有序集合)
-
hash (类似于java中的Map<String,<K,V>>)
1、KV模式不变,但是V是一个键值对
hset user id 11:设置初始值
hget user id:获取user的id
hmset customer id 11 name li4 age 22:设置初始值
hmget customer id name age:获取customer的id、name、age
hexists customer id:查看id在customer中是否存在
2、redis的持久化
-
RDB(Redis DataBase)
1、是什么?
在指定的时间间隔内将内存中的数据集快照写入磁盘,恢复时将快照文件读到内存
2、怎么实现的?
redis会单独创建一个子进程(fork)来进行持久化,会先将数据写入到一个临时 文件中,待持久化过程结束了,再用这个临时文件替换上次持久化好的文件。整个过程中,主进程不进行任何IO操作,这就保证了极高的性能
3、命令
save
save 120 10:如果两分钟以内修改了十次就执行RDB操作
4、如何恢复?
保存位置在config/dir下面,恢复时将备份文件(dump.rdb)移动到redis的安装目录并启动服务即可
5、优势和劣势
优势:适合大规模数据的数据恢复、对数据完整性要求不高
劣势:如果redis意外down掉的话,就会丢失最后一次快照后的所有修改、
-
AOF(Append Only File)
1、是什么?
以日志的形式记录每个写操作,将 redis执行过的所有写操作记录下来,只许追加文件,但不可改写文件,redis启动之初会读取该文件重新执行以恢复数据。
2、如何使用?
配置文件中修改配置:appendonly yes
保存的文件:appendfilename “appendonly.aof”
3、记录频率
appendsync Everysec:出厂默认推荐,每秒钟记录爱一次,如果一秒内宕机会有数据丢失
4、Rewrite机制
是什么?
AOF采用文件追加的方式,文件会越来越大,为避免出现这种情况,新增了重写机制,当AOF文件的大小超过设定的阈值时,redis就会启动AOF文件的压缩,只保留可以恢复数据的最小指令集。
重写原理?
触发机制?
redis会记录上次重写时AOF的大小,配置默认是当AOF的文件大小是上次rewrite后的一倍且文件大于64MB时
5、优势和劣势
优势:可以调整同步的频率、保证数据的完整性
劣势:AOF的文件要大于RDB文件,恢复速度慢于RDB
-
redis的事务
1、是什么?
可以一次执行多个命令,本质是一组命令的集合。一个事务中的所有命令都会序列化,按顺序串行执行而不会被其他命令插入。
2、能干嘛?
一个队列中,一次性、顺序性、排他性地执行一系列命令
3、常用命令
DISCARD:取消事务,放弃执行事务块内的所有命令
EXEC:执行所有事务块内的命令
MULTI:标记一个事务块的开始
UNWATCH:取消对所有key的监视
WATCH key:监视一个或多个key,如果在执行事务前这个key被其他名命令改动,那么事务将被打断
4、常见的情况
①正常执行
②放弃事务
③全体连坐(有一个错误的命令会导致后面所有的命令失效)
注意:这里出错的命令直接不能通过,没有加入事务的队列中去
④冤有头债有主(只有出错的命令不生效)
注意:这里出错的命令能够通过,加入事务的队列中去,但是提交事务之后会报错
⑤WATCH监控
通过WATCH命令在事务执行前监控多个key,倘若在 WATCH之后有任何key的值发生了变化,EXEX命令执行的事务都将被放弃,同时返回错误信息以通知调用者事务执行失败
⑥事务的三个阶段
开启:以MULTI开启一个事务
入队:将多个命令入队到事务中,接到这些命令并不会立即执行,而是放到等待执行的事务队列里面
执行:由EXEC命令触发事务
⑦三特性
单独的隔离操作:事务的所有命令都会序列化,按顺序执行,并且在执行过程中不会被打断
没有隔离级别的概念:队列中的命令没有提交之前都不会被实际地运行
不保证原子性:redis中如果有一条命令执行失败,其后的命令 仍然会被执行,没有回滚
3、发布订阅机制
4、主从复制机制
-
是什么
主机数据更新后根据配置和策略,自动同步到备份机器的master/slaver机制,Master以写为主,Slave以读为主
-
能干嘛
读写分离
容灾恢复
-
怎么用
步骤一:配置从库不配置主库
步骤二:从库配置 SLAVEOF 主库IP 主库端口号
例如:SLAVEOF 127.0.0.1 6379 表示备份本机的redis
步骤三:修改配置文件和细节操作
1、拷贝多个redis.conf文件
2、开启daemonize yes
3、修改PID文件名字
4、指定端口
5、修改logfile文件名字
6、修改dupm.rdb名字
步骤四:常用三招
1、一主二仆
一个主机一般配备两个备机,使用命令SLAVEOF 127.0.0.1 6379开启备份,开启之前的数据在备机上同样可以取到。备机不能设置值。主机宕机之后备机依然是备机,状态更新为down,当主机恢复之后,配置依旧。备机宕机之后,在宕机之间主机产生的数据,备机不存备份,当备机恢复之后角色会变成主机,除非将当前备机配置进主机的配置文件中。
2、薪火相传
上一个Slave可以是下一个Slave的master,Slave同样可以接收其他的Slave的连接和同步请求,那么该Slave作为了链条中的下一个master,可以有效减轻下一个master的写压力。如果中途变更转向,会清除之前的数据,重新建立拷贝最新的。
3、反客为主
主机宕机之后,其中的一台备机执行SLAVEOF NO ONE命令转换为主机,对数据的操作同样可以被另外一台主机感知。当宕机的主机恢复之后,其备机就不复存在了。
-
哨兵模式
1、是什么
反客为主的自动版,能够监控主机是否故障,如果故障了根据投票数重新选择新的主机
2、怎么用
增加配置文件sentinel.conf,文件内容写
sentinel monitor 被监控数据库名字(就是主机,名字自己起) IP 端口 1
代表的含义:监控主机,如果主机挂了会根据票数多少重新选择新的主机,当原来的主机恢复之后,会变成新主机的备机。
5、热点数据
当Redis的使用内存超过设置的最大内存时,会触发Redis的key淘汰机制确保缓存数据都是热点数据,一般的剔除策略有 FIFO 淘汰最早数据、LRU 剔除最近最少使用、和 LFU 剔除最近使用频率最低的数据几种策略。
-
noeviction :不删除策略。当达到最大内存限制时,如果需要使用更多内存,则直接返回错误信息(redis默认淘汰策略
-
allkeys-lru:在所有key中优先删除最近最少使用(less recently used,LRU)的key。
-
allkeys-random:在所有key中随机删除一部分key。
-
volatile-lru: 在设置了超时时间(expire)的key中优先删除最近最少使用的key
-
volatile-random:在设置了超时时间的key中随机删除一部分key
-
volatile-ttl: 在设置了超时时间的key中优先删除剩余时间(time to live,TTL)的key
6、内存穿透和雪崩
-
内存穿透:缓存穿透是指查询一个一定不存在的数据,由于缓存是不命中时需要从数据库查询,查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到数据库去查询,造成缓存穿透。
解决办法:最简单粗暴的方法如果一个查询返回的数据为空(不管是数据不存在,还是系统故障),我们就把这个空结果进行缓存,但它的过期时间会很短,最长不超过五分钟。
-
内存击穿:缓存击穿是指缓存中没有但数据库中有的数据(一般是缓存时间到期),这时由于并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大压力。
解决办法:最简单粗暴的方法是设置热点数据永不过期
-
缓存雪崩:如果缓存集中在一段时间内失效,发生大量的缓存穿透,所有的查询都落在数据库上,造成了缓存雪崩。
解决办法:设置数据的过期时间为随机,避免同一时间大量数据过期现象的发生
7、Redis为什么是单线程的?
因为Redis是基于内存的操作,单线程去操作内存效率就是最高的,因为多线程就是CPU模拟出来多个线程的情况,这种情况会有一个上下文切换的代价。Redis用单个CPU绑定一块内存的区域,然后针对这块内存的操作都是在一个CPU上完成的,所以他就是单线程处理这个事。CPU不是Redis的瓶颈,Redis的瓶颈最有可能是内存或者带宽,既然单线程容易实现,而且CPU又不会成为瓶颈,所以就采用单线程的方案了。
8、Redis为什么这么快?
- 完全基于内存的操作
- 数据结构简单,Redis中的数据结构是专门设计的,对数据的操作也简单
- 采用单线程,避免了不必要的上下文切换和竞争条件
- 使用多路I/O复用模型,非阻塞IO
9、缓存更新方式
缓存的数据在数据源发生变更时需要对缓存进行更新,数据源可能是 DB,也可能是远程服务。更新的方式可以是主动更新。数据源是 DB 时,可以在更新完 DB 后就直接更新缓存。
当数据源不是 DB 而是其他远程服务,可能无法及时主动感知数据变更,这种情况下一般会选择对缓存数据设置失效期,也就是数据不一致的最大容忍时间。
10、数据不一致
缓存不一致产生的原因一般是主动更新失败,例如更新 DB 后,更新 Redis 因为网络原因请求超时;或者是异步更新失败导致。
解决的办法是,如果服务对耗时不是特别敏感可以增加重试;如果服务对耗时敏感可以通过异步补偿任务来处理失败的更新,或者短期的数据不一致不会影响业务,那么只要下次更新时可以成功,能保证最终一致性就可以。
参考:
https://github.com/AobingJava/JavaFamily