Code前端首页关于Code前端联系我们

Redis新特性:100%掌握多线程模型

terry 2年前 (2023-09-28) 阅读数 59 #未命名

官方解答:

  • 使用Redis时,几乎不会出现CPU成为瓶颈的情况。 Redis主要受到内存和网络的限制。
  • 在典型的Linux系统上,Redis使用管道化每秒可以处理100万个请求,因此如果应用程序主要使用O(N)或O(log(N))命令,则几乎不需要太多中央处理器。
  • 采用单线后,可维护性高。虽然多线程模型在某些方面表现良好,但它给程序执行的顺序带来了不确定性,导致了一系列同时读写的问题,增加了系统复杂性,并可能导致线程切换甚至锁定。解锁和死锁造成的性能损失。

Redis通过AE事件模型和IO复用等技术具有非常高的处理性能,因此不需要使用多线程。

单线程机制大大降低了Redis内部实现的复杂度。 Hash、Rehash、LPush 等“线程不安全”命令的缓慢可以在没有锁的情况下执行

,马哥详细介绍了快的原理。

Redis 6.0之前,单线程意味着Redis只有一个线程运行?

没有,Redis在处理客户端请求时,包括获取(socket读)、解析、执行、内容返回(socket写)等,都是由一个顺序串行的主线程处理的。这就是所谓的“单线程”

由于Redis在命令执行阶段使用单线程处理命令,所以并不是所有到达服务器的命令都会立即执行。所有命令最终都在 Socket 队列中。当socket可读时,就交给单线程事件处理。调度员一一执行。

Redis 新特性篇:100% 掌握多线程模型

此外,一些命令操作可以使用后台线程或子进程来执行(例如删除数据、生成快照、重写AOF)。

马老师,为什么Redis 6.0要引入多线程呢?

随着硬件性能的提升,Redis在读写网络IO时可能会出现性能瓶颈,即: 单线程处理网络读写的速度可能会提高底层网络硬件的速度

读/写网络读/写系统调用在Redis执行过程中占用了大部分CPU时间。瓶颈主要在于网络的IO消耗。优化主要有两个方向:

  • 提高网络IO性能。典型的实现是使用 DPDK 替换内核网络堆栈。
  • 使用多线程,充分利用多核,提高读写网络请求的并行度。典型的实现如Memcached

要添加对用户态网络协议栈的支持,需要修改Redis源码中与网络相关的部分(比如更改所有发送和接收网络请求的函数),这涉及到大量的开发工作。

而且新的代码也会引入新的bug,使系统不稳定。

所以Redis使用多个IO线程来处理网络请求,以提高网络请求处理的并行度。

需要注意的是,Redis多IO线程模型仅用于处理网络读写请求。对于Redis的读写来说,仍然是单线程处理

这是因为网络处理往往是瓶颈,可以通过多线程并行处理来提高性能。

继续使用单线程执行读写命令,无需开发多线程安全机制来保证Lua脚本、事务等,实现更加简单。

架构图如下

Redis 新特性篇:100% 掌握多线程模型

主线程和IO多线程是如何协同工作的?

如下图:

Redis 新特性篇:100% 掌握多线程模型

主进程

  1. 主线程负责接收连接请求,获取socket并将其插入到全局待读处理队列中;
  2. 主线程轮询将可读的socket分配给IO线程;
  3. 主线程阻塞,等待IO线程读取socket完成;
  4. 主线程运行IO线程读取解析的Redis。请求命令;
  5. 主线程阻塞,等待IO线程将指令执行结果写回socket完成;
  6. 主线程清空全局队列,等待客户端后续请求。

想法:将IO读写任务从主线程拆分到一组独立的线程中处理,这样可以并行多个socket的读写,但Redis命令仍然是串行执行的主线程。

如何启用多线程?

Redis 6.0默认禁用多线程,仅使用主线程。要启用此功能,您需要编辑配置文件redis.confio-threads-do-reads yes

代码又旧又湿。线程不是越多越好吗?

当然不是。关于线程数的设置,官方有建议:4核的机器建议2或3线程,8核的机器建议6线程。线程数必须小于机器的核心数。

线程数越多越好。官方认为超过八个线程基本没有意义。

启用多线程后,还必须设置线程数,否则没有效果

io-threads 4

总结与思考

随着互联网的快速发展,企业互联网系统需要处理的在线流量不断增加。 Redis的单线程模式导致系统在网络I/O上消耗大量CPU时间,降低吞吐量。提高Redis的性能有两个方向:

  • 优化网络I/O模块
  • 提高机器内存的读写速度

后者取决于硬件的发展,有暂时没有解决办法。所以我们只能假设第一个。网络I/O优化可以分为两个方向:

  • 零拷贝技术或者DPDK技术
  • 利用多核优势

模型缺陷

Redis的多线程网络模型其实就是不是标准的多反应堆/主工模型。

在Redis的多线程解决方案中,I/O线程任务只是通过socket读取并解析客户端请求命令,但并不真正执行该命令。

所有客户端作业都要发回主线程执行,这样多核利用率不高,每次主线程都要忙着轮询并等待所有I/O线程完成后任务分配。只有完成任务后才能继续执行其他逻辑。

在我看来,Redis目前的多线程方案更多的是一种折衷的选择:既保持了原有系统的兼容性,又利用多核来提升I/O性能。

版权声明

本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。

热门