温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

服务端的多路复用如何解决连接高并发问题

发布时间:2021-12-06 17:31:22 来源:亿速云 阅读:208 作者:柒染 栏目:互联网科技

服务端的多路复用如何解决连接高并发问题,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。

在淘宝上购物,比如双11秒杀某个商品,对后台都是一次考验。一个网站系统,在很短时间内收到巨量请求时,稳定性至关重要,用户都不喜欢看自己的app老是转菊花。具体的后台并发详见前文:大白话描述淘宝服务端分布式架构演进之路----系列一大白话分布式系统演进之路----系列二

这里先不讲策略性的东西,讲讲socket层面多连接下的并发问题。先来看I/O操作,调用read可以从流中读入数据,调用write可以往流写入数据。那么如果调用read,但流中没有数据怎么办呢?只能使用阻塞I/O。对于服务端,有多个连接的情况,如果一个描述符fd阻塞了,导致另一个描述符fd即使收到数据也无法处理。对于这种情况,就得采用特殊方法处理。

一种方法是使用多进程,可使每个进程都执行阻塞read,但是进程间的信号同步就比较麻烦。

服务端的多路复用如何解决连接高并发问题

另一种办法就是使用一个进程执行程序,使用非阻塞I/O读取数据。采用轮询方式读取所有套接字是否能收到数据。这种方法不足之处就是浪费CPU的计算资源。

       这里要说的就是I/O多路复用,也就是poll、epoll、pselect、select这几个调用。可以通过以太驱动程序来大概看一下网卡接收数据的过程:

服务端的多路复用如何解决连接高并发问题

MAC网卡接收到数据包后通过DMA写入内存约定地址(这里如果刚好内存的数据缓存在cache里,就有DMA和Cache数据不一致的问题,不过这里不是本文重点),然后触发硬件中断通知CPU,CPU调用中断程序读取内存中的数据。

       接下来可以看看操作系统如何通过select来实现多个socket的读写操作。前文讲过进程调度的几种方式:进程调度与fork,大致就是操作系统会维护一个队列(假定任务优先级相同),任务调度器按顺序捞取队列上的任务执行:

服务端的多路复用如何解决连接高并发问题

当任务A创建socket时,操作系统会创建一个socket对象(一切描述符都是文件)。这个socket对象里面包含了发送接收缓冲区、任务等待队列等成员。参考lwip的实现:

服务端的多路复用如何解决连接高并发问题

创建socket:

服务端的多路复用如何解决连接高并发问题

进程A当执行read时,由于无数据可读,进程A由运行态变为阻塞态,操作系统会把进程A挂在socket的等待队列下,并从工作队列移除,这个时候只有进程B和C占用CPU资源。

服务端的多路复用如何解决连接高并发问题

这里要注意,并非直接把进程A挂接在等待队列下,而是把进程A的邮箱recvbox挂上去了:

服务端的多路复用如何解决连接高并发问题

       当接收到数据时,任务调度器会将进程A设置为就绪态并挂到工作队列中,重新接受任务调度。

那么,服务器需要管理多条连接,而一个read/recv只能阻塞一个socket,这里就用到了select。这里不放代码,而是直接用图说明:

服务端的多路复用如何解决连接高并发问题

进程A会监视所有的socket,任何一个连接收到数据后,中断程序都会唤醒等待队列上的进程,然后只有真正收到数据的那个进程运行,其余进程继续阻塞。这个就是服务器的”惊群”现象。

有没有更合适的方法监听事件呢?答案是epoll

epoll的接口如下:

int epoll_create(int size);//创建一个epoll的句柄,size为监听的数目int epoll_ctl(int epfd, int op, int fd,struct epoll_event *event);int epoll_wait(int epfd, struct epoll_event* events, int maxevents, int timeout);

select的缺点就是进程不知道哪些sock收到了数据,因此只能遍历所有sock。而epoll维护了一个就绪列表,引用收到数据的socket,可以避免遍历:

服务端的多路复用如何解决连接高并发问题

当进程调用epoll_create时,会创建一个 eventpoll 对象。eventpoll对象与socket对象类似,也有等待数组。然后进程可以使用epoll_ctl添加所要监听的socket,内核会将eventpoll添加到socket的等待队列中。

服务端的多路复用如何解决连接高并发问题

当socket收到数据后,中断程序会给eventpoll的“就绪列表”添加发生事件的socket序号,如sock2上面收到了数据,就把2写入eventpoll的rdlist数组里面:

服务端的多路复用如何解决连接高并发问题

       当进程执行epoll_wait时,如果rdlist里面有socket,那么epoll_wait直接返回,否则阻塞进程,阻塞的进程挂在eventpoll的等待队列下面,如下面的图表示进程A和进程F被阻塞:

服务端的多路复用如何解决连接高并发问题

收到数据时,中断程序将对应的socket序号写入rdlist,同时唤醒eventpoll 等待队列中的进程,进程A和F进入运行状态。

关于服务端的多路复用如何解决连接高并发问题问题的解答就分享到这里了,希望以上内容可以对大家有一定的帮助,如果你还有很多疑惑没有解开,可以关注亿速云行业资讯频道了解更多相关知识。

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI