Redis—网络模型
目录
Redis网络模型
1、用户空间和内核空间
为了避免用户应用导致冲突甚至内核崩溃,用户应用与内核是分离的:
-
进程的寻址空间会划分为两部分:内核空间、用户空间
-
用户空间智能执行受限的命令(Ring3),而且不能直接调用系统资源,必须通过内核提供的接口来访问
-
内核空间可以执行特权命令(Ring0),调用一切系统资源
Linux系统为了提供IO效率,会在用户空间和内核空间加入缓冲区:
-
写数据时,把用户缓冲数据拷贝到内核缓冲区,然后写入设备
-
读数据时,从设备读取数据到内核缓冲区,然后拷贝到用户缓冲区

阻塞IO
阻塞IO就是两个阶段都必须阻塞等待:

非阻塞IO
非阻塞IO的recvfrom操作会立即返回结果而不是阻塞用户进程

非阻塞IO模型中,用户进程在第一个阶段是非阻塞,第二个阶段是阻塞状态。虽然是非阻塞,但性能并没有得到提高。
相反可能导致CPU使用率暴增
2、IO多路复用
文件描述符:简称FD,是一个从0开始递增的无符号整数,用来关联linux中的一个文件。在linux中,一切皆为文件。
IO多路复用:是利用单个线程来同时监听多个FD,并在某个FD可读、可写时得到通知,从而避免无效的等待

监听FD的方式、通知的方式有多种实现,常见的有:
-
select(linux最早的IO多路复用)
-
poll
-
epoll
差异:
1、select和poll只会通知用户进程有FD就绪,但不确定具体哪个FD,需要用户进程逐个遍历FD来确定
2、epoll则会在通知用户进程FD就绪的同时,把已就绪的FD写入用户空间
事件通知机制
当FD有数据可读时,我们调用epoll_wait就可以得到通知。
事件通知分为两种:
LevelTriggered: 简称LT。当FD有数据可读时,会重复通知多次,直至数据处理完成。是Epoll默认模式
EdgeTriggered:简称ET。当FD有数据可读时,只会被通知一次,不管数据是否处理完成
基于epoll模式的web服务基本流程图:

信号驱动IO
信号驱动IO是与内核建立SIGIO的信号关联并设置回调,当内核有FD就绪时,会发出SIGIO信号通知用户,期间用户应用可以执行其他业务,无需阻塞等待
缺点:
1、当有大量IO操作时,信号较多,SIGIO处理函数不能及时处理可能导致信号队列溢出
2、内核空间与用户空间的频繁信息交互新能低
异步IO
异步IO的整个过程都是非阻塞,用户进程调用完异步API后就可以做其他事情,内核等待数据就绪并拷贝到用户空间后才会递交信号,通知用户进程

Redis网络模型(面试)
Redis到底是单线程还是多线程?
-
如果仅仅聊Redis的核心业务部分(命令处理),是单线程
-
如果是聊整个Redis,答应就是多线程
💖在Redis版本迭代过程中,在两个重要的时间节点上引入了多线程的支持:
Redis v4.0 :引入多线程异步处理一些耗时较长的任务,例如异步删除命令unlink
Redis v6.0:在核心网络模型中引入多线程,进一步提高对于多核CPU的利用率
为什么Redis要选择单线程?
😎抛开持久化不谈,Redis是纯内存操作,执行速度非常快,它的性能瓶颈是网络延迟而不是执行速度,因此多线程并不会带来巨大性能提升
😁多线程会导致过多的上下文的切换,带来不必要的开销
❤️引入多线程会面临线程安全问题,必然要引入线程锁这样安全手段,实现复杂度增高,而且性能也会大打折扣
Redis单线程整个网络模型:
Redis6.0版本引入多线程,目的是为了提高IO读写效率。因此在解析客户端命令、写响应结果采用了多线程。
核心的命令执行、IO多路复用模块依然是由主线程执行
3、Redis通信协议
RESP协议
Redis是一个CS架构软件,通信一般分为两步(不包括pipeline和PubSub):
1、客户端(client)向服务端(server)发送一条命令
2、服务端解析并执行命令,返回响应结果给客户端
-
因此客户端发送命令的格式、服务端响应结果的格式必须有一个规范,这个规范就是通信协议
在Redis中采用的是RESP协议:
😀Redis 1.2版本引入RESP协议
😁Redis 2.0版本中成为与Redis服务端通信的标准,称为RESP2
😆Redis 6.0版本中,从RESP2升级到RESP3协议,增加了更多数据类型并且支持6.0的新特性——客户端缓存
RESP协议—数据类型:
在RESP协议中,通过首字节的字符来区分不同数据类型,常用的数据类型有5种:
| 类型 | 首字节 | 格式示例 | 说明 |
|---|---|---|---|
| 单行字符串 | + |
+OK\r\n |
简单状态回复,如 "OK" |
| 错误信息 | - |
-Error msg\r\n |
错误回复,如 "-ERR unknown command" |
| 整数 | : |
:100\r\n |
数字回复,如 :1 |
| 多行字符串 | $ |
$5\r\nhello\r\n |
二进制安全的字符串$0\r\n\r\n 表示空串$-1\r\n 表示 null/不存在 |
| 数组 | * |
*2\r\n$5\r\nhello\r\n$5\r\nworld\r\n |
多个元素的组合,用于命令和回复 |

更多推荐


所有评论(0)