Redis线程模型

  对于读写命令来说,Redis 一直是单线程模型。不过,在 Redis 4.0 版本之后引入了多线程来执行一些大键值对的异步删除操作, Redis 6.0 版本之后引入了多线程来处理网络请求(提高网络 IO 读写性能)。
  Redis默认十个数据库,默认是第0个。
1.Redis 单线程模型了解吗?
  Redis 基于 Reactor 模式设计开发了一套高效的事件处理模型,这套事件处理模型对应的是 Redis 中的文件事件处理器(file event handler)。由于文件事件处理器(file event handler)是单线程方式运行的,所以我们一般都说 Redis 是单线程模型。
  Reactor模式异步阻塞IO)也叫反应器设计模式,是一种为处理服务请求并发提交到一个或者多个服务处理器的事件设计模式。当请求抵达后,通过服务处理器将这些请求采用多路分离的方式分发给相应的请求处理器。


既然是单线程,那怎么监听大量的客户端连接呢?
  Redis 通过 IO 多路复用程序来监听来自客户端的大量连接(或者说是监听多个 socket),它会将一些事件及类型(读、写)注册到内核中并监听每个事件是否发生。
  这样的好处非常明显:I/O多路复用技术的使用让 Redis不需要额外创建多余的线程来监听客户端的大量连接,降低了资源的消耗(和 NIO 中的 Selector组件很像)。
  文件事件处理器(file event handler)主要是包含4个部分:
    ·多个socket(客户端连接)
    ·IO多路复用程序(支持多个客户端连接的关键)
    ·文件事件分派器(将socket关联到相应的事件处理器)
    ·事件处理器(连接应答处理器、命令请求处理器、命令回复处理器)
 
2.Redis6.0之前为什么不使用多线程?为什么用单线程?
  ·单线程编程容易并且更容易维护;
  ·Redis 的性能瓶颈不在 CPU ,主要在内存和网络;
  ·多线程就会存在死锁、线程上下文切换等问题,甚至会影响性能。

  ·虽然Redis是单线程模型,但4.0之后就加入了对多线程的支持。Redis4.0增加的多线程主要是针对一些大键值对的删除操作的命令,使用这些命令就会使用主线程之外的其他线程来异步处理。
  为此,Redis 4.0 之后新增了UNLINK(可以看作是 DEL 的异步版本)、FLUSHALL ASYNC(清空所有数据库的所有 key,不仅仅是当前 SELECT 的数据库)、FLUSHDB ASYNC(清空当前 SELECT 数据库中的所有 key)等异步命令。
为什么Redis 的性能瓶颈不在 CPU ,主要在内存和网络?
  ·Redis使用内存存储数据,所以数据访问非常迅速,不会成为性能瓶颈。
  ·Redis的数据操作大多数都是简单的键值对操作,不包含复杂计算和逻辑,因而CPU开销很小。
  ·Redis的瓶颈在于内存的容量和网络的带宽,这些问题无法通过增加CPU核心来解决。
   从Redis自身角度来说,因为读写网络的read/write系统调用占用了Redis执行期间大部分CPU时间,瓶颈主要在于网络的 IO 消耗, 优化主要有两个方向:
    • 提高网络 IO 性能,典型的实现比如使用 DPDK 来替代内核网络栈的方式
    • 使用多线程充分利用多核,典型的实现比如 Memcached。


3.Redis6.0 之后为何引入了多线程?
  Redis6.0 引入多线程主要是为了提高网络 IO 读写性能,因为这个算是 Redis 中的一个性能瓶颈(Redis 的瓶颈主要受限于内存和网络)。
  虽然,Redis6.0 引入了多线程,但是 Redis 的多线程只是在网络数据的读写这类耗时操作上使用了,执行命令仍然是单线程顺序执行。因此,你也不需要担心线程安全问题。
  Redis6.0 的多线程默认是禁用的,只使用主线程。如需开启需要设置 IO 线程数 > 1,需要修改 redis 配置文件 redis.conf :

io-threads-do-reads yes
  官网描述开启多线程读并不能有太大提升,因此一般情况下并不建议开启。
 
4.Redis6.0多线程的实现机制?
  核心思路:将主线程的IO读写任务拆分出来给一组独立的线程执行,使得多个socket读写可以并行化。
    ·主线程负责接收建立连接的请求,获取socket放到全局等待处理队列
    ·主线程处理完读事件之后,通过Round Robin将这些连接分配给IO线程
    ·主线程阻塞等待IO线程读取socket完毕
    ·主线程通过单线程的方式执行请求命令,请求数据读取并解析完成,但并不执行
    ·主线程阻塞等待IO线程将数据回写socket完毕
    ·解除绑定,清空等待队列
  该线程有如下特点:
    ·IO线程要么同时在读socket,要么同时在写,不会同时读或写
    ·IO线程只负责读写socket解析命令,不负责命令处理(主线程串行执行命令)
 
5.Redis后台线程了解吗?
  我们虽然经常说 Redis 是单线程模型,一般是指正常的 请求处理+周期任务(处理请求包括:接收连接、IO监听/读/写以及命令执行;周期任务,如删除过期key、字典 rehash 等,但实际还有一些后台线程用于执行一些比较耗时的操作:
  • 通过 bio_close_file 后台线程来释放 AOF / RDB 等过程中产生的临时文件资源。
  • 通过 bio_aof_fsync 后台线程调用 fsync 函数将系统内核缓冲区还未同步到到磁盘的数据强制刷到磁盘( AOF 文件)。
  • 通过bio_lazy_free后台线程释放大对象(已删除)占用的内存空间。
 bio:background io
  生产者-消费者 模式,主线程负责生产任务事件,然后投递到 队列;后台线程就是我们的消费者,负责从队列取出任务事件并处理。
 
posted @ 2023-09-06 11:40  壹索007  阅读(79)  评论(0编辑  收藏  举报