redis为什么这么快

  1. C语言实现,执行速度快
  2. 纯内存操作,数据读写在内存中,异步持久化到磁盘
  3. 丰富和高效的数据结构
  4. 基于非阻塞的I/O多路复用机制
  5. 单线程避免了上下文切换

Redis单线程

redis单线程的核心就是它基于一个假设:它在内存中执行的操作耗时很快,以至于多线程带来的收益小于其上下文切换和锁管理的消耗。

redis 核心就是 如果我的数据全都在内存里,我单线程的去操作 就是效率最高的,为什么呢,因为多线程的本质就是 CPU 模拟出来多个线程的情况,这种模拟出来的情况就有一个代价,就是上下文的切换,对于一个内存的系统来说,它没有上下文的切换就是效率最高的。redis 用 单个CPU 绑定一块内存的数据,然后针对这块内存的数据进行多次读写的时候,都是在一个CPU上完成的,所以它是单线程处理这个事。在内存的情况下,这个方案就是最佳方案 —— 阿里 沈询

  • redis 用 单个CPU 绑定一块内存的数据,针对这块内存的数据进行多次读写的时候,都是在一个CPU上完成。对于多个CPU的机器可以使用多个redis实例绑定不同的CPU
  • redis的单线程模型指的是文件事件处理器单线程,即单线程的处理请求。但是它也有自己的一些后台线程,比如说删除大key
  • 并行与并发区别 :
  • 并行是为了快,多台处理器上同时处理多个任务
  • 并发是为了能够同一时间间隔做多个事情,一台处理器上“同时”处理多个任务,它一定是慢过串行

redis的单线程模型/通信流程




多线程redis生成表ID导致线程阻塞 redis 多线程 单线程_socket io 不使用redis


核心就两大块,IO多路复用模块支撑高并发请求,文件事件处理器单线程从队列中获取socket并调用相应的请求处理器

1、首先在redis启动初始化的时候,redis会先将事件处理器中的连接应答处理器和AE_READABLE事件关联起来;

2、如果客户端向redis发起连接,会产生AE_READABLE事,产生该事件后会被IO多路复用程序监听到(步骤B),然后IO多路复用程序会把监听到的socket信息放入到队列中(步骤C),事件分配器每次从队列中取出一个socket(步骤D),然后事件分派器把socket给对应的事件处理器(步骤E)。

3、当客户端向redis发生写请求时,首先就会在对应的socket如socket01上会产生AE_READABLE事件,产生该事件后会被IO多路复用程序监听到(步骤B),然后IO多路复用程序会把监听到的socket信息放入到队列中,事件分配器每次从队列中取出一个socket(步骤D),然后事件分派器把socket给对应的事件处理器(步骤E)。

5、当客户端会查询redis是否完成相应的操作,就会在socket01上产生一个AE_WRITABLE事件,会由对应的命令回复处理器来处理,就是将准备好的相应数据写入socket01(由于socket连接是双向的),返回给客户端,如读操作,客户端会显示ok。

6、如果命令回复处理器执行完成后,就会删除这个socket01的AE_WRITABLE事件和命令回复处理器的关联。

7、这样客户端就和redis进行了一次通信。由于连接应答处理器执行一次就够了,如果客户端再次进行操作就会由命令请求处理器来处理,反复执行。


多线程redis生成表ID导致线程阻塞 redis 多线程 单线程_c多线程并发处理方式_02


Redis底层IO模型代码封装

我感觉不会问,但是阿里面经有,先放着先。

芋道源码:为什么 Redis 单线程能支撑高并发?

Redis6.0多线程

redis单线程的核心就是它基于一个假设:它在内存中执行的操作耗时很快,以至于多线程带来的收益小于其上下文切换和锁管理的消耗。

而现在这个假设在真实场景下发生了瓶颈:网络IO消耗,当value比较大时:

  • 从socket中读取请求数据,会从内核态将数据拷贝到用户态 (read调用)
  • 将数据回写到socket,会将数据从用户态拷贝到内核态 (write调用)

解决方案:

  1. 主线程负责接收建立连接请求,获取 socket 放入全局等待读处理队列
  2. 主线程接收完所有读事件之后,通过 RR(Round Robin) 将这些连接分配给 IO 线程组
  3. 主线程阻塞等待 IO 线程组读取 socket 完毕
  4. 主线程通过单线程的方式执行请求命令(指客户端发送的命令),请求数据读取并解析完成
  5. 主线程阻塞等待 IO 线程组将数据回写 socket 完毕
  6. 解除绑定,清空等待队列
  • 命令的执行依然由主线程单线程串行顺序执行(保持单线程)
  • I/O线程要么同时读,要么同时写,不会同时读或写
  • IO 线程只负责读写 socket 解析命令,不负责命令处理
  • 整个过程无锁参与
  • 多线程肯定要低于机器CPU核数,并行才能提高性能,并发只会浪费


多线程redis生成表ID导致线程阻塞 redis 多线程 单线程_socket io 不使用redis_03


多线程redis生成表ID导致线程阻塞 redis 多线程 单线程_socket io 不使用redis_04


为什么之前不使用多线程?

官方曾经回应:使用Redis时,几乎不存在CPU成为瓶颈的情况, Redis主要受限于内存和网络。引入多线程,引入了程序执行顺序的不确定性,带来了并发读写的一系列问题,增加了系统复杂度、同时可能存在线程切换、甚至加锁解锁、死锁造成的性能损耗。

那为什么现在又要用多线程了呢?

因为现在业务场景越来越复杂,对性能要求越来越高,所以对redis做出了提高性能的要求

整理来源

单线程模型讲解

单线程模型讲解

redis6.0

redis6.0多线程