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

2021-09-0407:41:33服务器及运维Comments1,572 views字数 2032阅读模式

官方答复:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/yunwei/22509.html

  • 使用 Redis 时,几乎不存在 CPU 成为瓶颈的情况, Redis 主要受限于内存和网络。
  • 在一个普通的 Linux 系统上,Redis 通过使用pipelining 每秒可以处理 100 万个请求,所以如果应用程序主要使用 O(N) 或O(log(N)) 的命令,它几乎不会占用太多 CPU。
  • 使用了单线程后,可维护性高。多线程模型虽然在某些方面表现优异,但是它却引入了程序执行顺序的不确定性,带来了并发读写的一系列问题,增加了系统复杂度、同时可能存在线程切换、甚至加锁解锁、死锁造成的性能损耗。

Redis 通过 AE 事件模型以及 IO 多路复用等技术,处理性能非常高,因此没有必要使用多线程。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/yunwei/22509.html

单线程机制让 Redis 内部实现的复杂度大大降低,Hash 的惰性 Rehash、Lpush 等等『线程不安全』的命令都可以无锁进行文章源自菜鸟学院-https://www.cainiaoxueyuan.com/yunwei/22509.html

在《Redis 为什么这么快?》码哥有详细介绍快的原理文章源自菜鸟学院-https://www.cainiaoxueyuan.com/yunwei/22509.html

Redis 6.0 之前单线程指的是 Redis 只有一个线程干活么?文章源自菜鸟学院-https://www.cainiaoxueyuan.com/yunwei/22509.html

非也,Redis 在处理客户端的请求时,包括获取 (socket 读)、解析、执行、内容返回 (socket 写) 等都由一个顺序串行的主线程处理,这就是所谓的「单线程」文章源自菜鸟学院-https://www.cainiaoxueyuan.com/yunwei/22509.html

其中执行命令阶段,由于 Redis 是单线程来处理命令的,所有每一条到达服务端的命令不会立刻执行,所有的命令都会进入一个 Socket 队列中,当 socket 可读则交给单线程事件分发器逐个被执行。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/yunwei/22509.html

Redis 新特性篇:100% 掌握多线程模型文章源自菜鸟学院-https://www.cainiaoxueyuan.com/yunwei/22509.html

此外,有些命令操作可以用后台线程或子进程执行(比如数据删除、快照生成、AOF 重写)。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/yunwei/22509.html

码老湿,那 Redis 6.0 为啥要引入多线程呀?文章源自菜鸟学院-https://www.cainiaoxueyuan.com/yunwei/22509.html

随着硬件性能提升,Redis 的性能瓶颈可能出现网络 IO 的读写,也就是:单个线程处理网络读写的速度跟不上底层网络硬件的速度文章源自菜鸟学院-https://www.cainiaoxueyuan.com/yunwei/22509.html

读写网络的 read/write 系统调用占用了Redis 执行期间大部分CPU 时间,瓶颈主要在于网络的 IO 消耗, 优化主要有两个方向:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/yunwei/22509.html

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

添加对用户态网络协议栈的支持,需要修改 Redis 源码中和网络相关的部分(例如修改所有的网络收发请求函数),这会带来很多开发工作量。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/yunwei/22509.html

而且新增代码还可能引入新 Bug,导致系统不稳定。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/yunwei/22509.html

所以,Redis 采用多个 IO 线程来处理网络请求,提高网络请求处理的并行度。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/yunwei/22509.html

需要注意的是,Redis 多 IO 线程模型只用来处理网络读写请求,对于 Redis 的读写命令,依然是单线程处理文章源自菜鸟学院-https://www.cainiaoxueyuan.com/yunwei/22509.html

这是因为,网络处理经常是瓶颈,通过多线程并行处理可提高性能。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/yunwei/22509.html

而继续使用单线程执行读写命令,不需要为了保证 Lua 脚本、事务、等开发多线程安全机制,实现更简单。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/yunwei/22509.html

架构图如下文章源自菜鸟学院-https://www.cainiaoxueyuan.com/yunwei/22509.html

Redis 新特性篇:100% 掌握多线程模型文章源自菜鸟学院-https://www.cainiaoxueyuan.com/yunwei/22509.html

主线程与 IO 多线程是如何实现协作呢?文章源自菜鸟学院-https://www.cainiaoxueyuan.com/yunwei/22509.html

如下图:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/yunwei/22509.html

Redis 新特性篇:100% 掌握多线程模型文章源自菜鸟学院-https://www.cainiaoxueyuan.com/yunwei/22509.html

主要流程文章源自菜鸟学院-https://www.cainiaoxueyuan.com/yunwei/22509.html

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

思路:将主线程 IO 读写任务拆分出来给一组独立的线程处理,使得多个 socket 读写可以并行化,但是 Redis 命令还是主线程串行执行。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/yunwei/22509.html

如何开启多线程呢?文章源自菜鸟学院-https://www.cainiaoxueyuan.com/yunwei/22509.html

Redis 6.0 的多线程默认是禁用的,只使用主线程。如需开启需要修改 redis.conf 配置文件:io-threads-do-reads yes文章源自菜鸟学院-https://www.cainiaoxueyuan.com/yunwei/22509.html

码老湿,线程数是不是越多越好?文章源自菜鸟学院-https://www.cainiaoxueyuan.com/yunwei/22509.html

当然不是,关于线程数的设置,官方有一个建议:4 核的机器建议设置为 2 或 3 个线程,8核的建议设置为 6 个线程,线程数一定要小于机器核数。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/yunwei/22509.html

线程数并不是越大越好,官方认为超过了 8 个基本就没什么意义了。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/yunwei/22509.html

另外,开启多线程后,还需要设置线程数,否则是不生效的文章源自菜鸟学院-https://www.cainiaoxueyuan.com/yunwei/22509.html

io-threads 4

总结与思考

随着互联网的飞速发展,互联网业务系统所要处理的线上流量越来越大,Redis 的单线程模式会导致系统消耗很多 CPU 时间在网络 I/O 上从而降低吞吐量,要提升 Redis 的性能有两个方向:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/yunwei/22509.html

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

后者依赖于硬件的发展,暂时无解。所以只能从前者下手,网络 I/O 的优化又可以分为两个方向:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/yunwei/22509.html

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

模型缺陷文章源自菜鸟学院-https://www.cainiaoxueyuan.com/yunwei/22509.html

Redis 的多线程网络模型实际上并不是一个标准的 Multi-Reactors/Master-Workers 模型。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/yunwei/22509.html

Redis 的多线程方案中,I/O 线程任务仅仅是通过 socket 读取客户端请求命令并解析,却没有真正去执行命令。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/yunwei/22509.html

所有客户端命令最后还需要回到主线程去执行,因此对多核的利用率并不算高,而且每次主线程都必须在分配完任务之后忙轮询等待所有 I/O 线程完成任务之后才能继续执行其他逻辑。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/yunwei/22509.html

在我看来,Redis 目前的多线程方案更像是一个折中的选择:既保持了原系统的兼容性,又能利用多核提升 I/O 性能。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/yunwei/22509.html

  • 本站内容整理自互联网,仅提供信息存储空间服务,以方便学习之用。如对文章、图片、字体等版权有疑问,请在下方留言,管理员看到后,将第一时间进行处理。
  • 转载请务必保留本文链接:https://www.cainiaoxueyuan.com/yunwei/22509.html

Comment

匿名网友 填写信息

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定