查看“关于:Redis 到底是单线程还是多线程?”的源代码
←
关于:Redis 到底是单线程还是多线程?
跳到导航
跳到搜索
因为以下原因,您没有权限编辑本页:
您请求的操作仅限属于该用户组的用户执行:
用户
您可以查看和复制此页面的源代码。
[[category:Redis]] == “Redis 是不是单线程” == “Redis 是不是单线程”是最最最常问的一个问题,不能简而言之地用“是”或“不是”来描述。 === Redis 是单线程的吗? === '''执行 Redis 命令的核心模块是单线程的''',而不是整个 Redis 实例就一个线程,Redis 其他模块还有各自模块的线程的。 === 什么是“单线程模型”?=== “Redis 是单线程模型”指的是: <pre> Redis 客户端对服务端的每次调用都经历了:“发送命令”,“执行命令”,“返回结果”三个过程。 其中“执行命令”阶段,由于 Redis 是单线程来处理命令的: 所有到达服务端的命令都不会立刻执行,所有的命令都会进入一个队列中,然后逐个执行,并且多个客户端发送的命令的执行顺序是不确定的,但是可以确定的是不会有两条命令被同时执行,不会产生并发问题。 </pre> 这就是 Redis 的单线程基本模型。 === Redis “单线程”到底指什么? === <pre> Redis 服务器通过 socket(套接字)与客户端或其他 Redis 服务器进行连接,而“文件事件”就是“服务器对 socket 操作的抽象”。服务器与客户端或其他服务器的通信会产生相应的文件事件,而服务器通过监听并处理这些事件来完成一系列网络通信操作。 </pre> Redis 基于“Reactor模式”开发了“网络事件处理器”,这个处理器被称为“'''文件事件处理器'''”: :: 文件事件处理器使用 '''I/O 多路复用'''程序来同时监听多个 socket,并根据 socket 目前执行的任务来为 socket 关联不同的事件处理器。当被监听的 socket 准备好执行连接应答、读取、写入、关闭等操作时,与操作相对应的文件事件就会产生,这时文件事件处理器就会调用 socket 之前已关联好的事件处理器来处理这些事件。 “文件事件处理器”的组成结构为4部分: # 多个套接字、 # IO多路复用程序、 # 文件事件分派器、 # 事件处理器。 结构如下: : [[File:Redis:“文件事件处理器结构”.png|800px]] 综上所述,“单线程”指的是:“文件事件处理器”分派器队列的消费是单线程的。正因为如此,所以 Redis 才叫单线程模型。 === 什么是“I/O多路复用”技术? === Redis 采用网络 I/O 多路复用技术,来保证在多连接的时候系统的高吞吐量。 <pre> 关于 I/O 多路复用(又被称为“事件驱动”),首先要理解的是: 操作系统为你提供了一个功能,当你的某个 socket 可读或者可写的时候,它可以给你一个通知。这样当配合非阻塞的 socket 使用时,只有当系统通知我哪个'''描述符'''可读了,我才去执行 read 操作,可以保证每次 read 都能读到有效数据而不做纯返回 -1 和 EAGAIN 的无用功,写操作类似。 操作系统的这个功能是通过 select / poll / epoll / kqueue 之类的“系统调用函数”来实现,这些函数都可以同时监视多个描述符的读写就绪状况,这样,【多个描述符的 I/O 操作都能在一个线程内并发交替地顺序完成,这就叫 I/O 多路复用。】 </pre> 简而言之,“I/O多路复用”就是'''复用一个线程来完成多路(多个socket)的 I/O 请求'''。 * 多路:指的是多个 socket 连接, * 复用:指的是复用同一个 Redis 处理线程。 * 多路复用主要有三种技术:select,poll,epoll。 ** epoll 是最新的也是目前最好的多路复用技术。 : [[File:Redis:“IO多路复用”技术.png|800px]] 采用多路 I/O 复用技术可以让单个线程高效的处理多个连接请求(尽量减少网络 I/O 的时间消耗),且 Redis 在内存中操作数据的速度非常快,也就是说内存内的操作不会成为影响 Redis 性能的瓶颈,基于这两点 Redis 具有很高的吞吐量。 == “Redis”为什么使用单线程 == Redis 利用队列技术将并发访问变为串行访问,消除了传统数据库串行控制的开销。 === 为什么使用单线程? === 官方答案: : 因为 Redis 是基于内存的操作,'''CPU 不是 Redis 的瓶颈''',Redis 的瓶颈最有可能是机器内存的大小或者网络带宽。既然单线程容易实现,而且 CPU 不会成为瓶颈,那就顺理成章地采用单线程的方案了。 具体来讲: # 单线程避免了不必要的:上下文切换(切换线程导致的 CPU 消耗)和竞争条件(对资源加锁,请求等待锁); # 单线程多进程的集群方案,相比于单机多线程更加有效; === 为什么不采用多进程或多线程处理? === # 多线程处理可能涉及到锁。 # 多线程处理会涉及到线程切换而消耗 CPU。 === 单线程处理的缺点? === # 耗时的命令会导致并发的下降,不只是读并发,写并发也会下降。 # 无法发挥多核 CPU 性能。 #* 不过可以通过'''在单机开多个 Redis 实例'''来完善。 === Redis 不存在线程安全问题? === Redis 采用了'''线程封闭'''的方式,把任务封闭在一个线程,自然避免了线程安全问题。 不过对于需要依赖多个 Redis 操作(即多个 Redis 操作命令)的复合操作来说,依然需要锁,而且有可能是'''分布式锁'''。【???】 == Redis 为什么快? == Redis 的高并发和快速原因: # '''基于内存''',内存的读写速度非常快。 # '''单线程''',避免了不必要的上下文切换(多进程切换消耗CPU)和竞争条件(多线程竞争资源需要加锁等待锁)。 # '''多路复用技术''',可以处理并发的连接。 #* 非阻塞 IO 的实现采用 '''epoll''':epoll 中的读、写、关闭、连接都转化成了事件,然后利用 epoll 的多路复用特性,减少网络 I/O 的时间消耗。 另外: # '''数据结构简单''',对数据操作也简单,Redis 中的数据结构是专门进行设计的。 # Redis 直接自己构建了 '''VM 机制''' ,因为一般的系统调用系统函数的话,会浪费一定的时间去移动和请求; == Redis 不仅仅是单线程 == 如上所述,一般来说 Redis 的瓶颈并不在 CPU,而在内存和网络。如果要使用 CPU 多核,可以'''搭建多个 Redis 实例'''来解决。 其实,Redis 4.0 开始就有多线程的概念了,比如 Redis 通过多线程方式在后台'''删除对象'''、以及'''通过 Redis 模块实现的阻塞命令'''等: : [[File:Redis:多线程.png|600px]] 另外,Redis 6 中也有多线程IO: : [[File:Redis:Threaded IO.png|600px]] 这个“Theaded IO”指的是在'''网络 IO''' 处理方面上了多线程,如网络数据的读写和协议解析等。 但,无论如何,'''执行命令的核心模块还是单线程的'''。 === 为什么网络处理要引入多线程? === 因为: :<pre>Redis 的瓶颈并不在 CPU,而在内存和网络”</pre> 内存不够的话,可以加内存或者做数据结构优化和其他优化等。 但网络的性能优化才是最大问题,网络 I/O 的读写在 Redis 整个执行期间占用了大部分的 CPU 时间,如果把网络处理这部分做成多线程处理方式,那对整个 Redis 的性能会有很大的提升。 Redis 单/多线程情况下的 get/set 操作性能做了对比: : [[File:Redis:单、多线程情况下的“get、set”性能对比_1.png|600px]] : [[File:Redis:单、多线程情况下的“get、set”性能对比_2.png|600px]] 从上面的性能测试图来看,多线程的性能几乎是单线程的两倍了。 * 6.0 版本中,IO 多线程处理模式默认是不开启的,需要去配置文件中开启并配置线程数。
返回至“
关于:Redis 到底是单线程还是多线程?
”。
导航菜单
个人工具
登录
命名空间
页面
讨论
大陆简体
已展开
已折叠
查看
阅读
查看源代码
查看历史
更多
已展开
已折叠
搜索
导航
首页
最近更改
随机页面
MediaWiki帮助
笔记
服务器
数据库
后端
前端
工具
《To do list》
日常
阅读
电影
摄影
其他
Software
Windows
WIKIOE
所有分类
所有页面
侧边栏
站点日志
工具
链入页面
相关更改
特殊页面
页面信息