欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Redis常见面试题

程序员文章站 2022-06-17 20:56:46
##1.什么是redis Redis 是一个基于内存的高性能key-value数据库。整个数据库统统加载在内存当中进行操作,定期通过异步操作把数据库数据flush到硬盘上进行保存。因为是纯内存操作,Redis的性能非常出色,每秒可以处理超过 10万次读写操作,是已知性能最快的Key-Value DB ......

1.什么是redis

redis 是一个基于内存的高性能key-value数据库。整个数据库统统加载在内存当中进行操作,定期通过异步操作把数据库数据flush到硬盘上进行保存。因为是纯内存操作,redis的性能非常出色,每秒可以处理超过 10万次读写操作,是已知性能最快的key-value db。

2.为什么用redis/为什么用缓存

(1)高性能
假如用户第一次访问数据库中某些数据,这个过程会比较慢,因为是从硬盘上读取的,将用户访问的数据存放在缓存中,这样下一次访问这些数据的时候就会直接从缓存中获取,操作缓存是直接操作内存,所以速度相当快,如果数据库中的数据对应的数据改变后,同步改变缓存中相应的数据即可。
(2)高并发
直接操作缓存能够承受的请求是远远大于直接访问数据库的,所以把数据库中的部分数据转移到缓存中去,这样用户的一部分请求会直接到缓存中而不会经过数据库。

3.redis支持数据类型

redis 有 5 种基础数据结构,分别为:string (字符串)、list (列表)、set (集合)、hash (哈希) 和 zset (有序集合)。
string字符串:
格式: set key value
string类型是二进制安全的。意思是redis的string可以包含任何数据。比如jpg图片或者序列化的对象 。
string类型是redis最基本的数据类型,一个键最大能存储512mb。

hash(哈希)
格式: hmset name  key1 value1 key2 value2
redis hash 是一个键值(key=>value)对集合。
redis hash是一个string类型的field和value的映射表,hash特别适合用于存储对象。

list(列表)
redis 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)
格式: lpush  name  value
在 key 对应 list 的头部添加字符串元素
格式: rpush  name  value
在 key 对应 list 的尾部添加字符串元素
格式: lrem name  index
key 对应 list 中删除 count 个和 value 相同的元素
格式: llen name  
返回 key 对应 list 的长度

set(集合)
格式: sadd  name  value
redis的set是string类型的无序集合。
集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是o(1)。

zset(sorted set:有序集合)
格式: zadd  name score value
redis zset 和 set 一样也是string类型元素的集合,且不允许重复的成员。
不同的是每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序。
zset的成员是唯一的,但分数(score)却可以重复。

4.什么是redis持久化?redis持久化有哪几种持久方式?优缺点是什么?

redis是基于内存操作的,内存断电即失,redis持久化就是把内存的数据写到磁盘中去,防止服务器宕机,内存数据丢失。redis持久化提供两个两种方式rdf(默认)和aof。
rdb:
redis把数据快照存放在磁盘上的二进制文件中,文件名为dump.rdb。你可以配置redis的持久化策略,例如数据集中每n秒钟有超过m次更新,就将数据写入磁盘;或者你可以手工调用命令save或bgsave。
当redis意外宕机,会丢失部分数据。
aof:
aof(append-only-file)持久化即记录所有变更数据库状态的指令,以append的形式追加保存到aof文件中。在服务器下次启动时,就可以通过载入和执行aof文件中保存的命令,来还原服务器关闭前的数据库状态。
对于相同的数据来说,aof文件大小通常要大于rdb文件。aof持久化以日志的形式记录服务器所处理的每一个写、删除操作,查询操作不会记录,以文本的方式记录,可以打开文件看到详细的操作记录。所以redis意外宕机,redis只会丢失最后一次数据。

5.什么是缓存穿透?如何避免?

一般的缓存系统,都是按照key去缓存查询,如果不存在对应的value,就应该去后端系统查找(比如db)。一些恶意的请求会故意查询不存在的key,请求量很大,就会对后端系统造成很大的压力。这就叫做缓存穿透。
如何避免?
1:对查询结果为空的情况也进行缓存,缓存时间设置短一点,或者该key对应的数据insert了之后清理缓存。
2:对一定不存在的key进行过滤。可以把所有的可能存在的key放到一个大的bitmap中,查询时通过该bitmap过滤。

6.什么是缓存击穿?如何避免

对于设置了过期时间的 key,缓存在某个时间点过期的时候,恰好这时间点对这个 key 有大量的并发请求过来,这些请求发现缓存过期一般都会从后端 db 加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把 db 压垮。
解决方案:
i.使用互斥锁:当缓存失效时,不立即去 load db,先使用如 redis 的 setnx 去设置一个互斥锁,当操作成功返回时再进行 load db 的操作并回设缓存,否则重试 get 缓存的方法。
同时保证对于每个key同时只有一个线程去查询后端,其他线程没有获得锁的权限,只需要等待即可。
ii 永远不过期:物理不过期,但逻辑过期(后台异步线程去刷新)。

7.什么是缓存雪崩?如何避免

设置缓存时采用了相同的过期时间,导致缓存在某一时刻同时失效,请求全部转发到 db, db 瞬时压力过重雪崩。与缓存击穿的区别:雪崩是很多 key,击穿是某一个key 缓存。
解决方案:
将缓存失效时间分散开,比如可以在原有的失效时间基础上增加一个随机值,比如 1-5 分钟随机,这样每一个缓存的过期时间的重复率就会降低,就很难引发集体失效的事件。

8.redis为什么单线程还这么快?

redis是将所有数据全部放在内存中的,所以说使用单线程去操作效率就是最高的。多线程会产生cpu上下文切换,将会是比较耗时的操作。对于内存系统来说,如果没有上下文切换效率就是最高的。

9、redis内存淘汰机制(mysql里有2000w数据,redis中只存20w的数据,如何保证redis中的数据都是热点数据)

redis 内存数据集大小上升到一定大小的时候,就会施行数据淘汰策略(回收策略)。redis 提供 6种数据淘汰策略:
volatile-lru:从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰
volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰
volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰
allkeys-lru:从数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰
allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰
no-enviction(驱逐):当内存数据不足以容纳新写入的数据时。新写入操作时就会报错。

10.redis主从复制

是指将一台redis服务器的数据,复制到其他的redis服务器。前者称为主节点(master/leader),后者称为从结点(slave/follower);数据的复制是单向的,只能由主节点到从结点。master以写为主,slave以读为主。

11.redis事务

redis事务的本质是一组命令的集合,一个事务中所有命令都会被序列化,在事务执行过程中,会按照顺序执行。
redis单条命令保证原子性,但是redis事务中不保证原子性,不并且redis事务没有隔离级别的概念。
redis事务命令:
开启事务(multi)
执行事务(exec)
放弃事务(discard)