Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >单机高并发模型设计

单机高并发模型设计

作者头像
方丈的寺院
发布于 2022-11-08 05:21:59
发布于 2022-11-08 05:21:59
67900
代码可运行
举报
文章被收录于专栏:方丈的寺院方丈的寺院
运行总次数: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 删除。

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

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
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模型
Python入门之并发编程IO模型
了解新知识之前需要知道的一些知识 同步(synchronous):一个进程在执行某个任务时,另外一个进程必须等待其执行完毕,才能继续执行 #所谓同步,就是在发出一个功能调用时,在没有得到结果之前,该调用就不会返回。 #按照这个定义,其实绝大多数函数都是同步调用。 #但是一般而言,我们在说同步、异步的时候,特指那些需要其他部件协作或者需要一定时间完#成的任务。 #举例: #1. multiprocessing.Pool下的apply #发起同步调用后,就在原地等着任务结束, #根本不考虑任务是在计算还是在io
Jetpropelledsnake21
2018/06/14
6250
【云原生进阶之PaaS中间件】第一章Redis-2.2Redis IO模型
linux系统也是一种应用,它是基于计算机硬件的一种操作系统软件。当我们接收一次网络传输,计算机硬件的网卡会从网络中将读到的字节流写到linux的buffer缓冲区内存中,然后用户空间会调用linux对外暴露的接口,将linux中的buffer内存中的数据再读取到用户空间。这一次读操作就是一次IO。同样写也是这样的。
江中散人_Jun
2023/10/16
3550
【云原生进阶之PaaS中间件】第一章Redis-2.2Redis IO模型
IO模型
一 概念理解 在进行网络编程时,我们常常见到同步(Sync)/异步(Async),阻塞(Block)/非阻塞(Unblock)四种调用方式: 同步:   所谓同步,就是在发出一个功能调用时,在没有得到结果之前,该调用就不会返回。按照这个定义,其实绝大多数函数都是同步调用。但是一般而言,我们在说同步、异步的时候,特指那些需要其他部件协作或者需要一定时间完成的任务。   举例: 1. multiprocessing.Pool下的apply #发起同步调用后,就在原地等着任务结束,根本不考虑任务是在计算还是在io
用户1214487
2018/01/24
7510
IO模型
超详细的I/O多路复用概念、常用I/O模型、系统调用等介绍
I/O多路复用,I/O就是指的我们网络I/O,多路指多个TCP连接(或多个Channel),复用指复用一个或少量线程。串起来理解就是很多个网络I/O复用一个或少量的线程来处理这些连接。
lyb-geek
2021/09/23
2.1K0
一文搞懂什么是阻塞IO、信号驱动IO、Reactor模型、零拷贝
公众号《鲁大猿》 ,寻精品资料,帮你构建Java全栈知识体系 http://www.jiagoujishu.cn
鲁大猿
2024/01/05
4780
一文搞懂什么是阻塞IO、信号驱动IO、Reactor模型、零拷贝
IO模型梳理-从操作系统到应用层
IO模型是编程语言和软件开发中重要的知识。本篇从IO模型这个切入点横向梳理了从操作系统到应用层IO模型相关知识。考虑到技术本身具有横向迁移的特点,也可以帮助大家在宏观与微观,具体与细节,底层与应用多角度串联技术,本篇是第一篇从IO模型说起。
春哥大魔王
2019/08/06
1.3K0
详解Java中的五种IO模型
我们电脑上跑着的应用程序,其实是需要经过操作系统,才能做一些特殊操作,如磁盘文件读写、内存的读写等等。因为这些都是比较危险的操作,不可以由应用程序乱来,只能交给底层操作系统来。
Java微观世界
2025/01/21
1270
详解Java中的五种IO模型
Linux五大网络模型之I/O多路复用浅入深出
清·俞樾《湖楼笔谈》六:“盖诗人用意之妙,在乎深入显出。入之不深,则有浅易之病;出之不显,则有艰涩之患。”
翎野君
2023/05/12
6280
Linux五大网络模型之I/O多路复用浅入深出
一口气说出 5 种 IO 模型,蒙圈了!
recvfrom Linux系统提供给用户用于接收网络IO的系统接口。从套接字上接收一个消息,可同时应用于面向连接和无连接的套接字。
用户1516716
2021/04/13
8470
一口气说出 5 种 IO 模型,蒙圈了!
一口气说出 5 种 IO 模型,懵逼了
Linux系统提供给用户用于接收网络IO的系统接口。从套接字上接收一个消息,可同时应用于面向连接和无连接的套接字。
肉眼品世界
2020/11/11
7780
一口气说出 5 种 IO 模型,懵逼了
​网络 IO 演变发展过程和模型介绍
作者:jaydenwen,腾讯 pcg 后台开发工程师 在互联网中提起网络,我们都会避免不了讨论高并发、百万连接。而此处的百万连接的实现,脱离不了网络 IO 的选择,因此本文作为一篇个人学习的笔记,特此进行记录一下整个网络 IO 的发展演变过程。以及目前广泛使用的网络模型。 1.网络 IO 的发展 在本节内容中,我们将一步一步介绍网络 IO 的演变发展过程。介绍完发展过程后,再对网络 IO 中几组容易混淆的概念进行对比、分析。 1.1 网络 IO 的各个发展阶段 通常,我们在此讨论的网络 IO 一
腾讯技术工程官方号
2021/02/25
1.7K0
I/O多路复用,从来没遇到过这么明白的文章
很多对技术有追求的读者朋友,做到一定阶段后都希望技术有所精进。有些读者朋友可能会研究一些中间件的技术架构和实现原理。比如,Nginx为什么能同时支撑数万乃至数十万的连接?为什么单工作线程的Redis性能比多线程的Memcached还要强?Dubbo的底层实现是怎样的,为什么他的通信效率非常高?
用户7927337
2021/06/25
8150
I/O多路复用,从来没遇到过这么明白的文章
网络基础篇-网络编程
在内核中,为每个socket维护两个队列,一个是已建立连接的队列,也就是完成了三次握手,处于established状态,一个是还没有完全建立连接的队列,处于sync_rcvd状态。
Check King
2021/08/09
7860
Java网络编程和NIO详解3:IO模型与Java网络编程模型
本系列文章将整理到我在GitHub上的《Java面试指南》仓库,更多精彩内容请到我的仓库里查看
Java技术江湖
2019/11/21
7880
重大事故!IO问题引发线上20台机器同时崩溃
几年前的一个下午,公司里码农们正在安静地敲着代码,突然很多人的手机同时“哔哔”地响了起来。本来以为发工资了,都挺高兴!打开一看,原来是告警短信
cxuan
2020/04/22
2.3K0
IO模型
应用程序需要经过操作系统,才能做一些特殊操作,如磁盘读写。此类操作有较大风险,只能交给操作系统来控制。因此,操作系统将进程占用的内存空间划分为两部分:用户空间和内核空间。内核空间是操作系统内核访问的、受保护的内存空间,用户空间则是用户应用程序访问的内存区域。
羽毛球初学者
2024/10/14
1120
Netty基础—1.网络编程基础一
OSI是Open System Interconnect的简称,即开放系统互连参考模型。OSI为开放系统的计算机互连提供了一个共同的基础和标准框架,并为保持相关标准的一致性和兼容性提供了共同的参考。
东阳马生架构
2025/05/16
730
一文读懂Redis中的多路复用模型
首先,Redis 是跑在单线程中的,所有的操作都是按照顺序线性执行的,但是由于读写操作等待用户输入或输出都是阻塞的,所以 I/O 操作在一般情况下往往不能直接返回,这会导致某一文件的 I/O 阻塞导致整个进程无法对其它客户提供服务,而 I/O 多路复用就是为了解决这个问题而出现的。
用户2781897
2021/04/02
1.1K0
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.2K0
I/O的内核原理与5种I/O模型
相关推荐
Python之IO模型
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验