编程技术网

关注微信公众号,定时推送前沿、专业、深度的编程技术资料。

 找回密码
 立即注册

QQ登录

只需一步,快速开始

极客时间

Redis 单线程模型分析

你的怀里 redis 2021-12-22 01:56 120人围观

腾讯云服务器
Redis 单线程模型Redis 单线程模型
Redis 基于 Reactor 模式开发了自己的网络事件处理器,这个处理器被称为文件事件处理器(file event handler)。由于文件事件处理器(file event handler)是单线程方式运行的,所以说 Redis 是单线程模型。
虽然 Redis 是单线程的,但仍然可以监听大量的客户端连接,原因在于文件事件处理器使用 I/O 多路复用(multiplexing)程序来同时监听多个客户端连接(即多个套接字),并根据套接字目前执行的任务来为套接字关联不同的事件处理器。也就是说,I/O 多路复用技术使得 Redis 不需要额外创建多余的线程来监听客户端的大量连接,降低了资源的消耗
I/O 多路复用
多路指的是多个 Socke t连接,复用指的是复用一个线程。
多路复用主要有三种技术:select,poll,epoll。epoll 是最新的也是目前最好的多路复用技术。

文件事件处理器
Redis 服务器是一个事件驱动程序。服务器需要处理两类事件:
  • 文件事件:服务器通过套接字与客户端或者其它服务器进行通信,文件事件就是对套接字操作的抽象
  • 时间事件:服务器有一些操作需要在给定的时间点执行,时间事件是对这类定时操作的抽象。
文件事件处理器主要是包含 4 个部分:
  • 多个 Socket(客户端连接)
  • IO 多路复用程序(支持多个客户端连接)
  • 文件事件分派器(将 Socket 关联到相应的事件处理器)
  • 事件处理器(比如命令请求处理器、命令回复处理器、连接应答处理器)
Redis 选择使用单线程模型处理来自客户端的绝大多数网络请求,主要有以下 3 个原因:
  • 几乎不存在 CPU 成为瓶颈的情况, Redis 主要受限于内存和网络。
    Redis 并不是 CPU 密集型的服务,如果不开启 AOF 备份,所有 Redis 的操作都会在内存中完成不会涉及任何的 I/O 操作,这些数据的读写由于只发生在内存中,所以处理速度是非常快的;
    整个服务的瓶颈在于网络传输带来的延迟等待客户端的数据传输,也就是网络 I/O,所以使用多线程模型处理全部的外部请求可能不是一个好的方案。
  • 使用单线程模型能带来更好的可维护性,方便开发和调试
    单线程不需要并发控制。
  • 使用单线程模型也能并发的处理客户端的请求
    I/O 多路复用机制。

Redis 4.0 后引入多线程
在 Redis 4.0 之后的版本,Redis 服务在执行一些命令时就会使用 ”主处理线程“ 之外的其他线程,例如 UNLINK、FLUSHALL ASYNC、FLUSHDB ASYNC 等非阻塞的删除操作。
对于 Redis 中的一些超大键值对,几十 MB 或者几百 MB 的数据并不能在几毫秒的时间内处理完,Redis 可能会需要在释放内存空间上消耗较多的时间。其实释放内存空间的工作可以由后台线程异步进行处理,只需要将键从元数据中删除,而真正的删除操作会在后台异步执行。Redis 引入多线程后,对于一些大键值对的删除操作,可以通过多线程非阻塞地释放内存空间减少对 Redis 主线程阻塞的时间,提高执行的效率。
总的来说,Redis 6.0 之前主要还是单线程处理
Redis 6.0 引入多线程
Redis6.0 引入多线程主要是为了提高网络 IO 读写性能。
虽然 Redis6.0 引入了多线程,但是 Redis 的多线程只是在网络数据的读写这类耗时操作上使用,执行命令仍然是单线程顺序执行。所以仍然是线程安全的。
Redis 6.0 的多线程默认是禁用的,只使用主线程。如需开启需要修改 redis.conf 配置文件:
io-threads-do-reads yes # 开启多线程
开启多线程后,还需要设置线程数,否则是不生效的。同样需要修改 redis.conf 配置文件:
io-threads 2 # 官网建议 4 核的机器建议设置为2或3个线程,8 核的建议设置为6个线程
关于线程数,官方有一个建议:4 核的机器建议设置为 2 或 3 个线程,8 核的建议设置为 6个线程,线程数一定要小于机器核数。
Redis 6.0 多线程的实现机制
实现机制流程如下:
  • 主线程负责接收建立连接请求,获取 Socket 放入等待队列
  • 主线程处理完读事件之后,通过轮询调度方法将这些连接分配给这些 IO 线程
  • 主线程阻塞等待 IO 线程读取 Socket 完毕
  • 主线程执行请求命令,请求数据读取并解析完成
  • 主线程阻塞等待 IO 线程将数据回写 Socket 完毕
  • 解除绑定,清空等待队列
其中 IO 线程:
  • 要么同时在读 Socket,要么同时在写,不会同时读或写
  • 只负责读写 Socket 解析命令,不负责命令处理

Redis 6.0 多线程和 Memcached 多线程模型对比
相同点:都采用了 Master 线程-Worker 线程模型
不同点:Memcached 执行主逻辑也是在 Worker 线程里,模型更加简单,实现了真正的线程隔离,符合我们对线程隔离的常规理解。而 Redis 把处理逻辑交还给 Master 线程,虽然一定程度上增加了模型复杂度,但也解决了线程并发安全等问题。

腾讯云服务器 阿里云服务器
关注微信
^