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

socket&io高性能

作者头像
码农戏码
发布于 2021-04-29 03:09:14
发布于 2021-04-29 03:09:14
1K0
举报
文章被收录于专栏:DDDDDD

最近看到篇好文章《IO多路复用》,记得早期学习时,也去探索过select、poll、epoll的区别,但后来也是没有及时记录总结,也忘记了,学习似乎就是在记忆与忘记中徘徊,最后在心中留下的火种,是熄灭还是燎原就看记忆与忘记间的博弈

socket与io一对兄弟,有socket地方必然有io,io数据也大多来源于socket,回顾这两方面的知识点,大致梳理一下

socket

Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议

除了TCP协议(三次握手、四次挥手)知识点外,再就是各阶段与java api对应的方法

三次握手关联到两个方法:服务端的listen()与客户端的connect()

两个方法的共通点:TCP三次握手都不是他们本身完成的,握手都是内核完成的,他们只是通知内核,让内核自动完成三次握手连接

不同点:connect()是阻塞的,listen()是非阻塞的

三次握手的过程细节:

•第一次握手:客户端发送 SYN 报文,并进入 SYN_SENT 状态,等待服务器的确认;•第二次握手:服务器收到 SYN 报文,需要给客户端发送 ACK 确认报文,同时服务器也要向客户端发送一个 SYN 报文,所以也就是向客户端发送 SYN + ACK 报文,此时服务器进入 SYN_RCVD 状态;•第三次握手:客户端收到 SYN + ACK 报文,向服务器发送确认包,客户端进入ESTABLISHED 状态。待服务器收到客户端发送的 ACK 包也会进入ESTABLISHED 状态,完成三次握手

io

IO中常听到的就是同步阻塞IO,同步非阻塞IO,异步非阻塞IO;也就是同步、异步、阻塞、非阻塞四个词组合体,可从名字上看就不大对,既然同步,应该都是阻塞,怎么会有同步非阻塞?不知道哪位先贤的学习总结却流传深远

还有些把non-blocking IO与NIO都混淆了

对于IO模型,最正统的应该来自Richard Stevens的“UNIX® Network Programming Volume 1, Third Edition: The Sockets Networking ”,6.2节“I/O Models”

•Blocking I/O•Non-Blocking I/O•I/O Multiplexing•Asynchronous I/O

在理解这四种常见模型前,先简单说下linux的机制,可以更方便理解IO,在《堆外内存》[1]中提到linux的处理IO流程以及Zero-Copy技术,算是IO模型更深入的知识点

应用程序发起的一次IO操作实际包含两个阶段:

•1.IO调用阶段:应用程序进程向内核发起系统调用•2.IO执行阶段:内核执行IO操作并返回

•2.1. 准备数据阶段:内核等待I/O设备准备好数据•2.2. 拷贝数据阶段:将数据从内核缓冲区拷贝到用户空间缓冲区

对于阻塞与非阻塞,讲的是用户进程/线程与内核之间的切换;当内核数据没有准备好时,用户进程就得挂起

对于同步与异步,重点在于执行结果是否一起返回,IO就是指read,send是否及时获取到结果

大致分析一下,同步异步、阻塞非阻塞的两两组合其实是把宏观与微观进行了穿插,从应该程序角度获取结果是同步或异步,而IO内部再细分了阻塞与非阻塞

由上文所述:IO操作分两个阶段 1、等待数据准备好(读到内核缓存) ,2、将数据从内核读到用户空间(进程空间)。一般来说1花费的时间远远大于2。1上阻塞2上也阻塞的是同步阻塞IO;1上非阻塞2阻塞的是同步非阻塞IO,NIO,Reactor就是这种模型;1上非阻塞2上非阻塞是异步非阻塞IO,AIO,Proactor就是这种模型。

同步阻塞IO(Blocking IO)

因为用户态被阻塞,等待内核数据的完成,所以需要同步等待结果

同步非阻塞IO(Non-blocking IO)

用户态与内核不再阻塞了,但需要不停地轮询获取结果,浪费CPU,这方式还不如BIO来得痛快

IO多路复用

Reactor模式,意为事件反应,操作系统的回调/通知可以理解为一个事件,当事件发生时,进程/线程对该事件作出反应。Reactor模式也称作Dispatcher模式,即I/O多路复用统一监听事件,收到事件后分配(Dispatch)给某个进程/线程

对于IO多路复用,里面再有的细节就是一个优化过程,select,poll,epoll

AIO

Proactor模式,Reactor可理解为“来了事件我通知你,你来处理”,而Proactor是“来了事件我处理,处理完了我通知你”。这里“我”是指操作系统,“你”就是用户进程/线程

四种模型对比

对于IO模型的优化进程,一是操作系统的支持,减少系统调用,用户态与内核的切换;二是机制的变换,从命令式到响应性的转变


高性能架构

只温习Socket/IO知识太无趣了,我们要温故知新,升华一下,从架构角度谈一谈

从常规服务处理业务流程讲:request -> process -> response

站在架构师的角度,当然需要特别关注高性能架构的设计。高性能架构设计主要集中在两方面:

1.尽量提升单服务器的性能,将单服务器的性能发挥到极致。2.如果单服务器无法支撑性能,设计服务器集群方案。

除了以上两点,最终系统能否实现高性能,还和具体的实现及编码相关。但架构设计是高性能的基础,如果架构设计没有做到高性能,则后面的具体实现和编码能提升的空间是有限的。形象地说,架构设计决定了系统性能的上限,实现细节决定了系统性能的下限。

单服务器高性能的关键之一就是服务器采取的并发模型,并发模型有如下两个关键设计点:

•服务器如何管理连接•服务器如何处理请求

以上两个设计点最终都和操作系统的 I/O 模型及进程模型相关。

•I/O 模型:阻塞、非阻塞、同步、异步•进程模型:单进程、多进程、多线程

传统模式PPC&TPC

PPC,即Process Per Connection,为每个连接都创建一个进程去处理。此模式实现简单,适合服务器连接不多的场景,如数据库服务

TPC,即Thread Per Connection,为每个连接都创建一个线程去处理。线程创建消耗少,线程间通信简单

这两种都是传统的并发模式,使用于常量连接的场景,如数据库(常量连接海量请求),企业内部(常量连接常量请求)

至于是进程还是线程,大多与语言特性相关,Java语言由于JVM是一个进程,管理线程方便,故多使用线程,如Netty。C语言进程和线程均可使用,如Nginx使用进程,Memcached使用线程。

不同并发模式的选择,还要考察三个指标,分别是响应时间(RT),并发数(Concurrency),吞吐量(TPS)。三者关系,吞吐量=并发数/平均响应时间。不同类型的系统,对这三个指标的要求不一样。

三高系统,比如秒杀、即时通信,不能使用

三低系统,比如ToB系统,运营类、管理类系统,一般可以使用

高吞吐系统,如果是内存计算为主的,一般可以使用,如果是网络IO为主的,一般不能使用。

Reactor&Proactor

对于传统方式,显示只能适合常量连接常量请求,不能适应互联网场景

如双十一场景下的海量连接海量请求;门户网站的海量连接常量请求;

引入线程池也是一种手段,但也不能根本解决,如常量连接海量请求的中间件场景,线程虽然轻量但也有得消耗资源,终有上限

Reactor,意为事件反应,操作系统的回调/通知可以理解为一个事件,当事件发生时,进程/线程对该事件作出反应。Reactor模式也称作Dispatcher模式,即I/O多路复用统一监听事件,收到事件后分配(Dispatch)给某个进程/线程。

可以看到,I/O多路复用技术是Reactor的核心,本质是将I/O操作给剥离出具体的业务进程/线程,从而能够进行统一管理,使用select/epoll去同步管理I/O连接。

Reactor模式的核心分为Reactor和处理资源池。Reactor负责监听和分配事件,池负责处理事件

如何高性能呢?就得IO多路复用,配合上进程、线程组合,就有:

•单Reactor 单进程 / 线程•单Reactor 多线程•多Reactor 单进程 / 线程(此实现方案相比“单 Reactor单进程”方案,既复杂又没有性能优势,所以很少实际应用)•多Reactor 多进程 / 线程

单Reactor单线程

在这种模式中,Reactor、Acceptor和Handler都运行在一个线程中

单 Reactor 单进程的模式优点就是很简单,没有进程间通信,没有进程竞争,全部都在同一个进程内完成。

但其缺点也是非常明显,具体表现有:

•只有一个进程,无法发挥多核 CPU 的性能;只能采取部署多个系统来利用多核 CPU,但这样会带来运维复杂度,本来只要维护一个系统,用这种方式需要在一台机器上维护多套系统。•Handler 在处理某个连接上的业务时,整个进程无法处理其他连接的事件,很容易导致性能瓶颈

因此,单 Reactor 单进程的方案在实践中应用场景不多,只适用于业务处理非常快速的场景,目前比较著名的开源软件中使用单 Reactor 单进程的是 Redis

在redis中如果value比较大,redis的QPS会下降得很厉害,有时一个大key就可以拖垮

现在redis6.0版本后,已经变成多线程模型,对于大value的删除性能就提高了

单Reactor多线程

在这种模式中,Reactor和Acceptor运行在同一个线程,而Handler只有在读和写阶段与Reactor和Acceptor运行在同一个线程,读写之间对数据的处理会被Reactor分发到线程池中

单Reator多线程方案能够充分利用多核多 CPU的处理能力,但同时也存在下面的问题:

•多线程数据共享和访问比较复杂。例如,子线程完成业务处理后,要把结果传递给主线程的 Reactor 进行发送,这里涉及共享数据的互斥和保护机制。以 Java 的 NIO 为例,Selector 是线程安全的,但是通过 Selector.selectKeys() 返回的键的集合是非线程安全的,对 selected keys 的处理必须单线程处理或者采取同步措施进行保护。•Reactor 承担所有事件的监听和响应,只在主线程中运行,瞬间高并发时会成为性能瓶颈

多Reactor多线程

为了解决单 Reactor 多线程的问题,最直观的方法就是将单Reactor改为多Reactor

目前著名的开源系统 Nginx 采用的是多Reactor多进程,采用多Reactor多线程的实现有 Memcache 和 Netty

使用5W根因分析法(它又叫 5Why 分析法或者丰田五问法,具体是重复问五次“为什么”)检查一下对这块知识的学习程度

问题 1:为什么 Netty 网络处理性能高?

答:因为 Netty 采用了 Reactor 模式

问题 2:为什么用了 Reactor 模式性能就高?

答:因为 Reactor 模式是基于 IO 多路复用的事件驱动模式。

问题 3:为什么 IO 多路复用性能高?

答:因为 IO 多路复用既不会像阻塞 IO 那样没有数据的时候挂起工作线程,也不需要像非阻塞 IO 那样轮询判断是否有数据。

问题 4:为什么 IO 多路复用既不需要挂起工作线程,也不需要轮询?

答:因为 IO 多路复用可以在一个监控线程里面监控很多的连接,没有 IO 操作的时候只要挂起监控线程;只要其中有连接可以进行 IO 操作的时候,操作系统就会唤起监控线程进行处理。

问题 5:那还是会挂起监控线程啊,为什么这样做就性能高呢?

答:首先,如果采取阻塞工作线程的方式,对于 Web 这样的系统,并发的连接可能几万十几万,如果每个连接开一个线程的话,系统性能支撑不了;而如果用线程池的话,因为线程被阻塞的时候是不能用来处理其他连接,会出现等待线程的问题。其次,线上单个系统的工作线程数配置可以达到几百上千,这样数量的线程频繁切换会有性能问题,而单个监控线程切换的性能影响可以忽略不计。第三,工作线程没有 IO 操作的时候可以做其他事情,能够大大提升系统的整体性能。

References

[1] 《堆外内存》: http://www.zhuxingsheng.com/blog/common-sense-four-heaps-of-external-memory.html [2] 五种IO模型透彻分析: https://www.cnblogs.com/f-ck-need-u/p/7624733.html [3] IO模型: https://www.cnblogs.com/sheng-jie/p/how-much-you-know-about-io-models.html [4] Scalable IO in Java: http://gee.cs.oswego.edu/dl/cpjslides/nio.pdf [5] 《从零开始学架构》: http://www.zhuxingsheng.com/blog

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

本文分享自 码农戏码 微信公众号,前往查看

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

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

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
原来 8 张图,就能学废 Reactor 和 Proactor
别小看这两个东西,特别是 Reactor 模式,市面上常见的开源软件很多都采用了这个方案,比如 Redis、Nginx、Netty 等等,所以学好这个模式设计的思想,不仅有助于我们理解很多开源软件,而且也能在面试时吹逼。
小林coding
2021/05/27
9930
原来 8 张图,就能学废 Reactor 和 Proactor
​网络 IO 演变发展过程和模型介绍
作者:jaydenwen,腾讯 pcg 后台开发工程师 在互联网中提起网络,我们都会避免不了讨论高并发、百万连接。而此处的百万连接的实现,脱离不了网络 IO 的选择,因此本文作为一篇个人学习的笔记,特此进行记录一下整个网络 IO 的发展演变过程。以及目前广泛使用的网络模型。 1.网络 IO 的发展 在本节内容中,我们将一步一步介绍网络 IO 的演变发展过程。介绍完发展过程后,再对网络 IO 中几组容易混淆的概念进行对比、分析。 1.1 网络 IO 的各个发展阶段 通常,我们在此讨论的网络 IO 一
腾讯技术工程官方号
2021/02/25
1.6K0
高性能实践IO之Reactor模式
讲到高性能IO绕不开Reactor模式,它是大多数IO相关组件如Netty、Redis在使用的IO模式,为什么需要这种模式,它是如何设计来解决高性能并发的呢?
张哥编程
2024/12/19
1510
高性能实践IO之Reactor模式
高性能IO模型浅析
服务器端编程经常需要构造高性能的IO模型,常见的IO模型有四种: (1)同步阻塞IO(Blocking IO):即传统的IO模型。 (2)同步非阻塞IO(Non-blocking IO):默认创建的socket都是阻塞的,非阻塞IO要求socket被设置为NONBLOCK。注意这里所说的NIO并非Java的NIO(New IO)库。 (3)IO多路复用(IO Multiplexing):即经典的Reactor设计模式,有时也称为异步阻塞IO,Java中的Selector和Linux中的epoll都是这种模型
李海彬
2018/03/23
1.1K0
高性能IO模型浅析
Linux高性能IO网络模型对比分析:Reactor vs Proactor
随着互联网的发展,面对海量用户高并发业务,传统的阻塞式的服务端架构模式已经无能为力。本文旨在为大家提供有用的高性能网络编程的I/O模型概览以及网络服务进程模型的比较,以揭开设计和实现高性能网络架构的神秘面纱。 2、关于作者 陈彩华(caison):主要从事服务端开发、需求分析、系统设计、优化重构工作,主要开发语言是 Java。 3、线程模型 上篇《高性能网络编程(五):一文读懂高性能网络编程中的I/O模型》介绍完服务器如何基于 I/O 模型管理连接,获取输入数据,下面将介绍基于进程/线程模型,服务器如何处理请求。 值得说明的是,具体选择线程还是进程,更多是与平台及编程语言相关。 例如 C 语言使用线程和进程都可以(例如 Nginx 使用进程,Memcached 使用线程),Java 语言一般使用线程(例如 Netty),为了描述方便,下面都使用线程来进行描述。 4、线程模型1:传统阻塞 I/O 服务模型
sunsky
2021/01/06
3.9K0
彻底搞懂Reactor模型和Proactor模型
在高性能的I/O设计中,有两个著名的模型:Reactor模型和Proactor模型,其中Reactor模型用于同步I/O,而Proactor模型运用于异步I/O操作。
全菜工程师小辉
2019/08/16
42.2K4
一文搞懂什么是阻塞IO、信号驱动IO、Reactor模型、零拷贝
公众号《鲁大猿》 ,寻精品资料,帮你构建Java全栈知识体系 http://www.jiagoujishu.cn
鲁大猿
2024/01/05
4370
一文搞懂什么是阻塞IO、信号驱动IO、Reactor模型、零拷贝
IO你了解了,NIO你会吗?
作者:海 子 地址:cnblogs.com/dolphin0520   也许很多朋友在学习NIO的时候都会感觉有点吃力,对里面的很多概念都感觉不是那么明朗。在进入Java NIO编程之前,我们今天先来讨论一些比较基础的知识:I/O模型。下面本文先从同步和异步的概念 说起,然后接着阐述了阻塞和非阻塞的区别,接着介绍了阻塞IO和非阻塞IO的区别,然后介绍了同步IO和异步IO的区别,接下来介绍了5种IO模型,最后介绍了两种和高性能IO设计相关的设计模式(Reactor和Proactor)。   以下是本文的目录
Tanyboye
2018/07/02
4620
高性能IO编程设计
? 首先,在讲述高性能IO编程设计的时候,我们先思考一下何为“高性能”呢,如果自己来设计一个web体系服务,选择BIO还是NIO的编程方式呢?其次,我们可以了解下构建一个web体系服务中,为了能够支撑
小坤探游架构笔记
2020/04/07
1.2K0
彻底搞懂Java的网络IO
应用程序向操作系统发出IO请求:应用程序发出IO请求给操作系统内核,操作系统内核需要等待数据就绪,这里的数据可能来自别的应用程序或者网络。一般来说,一个IO分为两个阶段:
全菜工程师小辉
2019/08/16
2.2K0
搞懂I/O多路复用及其技术
高性能是每个程序员的追求,无论写一行代码还是做一个系统,都希望能够达到高性能的效果。高性能架构设计主要集中在两方面:
BUG弄潮儿
2021/01/05
6770
网络基础篇-网络编程
在内核中,为每个socket维护两个队列,一个是已建立连接的队列,也就是完成了三次握手,处于established状态,一个是还没有完全建立连接的队列,处于sync_rcvd状态。
Check King
2021/08/09
7320
架构设计-高性能篇
大家好,我是易安!今天我们谈一谈架构设计中的高性能架构涉及到的底层思想。本文分为缓存架构,单服务器高性能模型,集群下的高性能模型三个部分,内容很干,希望你仔细阅读。
架构狂人
2023/08/16
4330
架构设计-高性能篇
聊聊Netty那些事儿之从内核角度看IO模型
从今天开始我们来聊聊Netty的那些事儿,我们都知道Netty是一个高性能异步事件驱动的网络框架。
bin的技术小屋
2022/01/12
8002
聊聊Netty那些事儿之从内核角度看IO模型
如何设计真正高性能高并发分布式系统(万字长文)
“世间可称之为天经地义的事情没几样,复杂的互联网架构也是如此,万丈高楼平地起,架构都是演变而来,那么演变的本质是什么?”
玄姐谈AGI
2019/11/25
2.4K0
整天背诵五种I/O模型/epoll区别,换个马甲确不认识了!
Java 中的 BIO、NIO和 AIO 理解为是 Java 语言对操作系统的各种 IO 模型的封装。
早起的鸟儿有虫吃
2021/06/25
1.2K0
整天背诵五种I/O模型/epoll区别,换个马甲确不认识了!
Netty网络编程第六卷
1)获取请求数据,客户端与服务器建立连接发出请求,服务器接受请求(1-3); 2)构建响应,当服务器接收完请求,并在用户空间处理客户端的请求,直到构建响应完成(4); 3)返回数据,服务器将已构建好的响应再通过内核空间的网络 I/O 发还给客户端(5-7)。
大忽悠爱学习
2022/05/06
3820
Netty网络编程第六卷
Java NIO之理解I/O模型(二)
上一篇文章讲解了I/O模型的一些基本概念,包括同步与异步,阻塞与非阻塞,同步IO与异步IO,阻塞IO与非阻塞IO。这次一起来了解一下现有的几种IO模型,以及高效IO的两种设计模式,也都是属于IO模型的基础知识。
纪莫
2019/09/23
4800
Java NIO之理解I/O模型(二)
高性能服务器程序框架
http://blog.csdn.net/zs634134578/article/details/19806429
bear_fish
2018/09/20
2.1K0
高性能服务器程序框架
Java NIO:浅析I/O模型
也许很多朋友在学习NIO的时候都会感觉有点吃力,对里面的很多概念都感觉不是那么明朗。在进入Java NIO编程之前,我们今天先来讨论一些比较基础的知识:I/O模型。下面本文先从同步和异步的概念 说起,然后接着阐述了阻塞和非阻塞的区别,接着介绍了阻塞IO和非阻塞IO的区别,然后介绍了同步IO和异步IO的区别,接下来介绍了5种IO模型,最后介绍了两种和高性能IO设计相关的设计模式(Reactor和Proactor)。   以下是本文的目录大纲:   一.什么是同步?什么是异步?   二.什么是阻塞?什么是非阻塞
范蠡
2018/04/04
6970
Java NIO:浅析I/O模型
相关推荐
原来 8 张图,就能学废 Reactor 和 Proactor
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档