框架源码专题-Redis-4、原理进阶
1. Redis 使用单线程含义
主要是指 Redis 的网络 IO 和键值对读写是由一个线程来完成的,Redis 在处理客户端的请求时包括获取 (socket 读)、解析、执行、内容返回 (socket 写) 等都由一个顺序串行的主线程处理,这就是所谓的“单线程”。这也是 Redis 对外提供键值存储服务的主要流程。
但 Redis 的其他功能,比如持久化 RDB、AOF、异步删除、集群数据同步等等,其实是由额外的线程执行的。
Redis 命令工作线程是单线程的,但是,整个 Redis 来说,是多线程的;
2. 单多线程演进变化
2.1. 单多线程版本发展历史
Redis 的版本很多 3.x、4.x、6.x,版本不同架构也是不同的,不限定版本问是否单线程也不太严谨。
- 版本 3.x ,最早版本,也就是大家口口相传的 redis 是单线程。
- 版本 4.x,严格意义来说也不是单线程,而是负责处理客户端请求的线程是单线程,但是开始加了点多线程的东西 (异步删除)。
- 2020 年 5 月版本的 6.0.x 后及 2022 年出的 7.0 版本后,告别了大家印象中的单线程,用一种全新的多线程来解决问题。
2.2. Redis3.X 单线程但性能依旧很快
2.3. Redis4.0 之前一直采用单线程的主要原因
- 使用单线程模型是 Redis 的开发和维护更简单,因为单线程模型方便开发和调试;
- 即使使用单线程模型也能并发的处理多客户端的请求,主要使用的是 IO 多路复用和非阻塞 IO;
- 对于 Redis 系统来说,主要的性能瓶颈是内存或者网络带宽而并非 CPU。
2.4. 为什么又采用了多线程
2.4.1. 网络硬件性能提升
在 Redis6、7 之前,Redis 一直被大家熟知的就是它的单线程架构,虽然有些命令操作可以用后台线程或子进程执行(比如数据删除、快照生成、AOF 重写)。但是,从网络 IO 处理到实际的读写命令处理,都是由单个线程完成的。
然而,随着网络硬件的性能提升,Redis 的性能瓶颈有时会出现在网络 IO 的处理上,也就是说,单个主线程处理网络请求的速度跟不上底层网络硬件的速度,为了应对这个问题: 采用多个 IO 线程来处理网络请求,提高网络请求处理的并行度,Redis6/7 就是采用的这种方法。
但是,Redis 的多 IO 线程只是用来处理网络请求的,对于读写操作命令 Redis 仍然使用单线程来处理。这是因为,Redis 处理请求时,网络处理经常是瓶颈,通过多个 IO 线程并行处理网络操作,可以提升实例的整体处理性能。而继续使用单线程执行命令操作,就不用为了保证 Lua 脚本、事务的原子性,额外开发多线程互斥加锁机制了 (不管加锁操作处理),这样一来,Redis 线程模型实现就简单了
2.4.2. 单线程其他问题 - 删除数据效率比较低
比如当我(Redis)需要删除一个很大的数据时,因为是单线程原子命令操作,这就会导致 Redis 服务卡顿,于是在 Redis 4.0 中就新增了多线程的模块,当然此版本中的多线程主要是为了解决删除数据效率比较低的问题的。
unlink key
flushdb async
flushall async
把删除工作交给了后台的小弟(子线程)异步来删除数据了。
2.5. 主线程和 IO 多线程协作关系⭐️🔴
2.6. 如何开启多线程
Redis7 将所有数据放在内存中,内存的响应时长大约为 100 纳秒,对于小数据包,Redis 服务器可以处理 8W 到 10W 的 QPS,这也是 Redis 处理的极限了,对于 80% 的公司来说,单线程的 Redis 已经足够使用了。
在 Redis6.0 及 7 后,多线程机制默认是关闭的,如果需要使用多线程功能,需要在 redis.conf 中完成两个设置
- 设置 io-thread-do-reads 配置项为 yes,表示启动多线程。
- 设置线程个数。关于线程数的设置,官方的建议是如果为 4 核的 CPU,建议线程数设置为 2 或 3,如果为 8 核 CPU 建议线程数设置为 6,线程数一定要小于机器核数,线程数并不是越大越好。
3. Linux 网络模型
并发进阶-2、IO模型4. Redis 网络模型⭐️🔴
4.1. 单线程
https://www.bilibili.com/video/BV1cr4y1671t?t=2430.1&p=171
4.2. 多线程
5. Redis 为什么这么快⭐️🔴
❕ ^tl4ngs
决定 Redis 请求效率的因素主要是三个方面,分别是网络、cpu、内存。
5.1. 网络
在网络层面,Redis 采用多路复用的设计,提升了并发处理的连接数,不过这个阶段, {如图}Server 端的所有 IO 操作,都是由同一个主线程处理的这个时候 IO 的瓶颈就会影响到 Redis 端的整体处理性能。
所以从 Redis6.0 开始{如图},在多路复用及层面增加了多线程的处理,来优化 IO 处理的能力。 不过,具体的数据操作仍然是由主线程来处理的,所以我们可以认为 Redis 对于数据 IO 的处理依然是单线程。
5.2. CPU
从 CPU 层面来说,Redis 只需要采用单线程即可,原因有两个。如果采用多线程,对于 Redis 中的数据操作,都需要通过同步的方式来保证线程安全性,这反而会影响到 redis 的性能
在 Linux 系统上 Redis 通过 pipelining 可以处理 100w 个请求每秒,而应用程序的计算复杂度主要是 O(N) 或 O(log(N)) ,不会消耗太多 CPU
5.3. 内存
从内存层面来说,Redis 本身就是一个内存数据库,内存的 IO 速度本身就很快,所以内存的瓶颈只是受限于内存大小。最后,Redis 本身的数据结构也做了很多的优化,比如压缩表、跳跃表等方式降低了时间复杂读,同时还提供了不同时间复杂度的数据类型。使得开发人员能够有更多合适的选择
6. 实战经验
7. 参考与感谢
❕ ^5oujxq
7.1. 尚硅谷 - 周阳
7.1.1. 视频
https://www.bilibili.com/video/BV13R4y1v7sP?p=101&vd_source=c5b2d0d7bc377c0c35dbc251d95cf204
7.1.2. 脑图
file:///Users/taylor/Nutstore%20Files/Obsidian_data/pages/002-schdule/001-Arch/001-Subject/002-%E6%A1%86%E6%9E%B6%E6%BA%90%E7%A0%81%E4%B8%93%E9%A2%98/002-DB/001-Redis/%E5%B0%9A%E7%A1%85%E8%B0%B7Redis7/%E8%84%91%E5%9B%BE/Redis%E8%84%91%E5%9B%BE%EF%BC%88%E5%9F%BA%E7%A1%80%E7%AF%87+%E9%AB%98%E7%BA%A7%E7%AF%87%EF%BC%89.html
7.2. 黑马程序员
7.2.1. 视频
https://www.bilibili.com/video/BV1cr4y1671t?p=161&vd_source=c5b2d0d7bc377c0c35dbc251d95cf204
7.2.2. 资料
1 |
|