面试准备-redis篇

    redis会问到的一些知识点,学习过程中如有错误,欢迎私聊我纠正。

面试准备–redis常用的知识点

redis基础知识

redis 我就看了 核心数据结构:字符串、hash、列表、集合、有序集合
持久化:RDB快照、AOF、混合持久化
架构:主从架构、哨兵架构、redis高可用集群
每个架构的原理和常问的问题。
持久化:redis持久化,就是把缓存数据写到磁盘。
如果没有持久化,那每次重启redis,数据就全丢了,找不回来,之后的请求全部都打到数据库,压力太大。
有了持久化,把缓存数据备份一份到磁盘文件,下次重启redis,直接进去读,就能恢复缓存数据。
redis实现持久化有三种方式:
RDB快照、AOF持久化、redis4.0混合持久化
BGSAVE(fock一个子进程,子进程执行持久化) SAVE(阻塞,主进程执行持久化)
AOF 保存的是命令字符串,过程如下:
分为追加(append)、文件写入(write)、文件同步(sync)、文件重写(rewrite)和文件加载(load)
(1)所有的写命令会追加到 AOF 缓冲中。
(2)AOF 缓冲区根据对应的策略向硬盘进行同步操作。
(3)随着 AOF 文件越来越大,需要定期对 AOF 文件进行重写,达到压缩的目的。
(4)当 Redis 重启时,可以加载 AOF 文件进行数据恢复。
文件写入和同步
Redis 每次结束一个事件循环之前,它都会调用flushAppendOnlyFile 函数,判断是否需要将 AOF 缓存区中的内容写入和同步到 AOF 文件中。
flushAppendOnlyFile 函数的行为由 redis.conf 配置中的 appendfsync 选项的值来决定。该选项有三个可选值,分别是 always、everysec 和 no:
everysec:Redis 在每个事件循环都要将 AOF 缓冲区中的所有内容写入到 AOF 文件中,并且每隔一秒就要在子线程中对 AOF 文件进行一次同步。从效率上看,该模式足够快。当发生故障停机时,只会丢失一秒钟的命令数据。
文件的重写:rewrite的触发机制主要有以下三个:
(1)手动调用 bgrewriteaof 命令,如果当前有正在运行的 rewrite 子进程,则本次rewrite 会推迟执行,否则,直接触发一次 rewrite。
(2)通过配置指令手动开启 AOF 功能,如果没有 RDB 子进程的情况下,会触发一次 rewrite,将当前数据库中的数据写入 rewrite 文件。
(3)在 Redis 定时器中,如果有需要退出执行的 rewrite 并且没有正在运行的 RDB 或者 rewrite 子进程时,触发一次或者 AOF 文件大小已经到达配置的 rewrite 条件也会自动触发一次。
AOF 后台重写:在子进程进行 AOF 重启期间,Redis接收客户端命令,会对现有数据库状态进行修改,从而导致数据当前状态和 重写后的 AOF 文件所保存的数据库状态不一致。Redis 设置了一个 AOF 重写缓冲区,这个缓冲区在服务器创建子进程之后开始使用,当 Redis 执行完一个写命令之后,它会同时将这个写命令发送给 AOF 缓冲区和 AOF 重写缓冲区。
将 AOF 重写缓冲区中的所有内容写入到新的 AOF 文件中,保证新 AOF 文件保存的数据库状态和服务器当前状态一致。
对新的 AOF 文件进行改名,原子地覆盖现有 AOF 文件,完成新旧文件的替换
继续处理客户端请求命令。

在项目中缓存是如何使用的?为什么要用缓存?缓存使用不当会造成什么后果?

用途:高并发、高性能
造成的后果:缓存与数据库双写不一致 、缓存雪崩、缓存穿透、缓存并发竞争后面再详细说明。

redis和memcached有什么区别?redis的线程模型是什么?为什么 redis单线程却能支撑高并发?

区别:redis支持复杂的数据结构,相比memcached拥有更多的数据结构。
redis只使用单核,内部使用的文件事件处理器file event handle,采用IO多路复用机制同时监听多个socket,将产生事件的socket压入内存队列中,事件分派器根据socket上的事件类型来选择对应的事件处理器进行处理。
文件事件处理器的结构包括4个部分:
1、多个 socket
2、IO 多路复用程序
3、文件事件分派器
4、事件处理器(连接应答处理器、命令请求处理器、命令回复处理器)
答:(1)redis纯内存操作;
(2)核心是基于非阻塞的IO多路复用机制;
(3)单线程反而避免了多线程的频繁上下文切换问题;

redis 都有哪些数据类型?分别在哪些场景下使用比较合适?

(1)String 普通的set和get,做简单的KV缓存;
(2)hash 类似 map 的一种结构,一般就是可以将结构化的数据,比如一个对象(前提是这个对象没嵌套其他的对象)给缓存在 redis 里,然后每次读写缓存的时候,可以就操作 hash 里的某个字段。
(3)list 是有序列表;通过lrange命令,读取某个闭区间内的元素,基于 list 实现分页查询。
(4)set 是无序集合,自动去重。
(5)sorted set 是排序的 set,去重但可以排序

redis 的过期策略都有哪些?内存淘汰机制都有哪些?手写一下LRU代码实现?

过期策略:定期删除+惰性删除;
定期删除指的是 redis 默认是每隔 100ms 就随机抽取一些设置了过期时间的 key,检查其是否过期,如果过期就删除。
内存淘汰机制:allkeys-lru:当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的 key(这个是最常用的)
手写一个LRU算法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class LRUCache<k,v> extens LinkedHashMap<K,V>{
private final int CACHE_SIZE;
/**
* 传递进来最多能缓存多少数据 *
* @param cacheSize 缓存大小 */
public LRUCache(int cacheSize) {
// true 表示让 linkedHashMap 按照访问顺序来进行排序,最近访问的放在头部,最老访问的 放在尾部。
super((int) Math.ceil(cacheSize / 0.75) + 1, 0.75f, true);
CACHE_SIZE = cacheSize;
}
@Override
protected Boolean removeEldestEntry(Map.Entry<K, V> eldest) {
// 当 map 中的数据量大于指定的缓存个数的时候,就自动删除最老的数据。
return size() > CACHE_SIZE;
}
}

如何保证 redis 的高并发和高可用?redis 的主从复制原理能介绍一下么?redis 的哨兵原理能介绍一下么?

redis 主从架构
redis 基于哨兵实现高可用
redis 实现高并发主要依靠主从架构,一主多从,一般来说,单主用来写入数据,单机几万QPS,多从用来查询数据,多个实例提供每秒10w的QPS
如果想要实现高并发的同时,容纳大量的数据,就需要redis集群,可以提供每秒几十万的读写并发。
redis replication->主从结构->读写分离->水平扩容支撑读高并发
replication的核心机制:
(1) slvae node 在做复制的时候,不会block对自己的查询操作,它会用旧的数据集来提供服务;但是复制完成的时候,需要删除旧数据集,加载新数据集,这个时候就会暂停对外服务了;
(2)slave node 复制的时候,不会阻塞master node的正常工作;
(3)slave node 主要用来进行横向扩容,做读写分离,扩容的slvae node可以提高读的吞吐量;
注意:如果使用主从架构,必须开启master node持久化,不建议用slave node作为master node 的数据热备。因为如果关闭master的持久化,可能master宕机重启的时候数据是空的。
主从结构的核心原理:
主从复制的断点续传:

总结

坚持原创技术分享,您的支持将鼓励我继续创作!