乐趣区

关于多线程:Redis-60-新特性带你-100-掌握多线程模型

Redis 官网在 2020 年 5 月正式推出 6.0 版本,提供很多振奋人心的新个性,所以备受关注。

码老湿,提供了啥个性呀?晓得了我能加薪么?

次要个性如下:

  1. 多线程解决网络 IO;
  2. 客户端缓存;
  3. 细粒度权限管制(ACL);
  4. RESP3 协定的应用;
  5. 用于复制的 RDB 文件不在有用,将立即被删除;
  6. RDB 文件加载速度更快;

其中备受关注的就是「多线程模型 + 客户端缓存」,咱们只有把握了新个性原理,能力判断什么时候应用 6.0 版本,如何用的更好更快,不踩坑。

本篇先从 Redis 多线程模型 开始,至于客户端缓存、等且听下回分解。

最初,点击下方卡片关注「码哥字节」能加薪。

码老湿,Redis 6.0 之前为什么不应用多线程?

官网回答:

  • 应用 Redis 时,简直不存在 CPU 成为瓶颈的状况,Redis 次要受限于内存和网络。
  • 在一个一般的 Linux 零碎上,Redis 通过应用pipelining 每秒能够解决 100 万个申请,所以如果应用程序次要应用 O(N) 或 O(log(N)) 的命令,它简直不会占用太多 CPU。
  • 应用了单线程后,可维护性高。多线程模型尽管在某些方面体现优异,然而它却引入了程序执行程序的不确定性,带来了并发读写的一系列问题,减少了零碎复杂度、同时可能存在线程切换、甚至加锁解锁、死锁造成的性能损耗。

Redis 通过 AE 事件模型以及 IO 多路复用等技术,解决性能十分高,因而没有必要应用多线程。

单线程机制让 Redis 外部实现的复杂度大大降低,Hash 的惰性 Rehash、Lpush 等等『线程不平安』的命令都能够无锁进行

在《Redis 为什么这么快?》码哥有具体介绍快的原理

Redis 6.0 之前单线程指的是 Redis 只有一个线程干活么?

非也,Redis 在解决客户端的申请时,包含获取 (socket 读)、解析、执行、内容返回 (socket 写) 等都由一个程序串行的主线程解决,这就是所谓的「单线程」

其中执行命令阶段,因为 Redis 是单线程来解决命令的,所有每一条达到服务端的命令不会立即执行,所有的命令都会进入一个 Socket 队列中,当 socket 可读则交给单线程事件散发器一一被执行。

此外,有些命令操作能够用后盾线程或子过程执行(比方数据删除、快照生成、AOF 重写)。

码老湿,那 Redis 6.0 为啥要引入多线程呀?

随着硬件性能晋升,Redis 的性能瓶颈可能呈现网络 IO 的读写,也就是:单个线程解决网络读写的速度跟不上底层网络硬件的速度

读写网络的 read/write 零碎调用占用了 Redis 执行期间大部分 CPU 工夫,瓶颈次要在于网络的 IO 耗费, 优化次要有两个方向:

  • 进步网络 IO 性能,典型的实现比方应用 DPDK 来代替内核网络栈的形式。
  • 应用多线程充分利用多核,进步网络申请读写的并行度,典型的实现比方 Memcached

增加对用户态网络协议栈的反对,须要批改 Redis 源码中和网络相干的局部(例如批改所有的网络收发申请函数),这会带来很多开发工作量。

而且新增代码还可能引入新 Bug,导致系统不稳固。

所以,Redis 采纳多个 IO 线程来解决网络申请,进步网络申请解决的并行度。

须要留神的是,Redis 多 IO 线程模型只用来解决网络读写申请,对于 Redis 的读写命令,仍然是单线程解决

这是因为,网络解决常常是瓶颈,通过多线程并行处理可进步性能。

而持续应用单线程执行读写命令,不须要为了保障 Lua 脚本、事务、等开发多线程平安机制,实现更简略。

架构图如下

主线程与 IO 多线程是如何实现合作呢?

如下图:

次要流程

  1. 主线程负责接管建设连贯申请,获取 socket 放入全局期待读解决队列;
  2. 主线程通过轮询将可读 socket 调配给 IO 线程;
  3. 主线程阻塞期待 IO 线程读取 socket 实现;
  4. 主线程执行 IO 线程读取和解析进去的 Redis 申请命令;
  5. 主线程阻塞期待 IO 线程将指令执行后果回写回 socket结束;
  6. 主线程清空全局队列,期待客户端后续的申请。

思路:将主线程 IO 读写工作拆分进去给一组独立的线程解决,使得多个 socket 读写能够并行化,然而 Redis 命令还是主线程串行执行。

如何开启多线程呢?

Redis 6.0 的多线程默认是禁用的,只应用主线程。如需开启须要批改 redis.conf 配置文件:io-threads-do-reads yes

码老湿,线程数是不是越多越好?

当然不是,对于线程数的设置,官网有一个倡议:4 核的机器倡议设置为 2 或 3 个线程,8 核的倡议设置为 6 个线程,线程数肯定要小于机器核数。

线程数并不是越大越好,官网认为超过了 8 个根本就没什么意义了。

另外,开启多线程后,还须要设置线程数,否则是不失效的

io-threads 4

总结与思考

随着互联网的飞速发展,互联网业务零碎所要解决的线上流量越来越大,Redis 的单线程模式会导致系统耗费很多 CPU 工夫在网络 I/O 上从而升高吞吐量,要晋升 Redis 的性能有两个方向:

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

后者依赖于硬件的倒退,临时无解。所以只能从前者下手,网络 I/O 的优化又能够分为两个方向:

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

模型缺点

Redis 的多线程网络模型实际上并不是一个规范的 Multi-Reactors/Master-Workers 模型,Redis 的多线程计划中,I/O 线程工作仅仅是通过 socket 读取客户端申请命令并解析,却没有真正去执行命令。

所有客户端命令最初还须要回到主线程去执行,因而对多核的利用率并不算高,而且每次主线程都必须在调配完工作之后忙轮询期待所有 I/O 线程实现工作之后能力继续执行其余逻辑。

在我看来,Redis 目前的多线程计划更像是一个折中的抉择:既放弃了原零碎的兼容性,又能利用多核晋升 I/O 性能。

退出移动版