IO 多路复用:C10K 问题
点击上方“Java基基”,选择“设为星标”
做积极的人,而不是积极废人!
每天 14:00 更新文章,每天掉亿点点头发...
源码精品专栏
原创 | Java 2021 超神之路,很肝~
中文详细注释的开源项目
RPC 框架 Dubbo 源码解析
网络应用框架 Netty 源码解析
消息中间件 RocketMQ 源码解析
数据库中间件 Sharding-JDBC 和 MyCAT 源码解析
作业调度中间件 Elastic-Job 源码解析
分布式事务中间件 TCC-Transaction 源码解析
Eureka 和 Hystrix 源码解析
Java 并发源码
来源:juejin.cn/post/
7158097493031567373
一、前言
C10K 问题
I/O
模型:同步、异步、阻塞、非阻塞I/O
多路复用:select/poll/epoll
1)
select
2)
poll
3)
epoll
C10M问题
一、前言
「本文围绕 C10K
问题展开,讲述 I/O
多路复用:」
「本文提要:」 发现总结C10K
问题 -> 操作系统内核支撑不足 -> 提出 I/O
多路复用。
基于 Spring Boot + MyBatis Plus + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能
项目地址:https://gitee.com/zhijiantianya/ruoyi-vue-pro
视频教程:https://doc.iocoder.cn/video/
C10K 问题
「背景:」 互联网刚开始普及、用户群体几何增长,但单机服务器性能无法被完全充分利用,要投入更多服务器
当时服务器采用 「
PPC
(Process Per Connection
)模型」 :指每次有新的连接就创建一个进程去专门处理这个连接。「
C10K
:」 有 1万个连接,服务器就要创建 1万个进程,当时单机操作系统无法承受(出现效率低下、甚至瘫痪)。在这情况下,「即使提高服务器配置,并发能力也不能线性提升:」 假设原单机能处理 1000 并发,现提高一倍服务器性能,单机处理并发达不到 2000。
「归结问题:如何突破单机性能局限」
「C10K
问题由来:」 这些局限和问题最早被 Dan Kegel
进行了归纳和总结,并成系统地分析和提出解决方案,后来这种普遍的网络现象和技术局限都被大家称为 C10K
问题。
「
C10K
问题的最大特点:」 设计不够良好的程序,其性能和连接数及机器性能的关系往往是非线性的。「
C10K
问题本质上:」 是 「操作系统」 的问题,传统的同步阻塞I/O
模型。
1.进程/线程上下文切换消耗大。
2.数据频繁拷贝。
3.创建进程/线程过多:进程是最昂贵资源。
「C10K
问题的解决方案:I/O
多路复用」 ,每个进程/线程能同时处理多个连接。
「I/O
多路复用,实现方式有多种:」
「
select
方式:」 有连接请求抵达再检查处理,查询所有文件句柄。「
poll
方式:」 设计新的数据结构,解决select
的两个问题。「
epoll
方式:」 只返回状态变化的文件句柄。
基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能
项目地址:https://gitee.com/zhijiantianya/yudao-cloud
视频教程:https://doc.iocoder.cn/video/
I/O
模型:同步、异步、阻塞、非阻塞
「再来回顾下 I/O
模型:」
「阻塞和非阻塞的区别:」 线程是否挂起。
「异步和同步的区别:」 主动与被动的通知方式。
「UNIX
网络编程 中定义 五种 I/O
模型:」
等待数据: 等待数据就绪,数据从网卡写入到内存。
「将数据从内核复制到用户空间:」 将数据从内核空间写到用户空间,这才能给应用使用。
根据上述定义,前4种模型都是同步 I/O
模型:因为真正的 I/O
操作(recvfrom
)将阻塞进程。
「问题来了:epoll
是异步非阻塞嘛?」
❝
「结论是:
epoll
是同步非阻塞。」网上很多说
epoll
是异步非阻塞,但我们从UNIX
这定义上来看:它就不是。那Linux
上加上MMAP
呢,这样在『数据从内核拷贝到用户空间』这一步不就省了嘛,那在这步就没有阻塞了,那就能算得上是 异步非阻塞。这个说法有点牵强,定义了模式了,具体实现是在这框定下进行。「
Tips
:epoll
里没有涉及MMAP
。」❞
「Reactor
是同步非阻塞网络模型」 。
❝
这个很好理解:因为还有一个
Proactor
模式。
Reactor
:关注写入事件和读取事件,需要应用程序自己完成读取或者写入数据。
Proactor
:关注写入完成事件和读取完成事件。❞
I/O
多路复用:select/poll/epoll
❝
这一趴,只介绍这三种方式:遇到什么问题、解决了什么问题、有什么缺陷。
❞
「首先是暴力法:直接循环每个连接(对应 socket
)」
当所有的
socket
都有数据时,这种方式是可行的。当应用读取某个
socket
时,没有数据,那么整个应用会阻塞在这。
1) select
❝
select
的提出是为了解决暴力法的阻塞问题。❞
「select
方案:」 在读取文件句柄之前,「先检查其状态」 ,ready
就处理。
用
fd_set_
结构体来存储文件句柄,表示内核同时关注这些句柄。用
FD_ISSET
方法来查看哪个文件句柄的状态发生了变化。
#define FD_SETSIZE 1024
#define NFDBITS (8 * sizeof(unsigned long))
#define __FDSET_LONGS (FD_SETSIZE/NFDBITS)// 结构体 (bitmap)
typedef struct {unsigned long fds_bits[__FDSET_LONGS];
} fd_set;// 返回值就绪描述符的数目
int select(int max_fd, fd_set *readset, fd_set *writeset, fd_set *exceptset, struct timeval *timeout // 阻塞时长
)FD_ZERO(int fd, fd_set* fds) // 清空集合, 置为 0
FD_SET(int fd, fd_set* fds) // 将给定的描述符加入集合, 某位置为 1
FD_ISSET(int fd, fd_set* fds) // 判断指定描述符是否在集合中, 某位是否为 1
FD_CLR(int fd, fd_set* fds) // 将给定的描述符从文件中删除,某位置为 0
「缺点有:」
「性能开销大:」 每次需要轮询
fd_set
每一位。「性能开销大:」 调用
select
时,需要将参数中fd_set
从用户空间拷贝到内核空间。「同时监听的文件句柄数量少:」 受限于
FD_SETSIZE
大小,一般 1024,编译内核时就确定了无法更改。
2) poll
「poll
主要解决 select
文件句柄数少的问题。」
解决方法:定义新的结构体。
在用户空间通过「数组」 方式传递文件描述符,在内核空间会转为「链表」 方式进行存储,所以没有最大数量的限制。
// 结构体
struct pollfd {int fd; // 需要监视的文件描述符short events; // 需要内核监视的事件short revents; // 实际发生的事件
};// API
int poll(struct pollfd fds[], nfds_t nfds, int timeout);
「缺点:同 select
。」
3) epoll
「epoll
解决了 select/poll
的缺点,成为了 C10K Killer
:」
「解决每次查询文件句柄:」
使用「红黑树」 存储文件句柄、使用「队列」 存储就绪的文件句柄。
通过事件更改文件描述符状态。
有红黑树存储,只需要传入一个需要检测的文件句柄,减少了内核和用户空间大量的数据拷贝和内存分配。
❝
「
Tips
:」 通过epoll
内核源码可知,epoll_wait()
没有使用MMAP
,__put_user
函数就是将数据从内核拷贝到用户空间。❞
// 结构体
struct eventpoll {...// 红黑树:监听列表,所有要监听的文件描述符,使用红黑树struct rb_root rbr;// 双链表:就绪列表,所有就绪的文件描述符,使用链表struct list_head rdlist;...
};// API
// 1. 创建 eventpoll 对象
int epoll_create(int size);
// 2. epoll_ctl 负责把 socket 增加、删除到内核红黑树
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
// 3. epoll_wait 检测双链表中是否有就绪的文件描述符,如果有,则返回
int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);
「
epoll_create()
:」 创建eventpoll
对象,同时返回引用该实例的文件句柄。「
epoll_ctl()
:」 会监听文件句柄fd
上发生的event
事件,op
表示对fd
执行的操作。
因为
epoll
内核维护一颗红黑树,新增和删除操作,复杂度为O(logn)
。
「epoll_wait()
:」 当有事件发生时,内核通过回调函数将这个文件句柄加入就绪队列中。
当被调用时,只会返回有事件发生的文件句柄的个数。
❝
「
Tips
:」 通过epoll
内核源码可知,epoll_wait()
没有使用MMAP
,__put_user
函数就是将数据从内核拷贝到用户空间。❞
epoll
支持两种事件触发模式:「边缘触发(Edge Trigger
,ET
)」 和 「水平触发(Level Trigger
,LT
)」
「边缘触发:」 当文件句柄就绪时,会触发通知,如果用户程序没有一次性把数据读/写完,下次还会发出可读/可写信号进行通知。(「重复通知」 )
「水平触发:」 仅当文件句柄从未就绪变为就绪时,「通知一次」 ,之后不会再通知。
区别:边缘触发效率更高,减少了事件被重复触发的次数,函数不会返回大量用户程序可能不需要的文件描述符。
❝
水平触发、边缘触发的名称来源:数字电路当中的电位水平,高低电平切换瞬间的触发动作叫边缘触发,而处于高电平的触发动作叫做水平触发。
❞
「各操作系统提供了功能为了解决 C10K
问题:」
FreeBSD
推出了kqueue
,Linux
推出了epoll
,Windows
推出了IOCP
,Solaris
推出了/dev/poll
。但每个接口都有自己的特点,程序移植困难,于是需要对这些接口进行封装,以便使用和移植。
libevent
库提供统一的API
,底层在不同平台上自动选择合适的调用。在以下操作系统中编译通过Linux
、BSD
、Mac OSX
、Solaris
和Windows
。
C10M问题
❝
既然
C10K
问题已经解决了,那就要考虑下C10M
问题了。❞
「实现 10M(即1千万)的并发连接挑战意味着什么」 :http://www.52im.net/thread-568-1-1.html
1千万的并发连接数;
100万个连接/秒:每个连接以这个速率持续约10秒;
10GB/秒的连接:快速连接到互联网;
1千万个数据包/秒:据估计目前的服务器每秒处理50K数据包,以后会更多;
10微秒的延迟:可扩展服务器也许可以处理这个规模(但延迟可能会飙升);
10微秒的抖动:限制最大延迟;
并发10核技术:软件应支持更多核的服务器(通常情况下,软件能轻松扩展到四核,服务器可以扩展到更多核,因此需要重写软件,以支持更多核的服务器)。
「解决思路:关键在于如何将功能逻辑做好恰当的划分」
「数据包直接传递到业务逻辑:」 目的减少
Linux
内核传输的链路。
解决方案:网卡问题,使用自己的驱动程序并管理它们,使适配器远离操作系统。
「多线程的核间绑定:」 每个线程绑定到特定处理核心,这样最大化使用核心 Cache
、实现无锁设计、避免进程切换消耗等。
解决方案:核绑定。
「内存:」 采用更适合的页大小,比如从 4K
到 2M
,一定程度上减少地址转换等的性能消耗。
解决方案:系统启动时,分配大内存、管理大内存页。
欢迎加入我的知识星球,一起探讨架构,交流源码。加入方式,长按下方二维码噢:
已在知识星球更新源码解析如下:
最近更新《芋道 SpringBoot 2.X 入门》系列,已经 101 余篇,覆盖了 MyBatis、Redis、MongoDB、ES、分库分表、读写分离、SpringMVC、Webflux、权限、WebSocket、Dubbo、RabbitMQ、RocketMQ、Kafka、性能测试等等内容。
提供近 3W 行代码的 SpringBoot 示例,以及超 6W 行代码的电商微服务项目。
获取方式:点“在看”,关注公众号并回复 666 领取,更多内容陆续奉上。
文章有帮助的话,在看,转发吧。
谢谢支持哟 (*^__^*)
IO 多路复用:C10K 问题相关推荐
- C10K问题与IO多路复用
epoll基本介绍 操作系统早期的IO都是阻塞式的,所以为了一个应用能够支持并发的IO操作,所以基本的做法就是每来一个IO请求,就创建一个线程来专门处理.当IO并发不大的情况,这中方式工作的很好 但随 ...
- 网络编程实战之高级篇, 彻底解决面试C10k问题, 高并发服务器, IO多路复用, 同时监视多个IO事件
目录 一.前言 二.IO多路复用的理解 三.IO多路复用的发展 select poll epoll 四.C10K服务端代码 五. 总结 一.前言 网络入门篇,从操作系统的层次推开网络大门 网络入门基 ...
- IO多路复用底层原理及源码解析
基本概念 1. 关于linux文件描述符 在Linux中,一切都是文件,除了文本文件.源文件.二进制文件等,一个硬件设备也可以被映射为一个虚拟的文件,称为设备文件.例如,stdin 称为标准输入文件, ...
- java基础巩固-宇宙第一AiYWM:为了维持生计,四大基础之OS_Part_2整起~IO们那些事【包括五种IO模型:(BIO、NIO、IO多路复用、信号驱动、AIO);零拷贝、事件处理及并发等模型】
PART0.前情提要: 通常用户进程的一个完整的IO分为两个阶段(IO有内存IO.网络IO和磁盘IO三种,通常我们说的IO指的是后两者!):[操作系统和驱动程序运行在内核空间,应用程序运行在用户空间, ...
- 网络编程—IO多路复用详解
假如你想了解IO多路复用,那本文或许可以帮助你 本文的最大目的就是想要把select.epoll在执行过程中干了什么叙述出来,所以具体的代码不会涉及,毕竟不同语言的接口有所区别. 基础知识 IO多路复 ...
- io多路复用·零拷贝·while死循环cpu
文章目录 引用文章 问题 io多路复用效率为什么这么高 epoll和select/poll什么时候用 epoll的LT和ET 从 jdk 的 nio 到 epoll 源码与实现内幕全面解析 io多路复 ...
- 漫谈五种IO模型(主讲IO多路复用)
首先引用levin的回答让我们理清楚五种IO模型 1.阻塞I/O模型 老李去火车站买票,排队三天买到一张退票. 耗费:在车站吃喝拉撒睡 3天,其他事一件没干. 2.非阻塞I/O模型 老李去火车站买票, ...
- Python:通过一个小案例深入理解IO多路复用
通过一个小案例深入理解IO多路复用 假如我们现在有这样一个普通的需求,写一个简单的爬虫来爬取校花网的主页 import requests import timestart = time.time()u ...
- 聊一个不常见的面试题:为什么数据库连接池不采用 IO 多路复用?
欢迎关注方志朋的博客,回复"666"获面试宝典 今天我们聊一个不常见的 Java 面试题:为什么数据库连接池不采用 IO 多路复用? 这是一个非常好的问题.IO多路复用被视为是非常 ...
最新文章
- CSP-S2019游记
- JavaScript基础15-day17【BOM(Navigator、History、Location)、定时器、切换图片练习、轮播图】
- StackExchange.Redis客户端读写主从配置,以及哨兵配置
- 进一步了解 apt-get 的几个命令
- oracle 添加监听地址,oracle批改监听地址为localhost
- 渗透测试入门6之权限提升
- 市场部和销售部的区别
- c语言小型编译器编写,小型C语言编译器设计(4页)-原创力文档
- 天气城市代码查询接口
- php怎么生成缩略图,php怎么生成缩略图
- 互联网大厂的“中台战略”到底是什么?
- xp无线网卡开启的服务器,无线网卡在 Windows XP 系统下的安装与使用过程
- 软件文档的作用和分类
- quartz mysql 表 集群配置_Quartz集群配置
- 解决克隆RHEL7后网络无法启动问题
- Win10找不到gpedit.msc|找不到本地组策略编辑器的解决方法
- OpenCV4萌新之路——详解图像读取函数 “imread”
- 管理SQL Server AlwaysOn(5)——常规监控(1)——常规监控
- vue/react的hash模式下的锚点效果
- css3 3d 与案例分析