面试专题之——Redis

Redis的事务机制是怎么样的?

它本质是一组命令的集合

1、Redis的事务是基于队列实现的,开启事务后把事务中的命令添加到一个队列,然后依次执行。

2、它没有隔离级别的概念,在执行EXEC之前数据都放入队列缓存

3、Redis的事务不保证原子性,没有回滚,事务中任意命令执行失败其余命令都会继续执行

Redis为什么会这么快?

1、完全基于内存

2、数据结构简单

3、采用单线程,避免了上下文竞争,也不存在多线程切换导致消耗cpu,也不用考虑锁的问题

4、采用多路复用I/O模型

Redis如何查到一个想要的key?

使用scan方法迭代查询,千万别使用key *,因为数据很多会导致卡顿。

缓存雪崩、穿透、预热、降级

缓存雪崩

由于缓存过期,新的缓存还没添加,导致原本访问缓存的请求都去查询数据库,最终导致系统崩溃

解决方法:

1、分散过期时间

2、加锁,保证每次只有一个线程访问数据库,这样只有第一个线程查询了数据库,后面的请求都查询了缓存

缓存穿透

用户查询数据,数据库中没有,自然也无法添加缓存,导致每次都访问数据库

解决方法:

1、使用布隆过滤器,将所有可能存在的数据哈希存在足够大的bitmap中,一定不存在的数据可以直接拦截掉

2、直接在缓存中存放null

缓存击穿

大量并发访问某个数据,在这个缓存失效的瞬间就会导致大量请求击穿缓存

解决方法:

1、在访问key之前使用setnx设置一个临时的key,访问结束再删除

2、使用分布式锁,保证缓存穿透查询数据库时只有一个线程查询数据库

缓存预热思路

1、将高频数据提前存放至缓存中

2、手动模拟用户操作一下

缓存降级

当访问量剧增,服务出现问题时,为了防止因为Redis故障而导致数据库跟着雪崩,对于不重要的数据可以做降级处理,例如:Reids出现问题,不去查数据库,而是直接返回一个默认值

Memcache 与 Redis 的区别都有哪些?

1、Redis可以持久化,Memcache不能

2、Redis的数据类型更加丰富,Mencache只有简单的数据类型

3、Redis速度块很多

4、Redis的Value值可以达到512mb,而Mamcache只能达到1mb

Redis的数据类型有哪些?

String:文本类型

hash:类似一个双层map

list:列表,可以做一个简单的消息队列,列表左右都能进出

set:集合,但是里面的元素不能重复

sorted set:可排序的集合,它会有一个分数,根据这个分数进行排序,和set同样里面的元素不能重复。它可以用来做排行榜之类的

说说Redis的线程模型以及工作原理

Redis线程模型主要由以下组成:socket套接字、I/O多路复用程序、文件事件分派器、事件处理器

工作原理:

I/O多路复用程序监听多个套接字,并向文件事件分派器以队列的方式传送产生了事件的套接字。

然后文件事件分派器调用事件处理器处理当前套接字,处理完当前的套接字之后I/O多路复用程序才会传送下一个套接字给文件事件分派器

持久化机制

Redis持久化机制有哪些?

RDB:默认存储方式,它基于快照思想,当触发条件时将这一刻内存中的数据快照并保存到磁盘中,文件后缀名为.rdb

默认触发条件:

1、一个小时1个键以上被更改

2、5分钟100个键以上被更改

3、1分钟1万个键以上被更改

AOF:通过记录日志的方式进行持久化,每当对数据进行写操作,它都会记录当前的命令,当Redis重启后,通过读取AOF文件按照顺序执行命令即可恢复数据

save与bgsave的区别有哪些?

save:会阻塞Redis的服务进程,服务器不会执行任何命令,直到RDB快照完成

bgsave:不会阻塞Redis的服务进程,因为它会创建一个与主线程一样的子线程,创建这个子线程时是阻塞的,通过这个子线程来进行保存RDB快照,Redis保存快照时默认使用它

RDB与AOF两种持久化机制的优缺点有哪些?

RDB:

  • 优点:

    1、基于二进制文件完成数据备份,占用空间少,便于文件传输

    2、能够自定义触发备份规则

  • 缺点

    1、无法保证数据完整性,会丢失最后一次快照之后的所有数据

    2、每次bgsave创建子线程时都是阻塞的,频繁执行会影响系统性能

AOF:

  • 优点:

    1、数据安全性更高

    2、持久化时更加线性不会因为海量数据而造成系统性能严重下降,因为如果数据量非常大,RDB每次快照都是备份所有数据,容易造成系统性能严重下降

  • 缺点

    1、性能没有RDB好

AOF执行原理是怎么样的?

1、Redis接收到写命令

2、把接收到的命令添加到aof_buf缓存的末尾

3、将aof_buf缓存区的内容写入aof文件中

4、根据策略将AOF文件刷入磁盘

AOF的触发方式有哪些?

always:每次执行写入命令都会将aof_buf缓冲区文件写入到aof文件中,并且刷入磁盘。效率低,但安全性高

everysec:每次执行写入命令都会将aof_buf缓冲区文件写入到aof文件中,每隔1秒将aof文件刷入磁盘。兼备了效率与安全,最多只会丢不超过2秒的数据

no:每次执行写入命令都会将aof_buf缓冲区文件写入到aof文件中,但不对aof文件刷入磁盘,刷入磁盘的操作由系统来完成,默认是30秒一次。该方式最快,但最不安全。

什么是AOF重写优化?

随着长时间的运行,aof文件会占用大量空间,并且数据还原时间还长,为了解决这个问题,Redis提供了aof文件重写优化功能,当aof文件大小超过一定的值时,Redis会开启子线程创建一个新的aof文件替换老的,这个新的aof文件去除了冗余命令。默认大于64mb进行优化

高可用:主从复制

什么是主从复制,读写分离?

就是搭建一个Redis集群,分为主节点和从节点,主节点只负责写命令,从节点负责查命令

为什么要使用主从复制,读写分离?

因为单台服务器万一出问题就会导致整个系统崩溃或者持久化的数据丢失,搭建集群就能更好地提升高可用,数据安全性也能得到保障,并且可以通过负载均衡大大提高Redis的并发与吞吐量。然后在生产环境下,读请求是远远多于写请求的,读写分离可以更好的利用系统资源

主从复制结构是如何保证高可用的?

主节点宕机:从节点自动升级为主节点继续提供服务,这依赖哨兵模式,并且原先主节点重启后可以手动重新设置为主节点,但原先主节点宕机前还没同步到从节点的数据会丢失

从节点宕机:主节点自动同步数据到从节点上,没有影响

主从复制,读写分离下如何对持久化进行优化,以提升性能?

如果主节点和从节点都开启持久化的话,性能相对更低。我们可以在主节点关闭持久化,只在从节点开启持久化,因为主节点的数据始终要同步到从节点中的

主从复制,读写分离有哪些缺点?

因为所有的写操作都在主节点上,将数据同步到从节点上会有延迟,当从节点越来越多这个问题会更加严重

主从复制工作原理是什么样的?

  • 初始化阶段:全量复制

    1、从节点连接到主节点发送sync命令进行数据同步

    2、主节点收到sync命令后,开始执行bgsave生成RDB快照(默认超过60秒失败),并使用缓存区记录这之后的写命令

    3、RDB快照生成完毕之后,向所有从节点发送RDB快照文件,并缓冲区持续记录这之后的写命令

    4、从节点收到RDB文件之后,写入磁盘,并清空旧数据,最后载入RDB快照到内存中

    5、主节点发送完RDB快照之后便向从节点发送缓冲区中的写命令

    6、从节点完成对RDB快照的载入之后,接收来自主节点缓冲区中的写命令

  • 初始化完毕正常工作后:增量复制

    主节点发生写操作时,会把命令同步到从节点,从节点接收并执行收到的写命令

哨兵模式

为什么需要哨兵模式?

因为Redis集群中如果主节点宕机,就无法进行写操作,并且无法同步数据了。这时就需要哨兵选出一个新的主节点

什么是哨兵模式?

哨兵是一个分布式系统,它也是一台Redis服务器,只是不提供数据服务,它用于监控主节点服务器,当主节点发生故障,就通过投票的机制选出新的主节点,并让所有从节点连接这个主节点。

因为它采用投票机制选出新的主节点,所以哨兵集群中节点数量通常为单数

哨兵集群是通过什么方式互相发现的?

通过发布/订阅的方式组成哨兵集群,通过订阅主库频道sentinel_:hello来实现哨兵之间的互相发现,通过对主库发送info命令来发现从库

哨兵模式的投票机制是怎么样的?

哨兵会使用ping命令检测它和主节点的连接情况,如果响应超时了,就会先把它标记成“主观下线”,然后通过命令让其他哨兵节点都来判断该主节点是否下线,如果超过半数哨兵节点认为主节点下线,那么就把当前主节点标记为’’客观下线”,这时就又会通过投票机制来选取新的主节点

高可扩:Redis cluster分片集群

为什么要使用分片集群?

因为在使用一主二从三哨兵集群时,实际上每台机器存储的数据都是相同的,相当于同一份数据做了多个备份,如果遇到海量数据时,一台机器可能根本存储不了那么庞大的数据,这就需要使用分片集群了

什么是分片集群?

分片集群采用无中心化的思想,通过哈希槽来实现数据的分片,具体如何实现如下:

创建集群时把16384个哈希槽分配给每个主节点,在存取数据时获取数据键值对的key,通过CRC16算法计算当前key,得到一个16bit的值,再用这个值与16384取余得到相应的哈希槽编号,最后根据这个哈希槽编号定位到分片集群中相应的主节点上。

客户端如何定位数据?

在客户端与集群实例连接后,实例会把哈希槽分配信息发送给客户端,客户端会把这个信息缓存下来,在定位数据时就可以根据计算出的哈希槽编号找到相应的服务实列

key过期删除策略

Redis中,如果一个Key过期了,会直接删除吗?

不会直接删除,而是采用惰性删除 + 定期删除的方式

Redis中有哪些过期删除策略?

  • 定时删除:

    在设置过期时间的同时,创建一个定时器,过期了直接删除,这种方式对内存空间友好,但对cpu不友好,会拉低系统性能

  • 惰性删除:

    Redis不关注过期时间,而是再次用到这个键值对的时候查看它的过期时间,如果过期了就删除,这样对内存空间不友好,但对cpu很友好,会造成大量内存空间浪费

  • 定期删除:

    每秒扫描10次有过期时间的key,每次扫描随机取20个,删除这20个key中过期了的key,如果过期key占到25%则继续扫描

内存淘汰机制

noevction:不淘汰,内存满了直接报错

allkeys-lru:所有key中,删除最久没使用的key

allkeys-lfu:所有key中,删除最少使用的key

allkeys-random:所有key中,随机删除

volatile-lru:设置了过期时间的key中,删除最久没使用的key

volatile-lfu:设置了过期时间的key中,删除最少使用的key

volatile-ttl:设置了过期时间的key中,即将过期的key

volatile-random:设置了过期时间的key中,随机删除key