设计有关的网站,龙岗品牌网站建设,自己可以做网站吗,世界大学排名前言#xff1a;此篇文章系本人学习过程中记录下来的笔记#xff0c;里面难免会有不少欠缺的地方#xff0c;诚心期待大家多多给予指教。 基础篇#xff1a;
Redis#xff08;一#xff09;Redis#xff08;二#xff09;Redis#xff08;三#xff09;Redis#x… 前言此篇文章系本人学习过程中记录下来的笔记里面难免会有不少欠缺的地方诚心期待大家多多给予指教。 基础篇
Redis一Redis二Redis三Redis四Redis五Redis六Redis七Redis八 进阶篇
Redis九 接上期内容上期完成了Redis基础篇的学习。下面开始学习Redis的进阶知识话不多说直接发车。 一、前提说明
进阶篇主要学习Redis面试中反复出现的经典问题以及与之紧密对应的实际操作。这一阶段的学习具有一定的挑战性需要你具备扎实的Redis基础知识。如果你是零基础的新手或者目前基础较为薄弱建议你先移步基础篇。待你在基础篇中积累了足够的知识和经验再信心满满地回归向进阶篇发起冲击。 二、经典面试题
一、多线程 VS 单线程
1、Redis是多线程还是单线程
答分版本讨论。
redis版本为3.x redis是单线程。
redis版本4.x严格意义来说也不是单线程而是负责处理客户端请求的线程是单线程但是开始加了点多线程的东西(异步删除)。
2020年5月版本的6.0.x后及2022年出的7.0版本后告别了大家印象中的单线程用一种全新的多线程来解决问题 *总结分版本讨论。Redis6.x之前都可以称单线程Redis6.x之后是多线程这个多线程主要是用于处理网络 I/O 操作而键值对的读写操作仍然是单线程的。 2、Redis的单线程指的什么
答Redis单线程指Redis的网络IO和键值对读写是由一个线程来完成的Redis在处理客户端的请求时包括获取 (socket 读)、解析、执行、内容返回 (socket 写) 等都由一个顺序串行的主线程处理这就是所谓的“单线程”。这也是Redis对外提供键值存储服务的主要流程。 但Redis的其他功能比如持久化RDB、AOF、异步删除、集群数据同步等等其实是由额外的线程执行的。
*总结单线程指的是Redis命令工作线程但是整个Redis(6.x之后)来说是多线程的。 3、Redis4.x之前为啥选择单线程
答①、使用单线程模型是Redis的开发和维护更简单因为单线程模型方便开发和调试。
②、单线程避免了不必要的上下文切换和多线程竞争这就省去了多线程切换带来的时间和性能上的消耗而且单线程不会导致死锁问题的发生。
③、即使使用单线程模型也并发的处理多客户端的请求主要使用的是IO多路复用和非阻塞IO。
④、对于Redis系统来说主要的性能瓶颈是内存或者网络带宽而并非 CPU。 4、既然单线程这么好为啥又逐渐引入多线程
答单线程虽好但也不是全能。正常情况下使用 del 指令可以很快的删除数据而当被删除的 key 是一个非常大的对象时例如时包含了成千上万个元素的 hash 集合时那么 del 指令就会造成 Redis 主线程卡顿。这就是redis3.x单线程时代最经典的故障大key删除的问题。
于是在 Redis 4.x 中就新增了多线程的模块当然此版本中的多线程主要是为了解决删除数据效率比较低的问题的比如unlink key、flushdb async、flushall async命令。
*总结逐渐引入多线程是为了弥补单线程的短板比如删除bigKey问题。 二、I/O多路复用
1、什么是I/O多路复用
答①、I/O一般在操作系统层面指数据在内核态和用户态之间的读写操作。
②、多路指多个客户端连接连接就是套接字描述符即 socket 或者 channel。
③、复用指复用一个或几个线程
*总结在Redis中的I/O多路复用指一个或一组线程处理多个TCP连接使用单进程就能够实现同时处理多个客户端的连接无需创建或者维护过多的进程/线程。
在Unix网络编程中的I/O多路复用指的是一种同步的IO模型实现一个线程多个文件句柄一旦某个文件句柄就绪就能够通知到对应应用程序进行相应的读写操作没有文件句柄就绪时就会阻塞应用程序从而释放CPU资源。 后续会深入研究。 2、主线程和IO线程如何协作完成请求
答
阶段一服务端和客户端建立Socket连接并分配处理线程
首先主线程负责接收建立连接请求当有客户端请求和实例建立Socket连接时主线程会创建和客户端的连接并把 Socket 放入全局等待队列中。紧接着主线程通过轮询方法把Socket连接分配给IO线程。
阶段二IO线程读取并解析请求 主线程一旦把 Socket 分配给IO线程就会进入阻塞状态等待IO线程完成客户端请求读取和解析。因为有多个IO线程在并行处理所以这个过程很快就可以完成。
阶段三主线程执行请求操作 等到IO线程解析完请求主线程还是会以单线程的方式执行这些命令操作。
阶段四IO线程回写 Socket 和主线程清空全局队列 当主线程执行完请求操作后会把需要返回的结果写入缓冲区然后主线程会阻寨等待IO线程把这些结果回写到 Socket 中并返回给客户端。和IO线程读取和解析请求一样IO线程回写 Socket 时也是有多个线程在并发执行所以回写 Socket 的速度也很快。等到IO线程回写 Socket 完毕主线程会清空全局队列等待客户端的后续请求。 *总结Redis6.x之后将主线程的 IO 读写任务拆分给一组独立的线程去执行这样就可以使多个 socket 的读写可以并行化了采用多路 I/O 复用技术可以让单个线程高效的处理多个连接请求尽量减少网络IO的时间消耗将最耗时的Socket的读取、请求解析、写入单独外包出去剩下的命令执行仍然由主线程串行执行并和内存的数据交互。 三、Redis为什么这么快
答①、基于内存操作Redis 的所有数据都存在内存中因此所有的运算都是内存级别的所以他的性能比较高
②、高效的数据结构Redis 的数据结构是专门设计的而这些简单的数据结构的查找和操作的时间大部分复杂度都是 O(1)因此性能比较高
③、I/O多路复用和非阻塞 I/ORedis 使用 I/O多路复用功能来监听多个 Socket 连接客户端这样就可以使用一个线程连接来处理多个请求减少线程切换带来的开销同时也避免了 I/O 阻塞操作
④、上下文切换少因为是单线程模型因此就避免了不必要的上下文切换和多线程竞争这就省去了多线程切换带来的时间和性能上的消耗而且单线程不会导致死锁问题的发生。 三、Redis多线程实操
一、开启多线程
在Redis7的版本中多线程模式默认是关闭的。 如果需要使用多线程功能需要在redis.conf中完成两个设置 1、设置io-thread-do-reads配置项改为yes表示启动多线程。 2、io-threads设置线程个数。关于线程数的设置官方的建议是如果为 4 核的 CPU建议线程数设置为 2 或 3如果为 8 核 CPU 建议线程数设置为 6线程数一定要小于机器核数线程数并不是越大越好。 四、深入理解I/O多路复用和epoll
一、出现的背景
在处理并发多客户端连接的场景中在多路复用技术出现之前同步阻塞网络 I/O 模型是最简单且典型的方案。这种模式的核心特点是采用一个进程来处理一个网络连接也就是对应一个用户请求。
优点这种方式非常容易让人理解写起代码来非常的自然符合人的直线型思维
缺点性能差每个用户请求到来都得占用一个进程来处理来一个请求就要分配一个进程跟进处理。随着客户端数量的不断增加进程数量也会相应地急剧增长。每个进程都需要占用一定的系统资源如内存、CPU 时间片等这会导致系统资源的大量消耗甚至可能出现资源耗尽的情况。 二、Unix网络编程中的五种IO模型
1、Blocking IO阻塞式 IO
在这种模型下当一个应用程序执行 IO 操作时例如读取数据进程会一直处于阻塞状态直到数据准备好并且被成功读取到缓冲区中才会继续执行后续的代码。也就是说在等待数据的过程中进程无法进行其他任何操作只能等待。 2、Non-Blocking IO非阻塞式 IO
与阻塞式 IO 不同当应用程序执行 IO 操作时如果数据尚未准备好系统不会让进程进入阻塞状态而是立即返回一个错误信息告知当前数据未准备就绪。应用程序可以在不被阻塞的情况下继续执行其他任务并通过不断轮询的方式来检查数据是否准备好从而决定是否再次尝试进行 IO 操作。 3、IO multiplexingIO 多路复用
该模型允许一个进程同时监视多个文件描述符fd的状态变化。它通过使用特定的函数如 select、poll、epoll 等来监听多个文件描述符当其中任何一个文件描述符上有数据可读或可写时函数会返回相应的信息进程就可以对这些就绪的文件描述符进行对应的 IO 操作。这种方式有效地提高了系统资源的利用率避免了在多个文件描述符上进行阻塞式 IO 操作时可能出现的资源浪费。 4、signal driven IO信号驱动式 IO(暂不涉及)
5、asynchronous IO异步式 IO暂不涉及 三、四种状态理解
1、同步Synchronous
同步是一种操作模式在这种模式下当一个任务比如函数调用、IO 操作等被发起后调用者通常是进程或线程会一直等待该任务的完成期间不会执行其他相关操作。只有当任务执行结束并返回结果后调用者才会继续执行后续的代码 2、异步Asynchronous
异步与同步相反当一个任务被发起后调用者不会等待任务的完成而是立即继续执行后续的代码。任务在后台由系统或其他线程进行处理当任务完成时系统会以某种方式如回调函数、事件通知等告知调用者任务已完成。 3、阻塞Blocking
阻塞状态主要用于描述进程或线程在执行某些操作时的行为。当一个进程或线程执行一个阻塞操作如阻塞式的 IO 操作时它会暂停自身的执行进入等待状态直到操作完成例如数据读取完毕或写入成功才会继续执行后续代码。 4、非阻塞Non-Blocking
非阻塞意味着进程或线程在执行某些操作时不会因为操作未完成而被暂停。如果操作不能立即完成系统会立即返回一个状态信息如错误码或表示操作未完成的标识进程或线程可以继续执行其他任务。 5、组合
在实际的编程场景中这四种状态常常会以不同的组合形式出现。例如
同步阻塞最常见的传统操作模式比如同步文件读取操作在读取过程中进程被阻塞等待文件读取完成。同步非阻塞虽然操作是同步的需要等待操作结果但操作本身是非阻塞的调用者需要不断轮询检查操作是否完成。异步阻塞这种情况相对较少见理论上异步操作不应该阻塞调用者但在某些特殊情况下例如在异步操作完成前调用者可能因为等待异步操作的结果而被阻塞比如等待回调函数执行完毕。异步非阻塞这是一种理想的高效模式任务在后台异步执行调用者不会被阻塞可以继续执行其他任务并且当任务完成时系统会通过合适的方式通知调用者。
*总结同步、异步的讨论对象是被调用者(服务提供者)重点在于获得调用结果的消息通知方式上。阻塞、非阻塞的讨论对象是调用者(服务请求者)重点在于等消息时候的行为调用者是否能干其它事。 四、BIO、NIO实操
打算模拟一台Redis服务器两台两台客户端来完成接下来两种模式的实操。
1、BIO阻塞式IO
1.1、前提说明
了解一个专业词汇recvfrom。 1.2、模型图 解释当用户进程调用了recvfrom这个系统调用kernel(内核)就开始了IO的第一个阶段准备数据对于网络IO来说很多时候数据在一开始还没有到达。比如还没有收到一个完整的UDP包。这个时候kernel就要等待足够的数据到来。这个过程需要等待也就是说数据被拷贝到操作系统内核的缓冲区中是需要一个过程的。而在用户进程这边整个进程会被阻塞当然是进程自己选择的阻塞。当kernel一直等到数据准备好了它就会将数据从kernel中拷贝到用户内存然后kernel返回结果用户进程才解除block的状态重新运行起来。所以BIO的特点就是在IO执行的两个阶段都被block了。 1.3、代码验证
1、单线程
RedisServer
public class RedisServer {public static void main(String[] args) throws IOException {try (ServerSocket serverSocket new ServerSocket(6379);) {while (true) {System.out.println(-----111 等待连接);Socket socket serverSocket.accept();//阻塞1 ,等待客户端连接System.out.println(-----222 成功连接);InputStream inputStream socket.getInputStream();int length -1;byte[] bytes new byte[1024];System.out.println(-----333 等待读取);while ((length inputStream.read(bytes)) ! -1)//阻塞2 ,等待客户端发送数据{System.out.println(-----444 成功读取 new String(bytes, 0, length));System.out.println();System.out.println();}inputStream.close();socket.close();}}}}
RedisClient01和RedisClient02
public class RedisClient01 {public static void main(String[] args) throws IOException {try (Socket socket new Socket(127.0.0.1, 6379);OutputStream outputStream socket.getOutputStream()) {while (true) {Scanner scanner new Scanner(System.in);String string scanner.next();if (string.equalsIgnoreCase(quit)) {break;}socket.getOutputStream().write(string.getBytes());System.out.println(------input quit keyword to finish......);}}}
}
先启动serve在启动client进行测试 结论上面的模型存在很大的问题如果客户端与服务端建立了连接如果这个连接的客户端迟迟不发数据主线程就会一直堵塞在read()方法上这样其他客户端也不能进行连接也就是一次只能处理一个客户端对客户端很不友好。
解决办法使用多线程模型解决主线程堵塞问题。 2、多线程
RedisServerBIOMultiThread
public class RedisServerBIOMultiThread {public static void main(String[] args) throws IOException {try (ServerSocket serverSocket new ServerSocket(6379);) {while (true) {System.out.println(-----111 等待连接);Socket socket serverSocket.accept();//阻塞1 ,等待客户端连接System.out.println(-----222 成功连接);new Thread(() - {try {InputStream inputStream socket.getInputStream();int length -1;byte[] bytes new byte[1024];System.out.println(-----333 等待读取);while ((length inputStream.read(bytes)) ! -1)//阻塞2 ,等待客户端发送数据{System.out.println(-----444 成功读取 new String(bytes, 0, length));System.out.println();System.out.println();}inputStream.close();socket.close();} catch (IOException e) {e.printStackTrace();}}, Thread.currentThread().getName()).start();System.out.println(Thread.currentThread().getName());}}}
}
RedisClient01和RedisClient02不改变。先启动serve在启动client进行测试 结论多线程模型确实解决了单线程模型的问题。但是每来一个客户端就要开辟一个线程如果来1万个客户端那就要开辟1万个线程。在操作系统中用户态不能直接开辟线程需要调用内核来创建的一个线程。这其中还涉及到用户状态的切换上下文的切换十分耗资源。
解决办法
①、使用线程池。但是线程池在客户端连接少的情况下可以使用但是用户量大的情况下你不知道线程池要多大太大了内存可能不够也不可行。
②、使用NIO非阻塞式IO方式。因为read()方法堵塞了所有要开辟多个线程如果什么方法能使read()方法不堵塞这样就不用开辟多个线程了这就用到了另一个IO模型NIO非阻塞式IO。 1.4、BIO优劣势总结
优势
实现简单编程模型简单直观对于初学者和简单应用场景能快速完成系统搭建。可靠性高阻塞机制使程序执行流程清晰降低了并发问题出现的概率保证了程序的可靠性。 劣势
性能瓶颈高并发场景下每个连接需独立线程处理随着连接数增加线程数量增多会大量消耗系统资源如 CPU、内存且线程创建、销毁和上下文切换会带来额外开销。可扩展性差受线程数量限制难以处理大规模并发连接当并发数超过系统承受能力会导致性能急剧下降甚至系统崩溃。
很明显这种模式不适合Redis的定位。 2、NIO非阻塞式IO
2.1、前提说明
在传统的 BIOBlocking I/O模式中服务器会为每个新接入的客户端连接单独分配一个线程来处理。随着客户端数量的增多大量线程会被创建这不仅会导致系统资源的过度消耗还会因频繁的线程上下文切换而降低性能。为有效解决这一问题可将多个客户端的Socket连接统一存放在容器中进行管理以实现对资源的高效利用和连接的统一调度为此NIO模型诞生。
在NIO模式中一切都是非阻塞的
accept()方法是非阻塞的如果没有客户端连接就返回无连接标识。read()方法是非阻塞的如果。
read()方法读取不到数据就返回空闲中标识如果读取到数据时只阻塞read()方法读数据的时间。
在NIO模式中只有一个线程当一个客户端与服务端进行连接这个socket就会加入到一个数组中隔一段时间遍历一次看这个socket的read()方法能否读到数据这样一个线程就能处理多个客户端的连接和读取了。 2.2、模型图 解释当用户进程发出read操作时如果kernel(内核)中的数据还没有准备好那么它并不会block用户进程而是立刻返回一个error。从用户进程角度讲 它发起一个read操作后并不需要等待而是马上就得到了一个结果。用户进程判断结果是一个error时它就知道数据还没有准备好于是它可以再次发送read操作。一旦kernel中的数据准备好了并且又再次收到了用户进程的system call那么它马上就将数据拷贝到了用户内存然后返回。所以NIO特点是用户进程需要不断的主动询问内核数据准备好了吗一句话用轮询替代阻塞 2.3、代码验证
新建RedisServerNIO
public class RedisServerNIO {// 模拟Socket容器static ArrayListSocketChannel socketList new ArrayList();//模拟数据报存储空间static ByteBuffer byteBuffer ByteBuffer.allocate(1024);public static void main(String[] args) throws IOException {try (ServerSocketChannel serverSocket ServerSocketChannel.open()) {System.out.println(---------RedisServerNIO 启动等待中......);serverSocket.bind(new InetSocketAddress(127.0.0.1, 6379));serverSocket.configureBlocking(false);//设置为非阻塞模式while (true) {// 轮询容器for (SocketChannel element : socketList) {int read element.read(byteBuffer);if (read 0) {System.out.println(-----读取数据: read);byteBuffer.flip();byte[] bytes new byte[read];byteBuffer.get(bytes);System.out.println(new String(bytes));byteBuffer.clear();}}SocketChannel socketChannel serverSocket.accept();if (socketChannel ! null) {System.out.println(-----成功连接: );socketChannel.configureBlocking(false);//设置为非阻塞模式socketList.add(socketChannel);System.out.println(-----socketList size: socketList.size());}}}}
} RedisClient01和RedisClient02不改变。先启动serve在启动client进行测试 结论NIO成功的解决了BIO需要开启多线程的问题。在NIO中虽然一个线程就能解决多个socket但是还存在其他2个问题。
Q1这个模型在客户端少的时候十分好用但是客户端如果很多性能如何
在有1万个客户端连接的情况下每次循环都要遍历全部1万个Socket。即便只有10个Socket有数据但需要遍历1万次那9990次遍历就是浪费资源的系统调用。 Q2这个遍历过程是在用户态进行的用户态判断socket是否有数据还是调用内核的read()方法实现的这就涉及到用户态和内核态的切换每遍历一个就要切换一次开销依旧很大。 2.4、NIO优劣势总结
优势
资源利用率相比于BIO高由于线程不会因 I/O 操作而长时间阻塞系统可以使用更少的线程来处理更多的连接减少了线程创建和上下文切换的开销从而提高了资源的利用率。实时性好线程可以在发起读或写操作后立即返回不用等待数据传输完成。 劣势
可靠性问题在高并发场景下可能慧出现空轮询问题需要进行额外的处理和优化。编程复杂度高NIO 的编程模型相对复杂要处理各种复杂的事件和状态变化增加了开发和调试的难度。
很明显这种模式也不是Redis的最优选择。 五、IO多路复用
1、定义
I/O 多路复用是一种让单个线程能够同时监视多个文件描述符如套接字的 I/O 状态变化的机制。当其中任何一个或多个文件描述符就绪可读、可写或发生异常时程序能够及时感知并进行相应的 I/O 操作。 2、模型图 解释IO multiplexing就是我们说的selectpollepoll有些技术书籍也称这种IO方式为event driven IO事件驱动IO。就是通过一种机制一个进程可以监视多个描述符一旦某个描述符就绪一般是读就绪或者写就绪能够通知程序进行相应的读写操作。可以基于一个阻塞对象并同时在多个描述符上等待就绪而不是使用多个线程(每个文件描述符一个线程每次new一个线程)这样可以大大节省系统资源。所以I/O 多路复用的特点是通过一种机制使得一个进程能同时等待多个文件描述符而这些文件描述符套接字描述符其中的任意一个进入读就绪状态selectpollepoll等函数就可以返回。 3、具体实现
前提说明由于这三个函数都是C语言的内容不做深入研究大概了解原理即可。
3.1、select
①、定义
select(2) - Linux manual page可以在Linux上通过man手册参看也可以通过Linux官网查看select(2) - Linux manual page ②、核心思想
通过设置一个文件描述符集合(实际上是一个bitmap)调用 select 函数时将该集合从用户空间复制到内核空间内核检查集合中的文件描述符状态当有文件描述符就绪时select 返回程序再遍历集合来确定哪些文件描述符就绪。类似于我们自己写的这段Java代码。 ③、执行流程
select是一个阻塞函数当没有数据时会一直阻塞在select那一行。当有数据时会将rset中对应的那一位置为1。select函数返回不再阻塞。遍历文件描述符数组判断哪个fd被置位了。读取数据然后处理。 ④、优缺点
优
是最早的 I/O 多路复用实现几乎在所有操作系统上都有支持具有良好的跨平台性。用户态和内核态不用频繁切换节省系统资源。 缺
能监视的文件描述符数量有限通常受限于 FD_SETSIZE最大1024。rset每次循环都必须重新置位为0不可重复使用。每次调用select都需要进行用户空间和内核空间的文件描述符集合复制开销较大。需要遍历整个文件描述符集合来查找就绪的文件描述符时间复杂度为 O (n)。 ⑤、小总结
select方式虽然做到了一个线程处理多个客户端连接文件描述符同时又减少了系统调用的开销多个文件描述符只有一次 select 的系统调用 N次就绪状态的文件描述符的 read 系统调用但也有一定的优化空间。 3.2、poll
①、定义 可以在Linux上通过man手册参看也可以通过Linux官网查看poll(2) - Linux manual page ②、核心思想
优化掉了select的前两个缺点。 ③、执行流程
将fd数组从用户态拷贝到内核态。poll为阻塞方法执行pol方法如果有数据会将fd对应的revents置为pollin。poll方法返回。循环遍历查找那个fd被置位为pollin了。将revents重置为0便于复用。遍历fd找到置位的fd进行读取和处理。 ④、优缺点
优
poll使用pollfd数组来代替select中的bitmap解决了select文件描述符数量限制的问题。当pollfds数组中有事件发生相应的revents置位为1遍历的时候又置位回零实现了pollfd数组的重用。 缺
pollfds数组拷贝到了内核态仍然有开销。每次调用 poll 后仍需要遍历整个数组来查找就绪的文件描述符时间复杂度为 O (n)。 ⑤、小总结
相比于select虽做了优化但是原理基本一致。核心问题并没有解决掉。 3.3、epoll
①、定义
可以在Linux上通过man手册参看也可以通过Linux官网查看epoll(7) - Linux manual page ②、核心思想
使用红黑树来管理注册的文件描述符用链表来存储就绪的文件描述符。通过 epoll_create 创建一个 epoll 实例epoll_ctl 用于添加、修改或删除文件描述符的监视事件epoll_wait 等待就绪的文件描述符彻底优化掉select、poll没解决掉的问题。 ③、执行流程
首先epoll是非阻塞的当有数据的时候会把相应的文件描述符“置位”但是epool没有revent标志位所以并不是真正的置位这时候会把有数据的文件描述符放到队首。epoll会返回有数据的文件描述符的个数。根据返回的个数读取前N个文件描述符即可。(重点不是全部遍历)读取、处理。 ④、优缺点
优
select、poll具备的优点epoll都有。epoll_wait只返回就绪的文件描述符无需遍历所有注册的文件描述符时间复杂度为 O (1)。epoll仅注册时进行一次用户空间到内核空间的复制而select、poll都是两次。 缺Linux 系统特有的不具备跨平台性。 ⑤、小总结
epoll在 Linux 系统的高并发场景下表现出色是一种非常先进的 I/O 多路复用实现。这也是Redis为啥这么快的根本原因所在。 五、epoll在Redis中的体现
Redis利用epoll来实现IO多路复用将连接信息和事件放到队列中一次放到文件事件分派器事件分派器将事件分发给事件处理器。 Redis 是跑在单线程中的所有的操作都是按照顺序线性执行的但是由于读写操作等待用户输入或输出都是阻塞的所以 I/O 操作在一般情况下往往不能直接返回这会导致某一文件的 I/O 阻塞导致整个进程无法对其它客户提供服务而 I/O 多路复用就是为了解决这个问题而出现。
此外Redis 服务采用 Reactor 的方式来实现文件事件处理器每一个网络连接其实都对应一个文件描述符。
Redis基于Reactor模式开发了网络事件处理器这个处理器被称为文件事件处理器。它的组成结构为4部分多个套接字、IO多路复用程序、文件事件分派器、事件处理器。因为文件事件分派器队列的消费是单线程的所以Redis才叫单线程模型。 参考《Redis 设计与实现》。 六、总结
在对 Redis 的进阶知识学习时通过将一些经典面试题拆分、细化、理解的方法开展了系统性的研究与学习使我对 Redis 的理解有了新的深度为以后找工作又打了夯实的基础。 ps努力到底让持续学习成为贯穿一生的坚守。学习笔记持续更新中。。。。