百万笔记知识库 所有基础的笔记都在这里面啦点击左边蓝字即可获取助力每一位未来架构师欢迎大家在评论区唠嗑指正觉得好的话别忘了一键三连哦文章目录线程模型通信流程文件事件处理器I/O多路复用执行效率高Java类型所占字节数或bit数类型存储(byte)bit数(bit)取值范围int4字节4×8位即 (-2)的31次方 ~ (2的31次方) - 1short2字节2×8位即 (-2)的15次方 ~ (2的15次方) - 1long8字节8×8位即 (-2)的63次方 ~ (2的63次方) - 1byte1字节1×8位即 (-2)的7次方 ~ (2的7次方) - 1-128~127float4字节4×8位float 类型的数值有一个后缀 F例如3.14Fdouble8字节8×8位没有后缀 F 的浮点数值例如3.14默认为 doubleboolean1字节1×8位true、falsechar2字节2×8位Java中只要是字符不管是数字还是英文还是汉字都占两个字节注意英文的数字、字母或符号1个字符 1个字节数中文的数字、字母或符号1个字符 2个字节数计算机的基本单位bit 。一个bit代表一个0或11个字节是8个bit1TB1024GB1GB1024MB1MB1024KB1KB1024B字节byte1B8bbit位线程模型Redis内部使用文件事件处理器File Event Handler这个文件事件处理器是单线程的所以Redis才叫做单线程的模型。它采用I/O多路复用机制同时监听多个Socket将产生事件的Socket压入到内存队列中事件分派器根据Socket上的事件类型来选择对应的事件处理器来进行处理。文件事件处理器包含5个部分多个SocketI/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只调用了recvfromselect/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/1024977个进程才可以支持 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语言实现距离操作系统更近执行速度会更快单线程避免切换开销单线程避免了多线程上下文切换的时间开销预防了多线程可能产生的竞争问题