Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >单机高并发模型设计

单机高并发模型设计

作者头像
方丈的寺院
发布于 2022-11-08 05:21:59
发布于 2022-11-08 05:21:59
66400
代码可运行
举报
文章被收录于专栏:方丈的寺院方丈的寺院
运行总次数:0
代码可运行

背景

微服务架构下,我们习惯使用多机器、分布式存储、缓存去支持一个高并发的请求模型,而忽略了单机高并发模型是如何工作的。这篇文章通过解构客户端与服务端的建立连接和数据传输过程,阐述下如何进行单机高并发模型设计。

经典C10K问题

如何在一台物理机上同时服务10K用户,及10000个用户,对于java程序员来说,这不是什么难事,使用netty就能构建出支持并发超过10000的服务端程序。那么netty是如何实现的?首先我们忘掉netty,从头开始分析。每个用户一个连接,对于服务端就是两件事

  1. 管理这10000个连接
  2. 处理10000个连接的数据传输

TCP连接与数据传输

连接建立

我们以常见TCP连接为例。

一张很熟悉的图。这篇重点在服务端分析,所以先忽略客户端细节。服务器端通过创建socket,bind端口,listen准备好了。最后通过accept和客户端建立连接。得到一个connectFd,即连接套接字(在Linux都是文件描述符),用来唯一标识一个连接。之后数据传输都基于这个。

数据传输

为了进行数据传输,服务端开辟一个线程处理数据。具体过程如下

  1. select应用程序向系统内核空间,询问数据是否准备好(因为有窗口大小限制,不是有数据,就可以读),数据未准备好,应用程序一直阻塞,等待应答。
  2. read内核判断数据准备好了,将数据从内核拷贝到应用程序,完成后,成功返回。
  3. 应用程序进行decode,业务逻辑处理,最后encode,再发送出去,返回给客户端

因为是一个线程处理一个连接数据,对应的线程模型是这样

多路复用

阻塞vs非阻塞

因为一个连接传输,一个线程,需要的线程数太多,占用的资源比较多。同时连接结束,资源销毁。又得重新创建连接。所以一个自然而然的想法是复用线程。即多个连接使用同一个线程。这样就引发一个问题, 原本我们进行数据传输的入口处,,假设线程正在处理某个连接的数据,但是数据又一直没有好时,因为 select是阻塞的,这样即使其他连接有数据可读,也读不到。所以不能是阻塞的,否则多个连接没法共用一个线程。所以必须是非阻塞的。

轮询 VS 事件通知

改成非阻塞后,应用程序就需要不断轮询内核空间,判断某个连接是否ready.

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
for (connectfd fd:  connectFds) {
    if (fd.ready) {
        process()}
}

轮询这种方式效率比较低,非常耗CPU,所以一种常见的做法就是被调用方发事件通知告知调用方,而不是调用方一直轮询。这就是IO多路复用,一路指的就是标准输入和连接套接字。通过提前注册一批套接字到某个分组中,当这个分组中有任意一个IO事件时,就去通知阻塞对象准备好了。

select/poll/epoll

IO多路复用技术实现常见有select,poll。select与poll区别不大,主要就是poll没有最大文件描述符的限制。

从轮询变成事件通知,使用多路复用IO优化后,虽然应用程序不用一直轮询内核空间了。但是收到内核空间的事件通知后,应用程序并不知道是哪个对应的连接的事件,还得遍历一下

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
onEvent({
// 监听到事件
    for (connectfd fd:  registerConnectFds) {
        if (fd.ready) {
            process()}
    }
}

可预见的,随着连接数增加,耗时在正比增加。相比较poll返回的是事件个数,epoll返回是有事件发生的connectFd数组,这样就避免了应用程序的轮询。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
onEvent({
// 监听到事件
    for (connectfd fd: readyConnectFds) {
       process()}
}

当然epoll的高性能不止是这个,还有边缘触发(edge-triggered),就不在本篇阐述了。

非阻塞IO+多路复用整理流程如下:

  1. select应用程序向系统内核空间,询问数据是否准备好(因为有窗口大小限制,不是有数据,就可以读),直接返回,非阻塞调用。
  2. 内核空间中有数据准备好了,发送ready read给应用程序
  3. 应用程序读取数据,进行decode,业务逻辑处理,最后encode,再发送出去,返回给客户端

线程池分工

上面我们主要是通过非阻塞+多路复用IO来解决局部的 selectread问题。我们再重新梳理下整体流程,看下整个数据处理过程可以如何进行分组。这个每个阶段使用不同的线程池来处理,提高效率。首先事件分两种

  1. 连接事件 accept动作来处理
  2. 传输事件 selectread, send 动作来处理。 连接事件处理流程比较固定,无额外逻辑,不需要进一步拆分。传输事件 readsend是相对比较固定的,每个连接的处理逻辑相似,可以放在一个线程池处理。而具体逻辑 decode, logic, encode 各个连接处理逻辑不同。整体可以放在一个线程池处理。

服务端拆分成3部分

  1. reactor部分,统一处理事件,然后根据类型分发
  2. 连接事件分发给acceptor,数据传输事件分发给handler
  3. 如果是数据传输类型,handler read完再交给processorc处理

因为1,2处理都比较快,放在线程池处理,业务逻辑放在另外一个线程池处理。

以上就是大名鼎鼎的reactor高并发模型。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-07-07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 方丈的寺院 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Netty基础—1.网络编程基础一
OSI是Open System Interconnect的简称,即开放系统互连参考模型。OSI为开放系统的计算机互连提供了一个共同的基础和标准框架,并为保持相关标准的一致性和兼容性提供了共同的参考。
东阳马生架构
2025/05/16
440
python3--IO模型,阻塞,非阻塞,多路复用,异步,selectors模块
结论:协程任务开启,并不一定会执行,它需要I/O(阻塞)才能执行,上面代码的time.sleep(1)模拟了I/O(阻塞)
py3study
2018/08/02
1.2K0
​网络 IO 演变发展过程和模型介绍
作者:jaydenwen,腾讯 pcg 后台开发工程师 在互联网中提起网络,我们都会避免不了讨论高并发、百万连接。而此处的百万连接的实现,脱离不了网络 IO 的选择,因此本文作为一篇个人学习的笔记,特此进行记录一下整个网络 IO 的发展演变过程。以及目前广泛使用的网络模型。 1.网络 IO 的发展 在本节内容中,我们将一步一步介绍网络 IO 的演变发展过程。介绍完发展过程后,再对网络 IO 中几组容易混淆的概念进行对比、分析。 1.1 网络 IO 的各个发展阶段 通常,我们在此讨论的网络 IO 一
腾讯技术工程官方号
2021/02/25
1.6K0
阻塞、非阻塞、多路复用、同步、异步、BIO、NIO、AIO 一锅端
本文会涉及到阻塞、非阻塞、多路复用、同步、异步、BIO、NIO、AIO等几个知识点,知识点虽然不难但经常容易搞混,这次带领大家再回顾一遍。
码农编程进阶笔记
2021/07/20
4150
阻塞、非阻塞、多路复用、同步、异步、BIO、NIO、AIO 一锅端
I/O多路复用,从来没遇到过这么明白的文章
很多对技术有追求的读者朋友,做到一定阶段后都希望技术有所精进。有些读者朋友可能会研究一些中间件的技术架构和实现原理。比如,Nginx为什么能同时支撑数万乃至数十万的连接?为什么单工作线程的Redis性能比多线程的Memcached还要强?Dubbo的底层实现是怎样的,为什么他的通信效率非常高?
用户7927337
2021/06/25
8010
I/O多路复用,从来没遇到过这么明白的文章
I/O的内核原理与5种I/O模型
我们都知道unix世界里、一切皆文件、而文件是什么呢?文件就是一串二进制流而已、不管socket、还是FIFO、管道、终端、对我们来说、一切都是文件、一切都是流、在信息交换的过程中、我们都是对这些流进行数据的收发操作、简称为I/O操作(input and output)、往流中读出数据、系统调用read、写入数据、系统调用write、不过话说回来了、计算机里有这么多的流、我怎么知道要操作哪个流呢?做到这个的就是文件描述符、即通常所说的fd(file descriptor)、一个fd就是一个整数、所以对这个整数的操作、就是对这个文件(流)的操作、我们创建一个socket、通过系统调用会返回一个文件描述符、那么剩下对socket的操作就会转化为对这个描述符的操作、不能不说这又是一种分层和抽象的思想、
小柒吃地瓜
2020/04/21
2.1K0
I/O的内核原理与5种I/O模型
I/O 模型如何演进及 I/O 多路复用是什么?
I/O 是 Input/Ouput 的缩写,即输入输出端口,是信息处理系统(例如计算机)与外部世界(可能是人类或另一信息处理系统)之间的通信。输入是系统接收的信号或数据,输出则是从其发送的信号或数据。
五月君
2019/08/13
7510
超详细的I/O多路复用概念、常用I/O模型、系统调用等介绍
I/O多路复用,I/O就是指的我们网络I/O,多路指多个TCP连接(或多个Channel),复用指复用一个或少量线程。串起来理解就是很多个网络I/O复用一个或少量的线程来处理这些连接。
lyb-geek
2021/09/23
2.1K0
详解Java中的五种IO模型
我们电脑上跑着的应用程序,其实是需要经过操作系统,才能做一些特殊操作,如磁盘文件读写、内存的读写等等。因为这些都是比较危险的操作,不可以由应用程序乱来,只能交给底层操作系统来。
Java微观世界
2025/01/21
1050
详解Java中的五种IO模型
一文搞懂什么是阻塞IO、信号驱动IO、Reactor模型、零拷贝
公众号《鲁大猿》 ,寻精品资料,帮你构建Java全栈知识体系 http://www.jiagoujishu.cn
鲁大猿
2024/01/05
4470
一文搞懂什么是阻塞IO、信号驱动IO、Reactor模型、零拷贝
一口气说出 5 种 IO 模型,蒙圈了!
recvfrom Linux系统提供给用户用于接收网络IO的系统接口。从套接字上接收一个消息,可同时应用于面向连接和无连接的套接字。
用户1516716
2021/04/13
8230
一口气说出 5 种 IO 模型,蒙圈了!
Linux五大网络模型之I/O多路复用浅入深出
清·俞樾《湖楼笔谈》六:“盖诗人用意之妙,在乎深入显出。入之不深,则有浅易之病;出之不显,则有艰涩之患。”
翎野君
2023/05/12
6150
Linux五大网络模型之I/O多路复用浅入深出
这次 moon 要把网络 I/O 一网打尽
大家好,我是 moon,上一次和大家聊了一下 socket(这次 moon 要把 socket 玩的明明白白),相信大家对 socket 有了一定的认识,对于 socket 还不熟悉的同学,可以先看看 socket 这篇文章,今天这篇文章是基于 socket,再和大家讲一讲「网络I/O」相关的知识,也刚好为后续 netty 的文章做下铺垫
moon聊技术
2022/05/27
3390
这次 moon 要把网络 I/O 一网打尽
网络基础篇-网络编程
在内核中,为每个socket维护两个队列,一个是已建立连接的队列,也就是完成了三次握手,处于established状态,一个是还没有完全建立连接的队列,处于sync_rcvd状态。
Check King
2021/08/09
7430
Python之IO模型
IO模型介绍 为了更好地了解IO模型,我们需要事先回顾下:同步、异步、阻塞、非阻塞     同步(synchronous) IO和异步(asynchronous) IO,阻塞(blocking) IO和非阻塞(non-blocking)IO分别是什么,到底有什么区别?这个问题其实不同的人给出的答案都可能不同,比如wiki,就认为asynchronous IO和non-blocking IO是一个东西。这其实是因为不同的人的知识背景不同,并且在讨论这个问题的时候上下文(context)也不相同。所以,为了更好
新人小试
2018/04/12
1K0
Python之IO模型
后台开发-核心技术与应用实践--网络模型与网络调试
IO 有两种操作,同步 IO 和 异步 IO。同步 IO 指的是,必须等待 IO 操作完成后,控制权才返回给用户进程。异步 IO 是,无须等待 IO 操作完成,就将控制权返回给用户进程。
范中豪
2021/04/15
6610
后台开发-核心技术与应用实践--网络模型与网络调试
一文读懂Redis中的多路复用模型
首先,Redis 是跑在单线程中的,所有的操作都是按照顺序线性执行的,但是由于读写操作等待用户输入或输出都是阻塞的,所以 I/O 操作在一般情况下往往不能直接返回,这会导致某一文件的 I/O 阻塞导致整个进程无法对其它客户提供服务,而 I/O 多路复用就是为了解决这个问题而出现的。
用户2781897
2021/04/02
1K0
Python入门之并发编程IO模型
了解新知识之前需要知道的一些知识 同步(synchronous):一个进程在执行某个任务时,另外一个进程必须等待其执行完毕,才能继续执行 #所谓同步,就是在发出一个功能调用时,在没有得到结果之前,该调用就不会返回。 #按照这个定义,其实绝大多数函数都是同步调用。 #但是一般而言,我们在说同步、异步的时候,特指那些需要其他部件协作或者需要一定时间完#成的任务。 #举例: #1. multiprocessing.Pool下的apply #发起同步调用后,就在原地等着任务结束, #根本不考虑任务是在计算还是在io
Jetpropelledsnake21
2018/06/14
6070
重大事故!IO问题引发线上20台机器同时崩溃
几年前的一个下午,公司里码农们正在安静地敲着代码,突然很多人的手机同时“哔哔”地响了起来。本来以为发工资了,都挺高兴!打开一看,原来是告警短信
cxuan
2020/04/22
2.2K0
Linux IO 模型
先抛出一个问题,基于此问题引出文章的主题:1999 年 Dan Kegel 在其个人站点提出了 C10K问题,首字母 C 是 Client 的缩写,C10K 即单机同时处理 1 万个连接的问题。C10K 表示处理 10000 个并发连接,注意这里的并发连接和每秒请求数不同,虽然它们是相似的,每秒处理许多请求需要很高的吞吐量(快速处理它们),但是更大数量的并发连接需要高效的连接调度,即 I/O 模型的问题。
政采云前端团队
2023/11/14
3270
Linux IO 模型
相关推荐
Netty基础—1.网络编程基础一
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验