博客昵称:架构师Cool
最喜欢的座右铭:一以贯之的努力,不得懈怠的人生。
作者简介:一名Coder,软件设计师/鸿蒙高级工程师认证,在备战高级架构师/系统分析师,欢迎关注小弟!
博主小留言:哈喽!各位CSDN的uu们,我是你的小弟Cool,希望我的文章可以给您带来一定的帮助
百万笔记知识库, 所有基础的笔记都在这里面啦,点击左边蓝字即可获取!助力每一位未来架构师!
欢迎大家在评论区唠嗑指正,觉得好的话别忘了一键三连哦!😘
Java类型所占字节数(或bit数)
| 类型 | 存储(byte) | bit数(bit) | 取值范围 |
|---|---|---|---|
| int | 4字节 | 4×8位 | 即 (-2)的31次方 ~ (2的31次方) - 1 |
| short | 2字节 | 2×8位 | 即 (-2)的15次方 ~ (2的15次方) - 1 |
| long | 8字节 | 8×8位 | 即 (-2)的63次方 ~ (2的63次方) - 1 |
| byte | 1字节 | 1×8位 | 即 (-2)的7次方 ~ (2的7次方) - 1,-128~127 |
| float | 4字节 | 4×8位 | float 类型的数值有一个后缀 F(例如:3.14F) |
| double | 8字节 | 8×8位 | 没有后缀 F 的浮点数值(例如:3.14)默认为 double |
| boolean | 1字节 | 1×8位 | true、false |
| char | 2字节 | 2×8位 | Java中,只要是字符,不管是数字还是英文还是汉字,都占两个字节 |
注意:
- 英文的数字、字母或符号:1个字符 = 1个字节数
- 中文的数字、字母或符号:1个字符 = 2个字节数
- 计算机的基本单位:bit 。一个bit代表一个0或1,1个字节是8个bit
- 1TB=1024GB,1GB=1024MB,1MB=1024KB,1KB=1024B(字节,byte),1B=8b(bit,位)
线程模型

Redis内部使用文件事件处理器File Event Handler,这个文件事件处理器是单线程的所以Redis才叫做单线程的模型。它采用I/O多路复用机制同时监听多个Socket,将产生事件的Socket压入到内存队列中,事件分派器根据Socket上的事件类型来选择对应的事件处理器来进行处理。文件事件处理器包含5个部分:
- 多个Socket
- I/O多路复用程序
- Scocket队列
- 文件事件分派器
- 事件处理器(连接应答处理器、命令请求处理器、命令回复处理器)

通信流程
客户端与redis的一次通信过程:

-
请求类型1:
客户端发起建立连接的请求- 服务端会产生一个
AE_READABLE事件,I/O多路复用程序接收到server socket事件后,将该socket压入队列中 - 文件事件分派器从队列中获取
socket,交给连接应答处理器,创建一个可以和客户端交流的socket01 - 将
socket01的AE_READABLE事件与命令请求处理器关联
- 服务端会产生一个
-
请求类型2:
客户端发起set key value请求socket01产生AE_READABLE事件,socket01压入队列- 将获取到的
socket01与命令请求处理器关联 - 命令请求处理器读取
socket01中的key value,并在内存中完成对应的设置 - 将
socket01的AE_WRITABLE事件与命令回复处理器关联
-
请求类型3:
服务端返回结果Redis中的socket01会产生一个AE_WRITABLE事件,压入到队列中- 将获取到的
socket01与命令回复处理器关联 - 回复处理器对
socket01输入操作结果,如ok。之后解除socket01的AE_WRITABLE事件与命令回复处理器的关联
文件事件处理器
- 基于 Reactor 模式开发了自己的网络事件处理器(文件事件处理器,file event handler)
- 文件事件处理器 使用 I/O 多路复用(multiplexing)程序来同时监听多个套接字,并根据套接字目前执行的任务来为套接字关联不同的事件处理器
- 当被监听的套接字准备好执行连接应答(accept)、读取(read)、写入(write)、关闭(close)等操作时, 与操作相对应的文件事件就会产生, 这时文件事件处理器就会调用套接字之前关联好的事件处理器来处理这些事件
- 文件事件处理器以单线程方式运行, 但通过使用 I/O 多路复用程序来监听多个套接字, 文件事件处理器既实现了高性能的网络通信模型, 又可以很好地与 redis 服务器中其他同样以单线程方式运行的模块进行对接, 这保持了 Redis 内部单线程设计的简单性
I/O多路复用
I/O多路复用的I/O是指网络I/O,多路指多个TCP连接(即socket或者channel),复用指复用一个或几个线程。意思说一个或一组线程处理多个TCP连接。最大优势是减少系统开销小,不必创建过多的进程/线程,也不必维护这些进程/线程。
I/O多路复用使用两个系统调用(select/poll/epoll和recvfrom),blocking I/O只调用了recvfrom;select/poll/epoll 核心是可以同时处理多个connection,而不是更快,所以连接数不高的话,性能不一定比多线程+阻塞I/O好,多路复用模型中,每一个socket,设置为non-blocking,阻塞是被select这个函数block,而不是被socket阻塞的。
select机制
基本原理
客户端操作服务器时就会产生这三种文件描述符(简称fd):writefds(写)、readfds(读)、和exceptfds(异常)。select会阻塞住监视3类文件描述符,等有数据、可读、可写、出异常 或超时、就会返回;返回后通过遍历fdset整个数组来找到就绪的描述符fd,然后进行对应的I/O操作。
优点
- 几乎在所有的平台上支持,跨平台支持性好
缺点
- 由于是采用轮询方式全盘扫描,会随着文件描述符FD数量增多而性能下降
- 每次调用 select(),需要把 fd 集合从用户态拷贝到内核态,并进行遍历(消息传递都是从内核到用户空间)
- 默认单个进程打开的FD有限制是1024个,可修改宏定义,但是效率仍然慢。
poll机制
基本原理与select一致,也是轮询+遍历;唯一的区别就是poll没有最大文件描述符限制(使用链表的方式存储fd)。
epoll机制
基本原理
没有fd个数限制,用户态拷贝到内核态只需要一次,使用时间通知机制来触发。通过epoll_ctl注册fd,一旦fd就绪就会通过callback回调机制来激活对应fd,进行相关的io操作。epoll之所以高性能是得益于它的三个函数:
epoll_create():系统启动时,在Linux内核里面申请一个B+树结构文件系统,返回epoll对象,也是一个fdepoll_ctl():每新建一个连接,都通过该函数操作epoll对象,在这个对象里面修改添加删除对应的链接fd, 绑定一个callback函数epoll_wait():轮训所有的callback集合,并完成对应的IO操作
优点
- 没fd这个限制,所支持的FD上限是操作系统的最大文件句柄数,1G内存大概支持10万个句柄
- 效率提高,使用回调通知而不是轮询的方式,不会随着FD数目的增加效率下降
- 内核和用户空间mmap同一块内存实现(mmap是一种内存映射文件方法,即将一个文件或其它对象映射到进程的地址空间)
例子:100万个连接,里面有1万个连接是活跃,我们可以对比 select、poll、epoll 的性能表现:
select:不修改宏定义默认是1024,则需要100w/1024=977个进程才可以支持 100万连接,会使得CPU性能特别的差poll: 没有最大文件描述符限制,100万个链接则需要100w个fd,遍历都响应不过来了,还有空间的拷贝消耗大量资源epoll: 请求进来时就创建fd并绑定一个callback,主需要遍历1w个活跃连接的callback即可,即高效又不用内存拷贝
执行效率高
Redis是单线程模型为什么效率还这么高?
纯内存操作:数据存放在内存中,内存的响应时间大约是100纳秒,这是Redis每秒万亿级别访问的重要基础非阻塞的I/O多路复用机制:Redis采用epoll做为I/O多路复用技术的实现,再加上Redis自身的事件处理模型将epoll中的连接,读写,关闭都转换为了时间,不在I/O上浪费过多的时间C语言实现:距离操作系统更近,执行速度会更快单线程避免切换开销:单线程避免了多线程上下文切换的时间开销,预防了多线程可能产生的竞争问题
Redis单线程模型下的高效I/O多路复用
文章介绍了Java中各种类型所占的字节数,接着详细阐述了Redis的线程模型,特别是其文件事件处理器如何利用I/O多路复用机制实现高性能。重点讨论了I/O多路复用中的select、poll和Epoll机制,并指出Redis使用Epoll的原因,以及单线程模型如何提高效率。

被折叠的 条评论
为什么被折叠?



