1、谈下你对 Redis 的了解
Redis 是一个用 C 语言编写的、开源的 key-value 数据库
Redis 运行在内存中,所以处理数据的速度非常快,同时 Redis 还支持数据的持久化,将内存中的数据保存在磁盘
2、Redis适用于哪些场景?不适用于哪些场景?
适用的场景:
- 会话缓存:减轻后端sql数据库的IO压力,提升系统性能
- 排行榜:利用 sortset(有序集合)可以排序且不能有重复数据的特性来实现
- 消息队列:redis 支持生产者/消费者模式、发布者/订阅者模式的消息队列
不适用场景:
- 数据量太大的业务场景:内存成本大
- 数据访问频率非常低的业务场景:浪费内存资源
3、Redis 支持的数据类型有哪些?
- string(字符串)
字符串类型是redis最基础的数据结构,而且其他集中数据结构都是在字符串类型基础上构建的
- Hash(哈希)
Redis中哈希类型是指键本身是一种键值对结构
- List(列表)
列表(list)类型是用来存储多个有序的字符串,是一种线性结构可以充当栈和队列的角色
- Set(集合)
集合(set)类型也是用来保存多个的字符串元素,集合中不允许有重复出现的元素
集合的元素是无序的,不能够通过下标来获得值
- zset(即sotred set:有序集合)
有序集合保留了集合不能有重复成员的特性,不同的是有序集合中的元素是可以排序的。
和列表使用索引下标作为排序依据不同的是它给每个元素设置一个分数(score)作为排序的依据
4、Redis是单线程架构,但为什么这么快?
- Redis 的数据都是存放在内存上,绝大部分请求都是对内存进行操作,非常快速
- 非阻塞I/O,Redis使用 epoll 作为I/O多路复用技术的实现;加上Redis自身事件处理模型将epoll中的连接,读写,关闭都转换为事件,不会在网络I/O上浪费过多时间
- 单线程避免了不必要的因上下文切换、多线程资源竞争所导致的资源消耗,更加快速
5、什么是缓存穿透?怎么解决?
- 缓存穿透
是指当查询一个不存在的数据时,由于缓存不命中就会去数据库查询
如果每次都去查询一个不存在的数据,就会导致这个不存在的数据每次请求都要到数据库中查询,造成缓存穿透
- 解决方法
将空数据缓存,如果查询一个数据返回空值(不管数据存不存在还是系统故障),仍把这个空结果缓存起来,并设置过期时间
布隆过滤器,将所有可能存在的数据哈希到一个足够大的 bitmap 中,一定不存在的数据会被这个 bitmap 拦截掉,从而避免对数据库的查询压力
6、什么是缓存雪崩?该如何解决?
- 缓存雪崩
指的是缓存集中在一段时间内失效,发生了大量的缓存穿透,导致所有的查询操作都落在数据库上,造成了缓存雪崩
- 解决方法
加锁排队:缓存失效后,通过加锁或者队列来控制对数据库进行操作的线程数量,避免数据库压力过大
数据预热:通过缓存 reload 机制,预先更新缓存,在即将发生大并发访问前手动触发缓存,并设置不同的过期时间
二级缓存(双缓存)策略:Cache1 为原始缓存,Cache2 为拷贝缓存,Cache1 失效时,可以访问 Cache2,Cache1 缓存失效时间设置为短期,Cache2 设置为长期
在缓存的时候给过期时间加上一个随机值,这样就会大幅度的减少缓存在同一时间过期
7、Redis 持久化机制有哪几种
Redis是将数据运行在内存中的,如果出现服务挂掉或者服务器宕机都可以导致数据全部丢失,为了解决这个问题 redis 提供了两种数据持久化机制——RDB、AOF
- RDB
RDB 是 Redis DataBase 的缩写
按照一定时间间隔把内存中的数据以快照的形式(dump.rdb)保存到磁盘中
触发RDB持久化过程为手动触发和自动触发
手动触发:save 命令或 bgsave 命令
自动触发:配置文件添加 save 字段
- AOF
AOF 是 Append-only file 的缩写
Redis 会将每一个收到的写命令都追加到 AOF 文件最后,类似于 MySQL 的 binlog,Reids重启后会通过重新执行 AOF 文件中的写命令来实现数据的恢复
通过在配置文件里添加 appendonly yes 字段来开启 AOF
- 两者区别
RDB 使用快照的形式来持久化整个 Redis 数据,而 AOF 只是将每次执行的命令追加到 AOF
文件中
如果两个都配置了,优先采用 AOF
AOF 提供了多种数据同步频率,最多丢失 1 秒的数据而已,RDB是隔一段时间进行持久化,比 RDB 安全
对于具有相同数据的的 Redis,AOF 文件通常会比 RDB 文件体积更大
8、在进行RDB持久化时,Redis 可以处理写请求吗
可以,Redis 使用操作系统的多进程写时复制技术 COW(Copy On Write) 来实现快照持久化,保证数据一致性
Redis 在 RDB 持久化时会 fork 出一个子进程,由子进程来负责持久化,而父进程继续处理客户端请求
当父进程收到客户端的写请求时,就会将数据复制一份传给子进程,子进程将副本数据写到 RDB 文件里
9、谈谈 Redis 的内存回收机制吧
Redis是基于内存的数据库,常被用作缓存,以此来提高系统的响应速率与性能
因此在一些业务场景中往往会出现 Redis 消耗了大量的内存,导致系统出现性能瓶颈,为此 Redis 提供了内存回收机制(Redis默认采用noeviction策略)
volatile-lru:
#在设置了过期时间的所有键中,选取最近最少使用的数据删除。
volatile-lfu:
#在设置了过期时间的所有键中,选取最近最不常用,也就是一定时期内被访问次数最少的数据删除
volatile-random:
#筛选出设置了过期时间的键值对,随机删除。
volatile-ttl:
#筛选出设置了过期时间的键值对,越早过期的越先被删除。
allkeys-lru:
#在所有键中,选取最近最少使用的数据删除
allkeys-lfu:
#在所有键中,选取最近最不常用,也就是一定时期内被访问次数最少的数据删除
allkeys-random:
#采用随机淘汰策略删除所有的键值对,这个策略不常用。
noeviction:
#不淘汰任何键值对,当内存满时,如果进行读操作,例如get命令,它将正常工作,而做写操作,它将返回错误,也就是说,当Redis采用这个策略内存达到最大的时候,它就只能读不能写了
10、谈谈 Redis 的键过期机制吧
除了 Redis 的内存回收机制可以有效解决消耗内存过高的问题
还有一个键过期机制,通过给 key 设置一个过期时间,超过过期时间后 key 就会被删除,内存就被回收
Redis key过期处理的方式有三种
- 惰性删除
不管键有没有过期都不主动删除,等到每次去获取键时再判断是否过期,如果过期就删除该键,否则返回键对应的值。这种策略对内存不够友好,可能会浪费很多内存
缺点:若大量的key在超出超时时间后,很久一段时间内,都没有被获取过,那么可能发生内存泄露(无用的数据占用了大量的内存)
- 定时删除
在设置key的过期时间的同时,还会为该key创建一个定时器,让定时器在key的过期时间来临时,对key进行删除
缺点:定时器的创建耗时,若为每一个设置过期时间的key创建一个定时器(将会有大量的定时器产生),性能影响严重,因为每个定时器都会占用一定的
CPU
资源 定期删除
系统每隔一段时间就定期扫描一次,发现过期的键就进行删除
以下两种方式可以触发定期删除
- 配置redis.conf 的hz选项,默认为10 (即1秒执行10次,100ms一次,值越大说明刷新频率越快,最Redis性能损耗也越大)
- 配置内存回收策略,当Redis消耗内存达到最大内存使用限制,就会自行对应的策略,来对过期key进行删除
在 Redis
当中,其选择的是策略 2
和策略 3
的综合使用。不过 Redis
的定期删除只会扫描设置了过期时间的键,因为设置了过期时间的键 Redis
会单独存储,所以不会出现扫描所有键的情况
11、同一时间大量 key 都过期的话会有什么影响?
- 读写请求响应时间变长
当 key 过期后,内存管理器需要对 key 占用的内存进行回收,会产生一定的 CPU 消耗
大量的 key 过期会导致频繁回收内存,消耗 CPU 资源,导致系统响应变慢
- 缓存雪崩
缓存失效后导致所有的查询操作都落在数据库上,造成了缓存雪崩
12、slave是怎么实现键过期策略的?
slave 不会进行过期扫描, slave 对过期 key 的处理是被动的
当 master 采用定期或惰性删除过期 key 时,会同步一个 del 操作到 slave,这样 slave 也可以删除过期 key
RDB对过期Key的处理
持久化数据到RDB文件
- 持久化之前会检查 key 是否过期,过期的 key 不进入RDB文件
从RDB文件恢复数据
- 数据载入数据库之前,会对 key 进行过期检查,如果过期则不导入数据库(主库)
- 如果 RDB 文件里有过期的键,那还是会载入,但是主从在数据同步时(全量复制),slave的数据会被清空(丢弃原先所有数据),所以不影响
AOF对过期Key的处理
持久化数据到 AOF 文件
- 如果某个 key 过期,还没有被删除,该 key 是不会进入 aof 文件的,因为没有发生修改命令
- 当 key 过期被删除后,就会向 aof 文件追加一条 del 命令(在将来的以 aof 文件恢复数据的时候该过期的键就会被删掉)
AOF重写
- 重写时,会先判断 key 是否过期,已过期的 key不会重写到 aof 文 件