redis:深剖redis的单线程架构
redis使用了单线程架构和IO多路复用模型来实现高性能的内存数据库服务
单线程模型
现在开启了三个redis-cli客户端同时执行命令
客户端1设置了一个字符串键值对
set hello world
客户端2对counter自增
incr counter
客户端3对counter自增
incr counter
redis客户端和服务端的模型可以简化成下图,每次客户端调用都经历了发送命令、执行命令、返回结果三个过程我们说的单线程就是在第二步执行命令,一条命令从从客户端达到服务端不会立刻被执行,而是会进入一个队列中等待,每次只会有一条指令被选中执行。上面三个客户端命令的执行顺序是不确定的,如下图。
但是可以确定不会同时有两条命令被同时执行,如下图。所以两条incr命令无论怎么怎么执行都不会有并发问题
为什么单线程还能怎么块
为什么单线程还能怎么块
- 第一:纯内存访问,redis将所有数据放在内存中,内存的响应时长大约为100纳秒,这是Redis达到每秒万级别访问的最重要的基础。
- 第二:非阻塞IO,redis使用epoll作为IO多路复用技术的实现,在加上redis自身的事件处理模型将epoll中的连接、读写、关闭都转换为事件,不在网络IO浪费时间
这里再扩展一下I/O多路复用:
引用知乎上一个高赞的回答来解释什么是I/O多路复用。假设你是一个老师,让30个学生解答一道题目,然后检查学生做得是否正确,你有下面几个选择:
- 第一种选择:按顺序逐个检查,先检查A,然后是B,之后是C、D。。。这中间如果有一个学生卡主,全班都会被耽误。这种模式就好比,你用循环挨个处理socket,根本不具有并发能力。
- 第二种选择:你创建30个分身,每个分身检查一个学生的答案是否正确。 这种类似于为每一个用户创建一个进程或者线程处理连接。
- 第三种选择,你站在讲台上等,谁解答完谁举手。这时C、D举手,表示他们解答问题完毕,你下去依次检查C、D的答案,然后继续回到讲台上等。此时E、A又举手,然后去处理E和A。
第一种就是阻塞IO模型,第三种就是I/O复用模型,Linux下的select、poll和epoll就是干这个的。将用户socket对应的fd注册进epoll,然后epoll帮你监听哪些socket上有消息到达,这样就避免了大量的无用操作。此时的socket应该采用非阻塞模式。
这样,整个过程只在调用select、poll、epoll这些调用时才会阻塞,收发客户消息是不会阻塞的,整个进程或者线程就被充分利用起来,这就是事件启动,所谓的reactor模式
- 第三:单线程可以简化数据结构和算法的实现;单线程避免了线程切换和竞态产生的消耗
对于服务器开发来说,锁和线程切换通常是性能杀手
单线程带来的问题
对于每个命令的执行时间是由要求的。如果某个命令执行过长,会造成其他命令的阻塞,对于redis这样的高性能服务来说是致命的,所以redis是面向快速执行场景的服务器
支持多线程的Redis6.0
Redis6.0引入了多线程的特性,这个多线程是在哪里呢?—— 是对处理网络请求过程采用了多线程
redis6.0采用多个IO线程来处理网络请求,网络请求的解析可以由线程完成,然后把解析后的请求交给主线程进行实际的内存读写。提升网络请求处理的并行度,进而提升整体性能
还没有评论,来说两句吧...