将serversocket 写在按钮事件中连接不上_Java服务器的模型—TCP连接/流量优化

d68c9083d4dd5682844e519f8a091892.png

本文很长哦,但请给我一点时间。

通常,我们的应用程序不需要并行处理成千上万的用户,也不需要在一秒钟内处理成千上万的消息。我们只需要应付数十或数百个并发连接的用户,就可以在内部应用程序或某些微服务应用程序中承受如此大的负担。

在这种情况下,我们可以使用某些高级框架/库,这些框架/库在线程模型/使用的内存方面没有得到优化,并且仍然可以承受一些合理的资源和相当快的交付时间。

然而,有时我们会遇到这样的情况:我们的系统的一部分需要比其他应用程序更好地扩展。用传统的方法或框架编写系统的这一部分可能会导致巨大的资源消耗,并且需要启动同一服务的许多实例来处理负载。导致处理成千上万个连接的算法和方法也被称为C10K问题。

在本文中,我将主要关注在TCP连接/流量方面可以进行的优化,以优化(微型)服务实例以尽可能少地浪费资源,深入了解操作系统如何与TCP和Sockets一起工作,以及最后但并非最不重要的是,如何深入了解所有这些事情。我们开始吧。

I/O编程策略

让我们描述一下我们目前拥有什么类型的I/O编程模型,以及在设计应用程序时需要从哪些选项中进行选择。首先,没有好的或坏的方法,只有更适合我们当前用例的方法。选择错误的方法在将来会产生非常不方便的后果。它可能导致资源浪费,甚至从头开始重新编写应用程序。

带阻塞处理的阻塞I/O

每个连接服务器的线程数

这种方法背后的想法是,如果没有任何专用/空闲线程,就不接受套接字连接(稍后我们将展示它的含义)。在这种情况下,阻塞意味着特定的线程被绑定到连接,并且总是在读取或写入连接时阻塞。

public static void main(String[] args) throws IOException {try (ServerSocket serverSocket = new ServerSocket(5050)) {while (true) {Socket clientSocket = serverSocket.accept();var dis = new DataInputStream(clientSocket.getInputStream());var dos = new DataOutputStream(clientSocket.getOutputStream());new Thread(new ClientHandler(dis, dos)).start();}}
}

最简单的套接字服务器版本,从端口5050开始,以阻塞的方式从InputStream读取并写入OutputStream。当我们需要通过一个连接传输少量对象时很有用,然后在需要时关闭它并启动一个新的对象。

  • 即使没有任何高级库,它也可以实现。
  • 使用阻塞流进行读/写(等待阻塞InputStream读操作,该操作按当时TCP接收缓冲区中可用的字节填充提供的字节数组,并返回字节数或-1-流的结尾)和消耗字节,直到我们有足够的数据来构造请求。
  • 当我们开始为无边界的传入连接创建线程时,会出现一个大问题和效率低下。我们将为非常昂贵的线程创建和内存影响付出代价,这与将一个Java线程映射到一个内核线程是密不可分的。
  • 它不适合“真正的”生产,除非我们真的需要一个内存占用率低的应用程序,并且不想加载属于某些框架的很多类。

带阻塞处理的非阻塞I/O

基于线程池的服务器

这是大多数知名企业HTTP服务器所属的类别。一般来说,该模型使用多个线程池,使多cpu环境下的处理更高效,更适合企业应用程序。有几种方法可以配置线程池,但基本思想在所有HTTP服务器中是完全相同的。请参阅HTTP Grizzly I/O策略,了解通常可以根据基于线程池的非阻塞服务器配置的所有可能策略。

  • 用于接受新连接的第一个线程池。如果一个线程能够管理传入连接的速度,它甚至可以是一个单线程池。通常有两个积压可以填补和下一个传入连接拒绝。如果可能,请检查是否正确使用了持久连接。

f74b3e98d4a5267f54083421399b00c9.png
  • 用于以非阻塞方式(选择器线程或IO线程)从/写入套接字的第二个线程池。每个选择器线程处理多个客户端(通道)。
  • 第三个线程池,用于分离请求处理的非阻塞部分和阻塞部分(通常称为工作线程)。某些阻止操作无法阻止选择器线程,因为所有其他通道都无法取得任何进展(通道组只有一个线程,此线程将被阻止)。
  • 非阻塞读/写是使用缓冲区实现的,只要处理请求的特定线程不满意(因为它们没有足够的数据来构造例如HTTP请求),选择器线程就会从套接字读取新字节并写入专用缓冲区(池缓冲区)。
  • 我们需要澄清非阻塞术语:
  1. 我们在Socket服务器的上下文中对话,那么非阻塞意味着线程没有绑定到打开的连接,并且不等待传入的数据(甚至在TCP发送缓冲区已满的情况下写入数据),只要尝试读取,如果没有字节,那么就不会将任何字节添加到缓冲区中以进行进一步处理(构造请求),给定的选择器线程将继续从另一个打开的连接读取。
  2. 然而,在处理请求方面,代码在大多数情况下是阻塞的,这意味着我们执行一些代码来阻塞当前线程,这个线程等待I/O绑定处理(数据库查询、HTTP调用、从磁盘读取等)或一些长时间CPU绑定处理(计算哈希/阶乘,加密挖掘,…)。如果执行完成,则会唤醒线程,并在某些业务逻辑中继续执行。
  • 业务逻辑的阻塞特性是工作池如此庞大的主要原因,我们只需要让大量线程发挥作用来提高吞吐量。否则,在负载较高的情况下(例如,更多的HTTP请求),我们可能会导致所有线程都处于阻塞状态,并且没有可用于请求处理的线程(没有处于可运行状态的线程可以在CPU上执行)。

优势

  • 即使请求的数量相当高,并且我们的许多工作线程在某些阻塞操作上被阻塞,我们也能够接受新的连接,即使我们可能无法立即处理它们的请求,并且数据必须在TCP接收缓冲区中等待。
  • 这种编程模型被许多框架/库(Spring Controllers,Jersey,…)和HTTP服务器(Jetty,Tomcat,Grizzly…)暗中使用,因为它非常容易编写业务代码,如果真的需要的话,让线程阻塞。

缺点

  • 并行性通常不是由CPU的数量决定的,而是由阻塞操作的性质和工作线程的数量限制的。一般来说,这意味着如果阻塞操作(I/O)和进一步执行(在请求过程中)的时间比率过高,那么我们可以得到:
  1. 阻塞操作(数据库查询…)上的许多阻塞线程
  2. 等待处理工作线程的大量请求,以及
  3. 由于没有线程可以继续执行而非常未使用的CPU
  • 较大的线程池导致上下文切换和CPU缓存的低效使用

如何设置线程池

好的,我们有一个或多个线程池来处理阻塞的业务操作。但是,线程池的最佳大小是多少?我们可能会遇到两个问题:

  • 线程池太小,我们没有足够的线程来覆盖所有线程被阻塞的时间,比如说等待I/O操作,而您的CPU没有得到有效使用。
  • 线程池太大,我们要为很多实际空闲的线程付出代价(见下面运行很多线程的代价)。

我觉得可以参考Brian Goetz的一本书Java并发实践,书中说调整线程池的大小并不是一门精确的科学,它更多的是关于理解您的环境和任务的性质。

  • 您的环境有多少CPU和多少内存?
  • 任务主要执行计算、I/O或某种组合吗?
  • 它们是否需要稀缺资源(JDBC连接)?线程池和连接池会相互影响,当我们充分利用连接池时,增加线程池以获得更好的吞吐量可能没有意义。

如果我们的程序包含I/O或其他阻塞操作,您需要一个更大的池,因为您的线程不允许一直放在CPU上。您需要使用一些分析器或基准来估计等待时间与计算任务时间的比率,并观察生产工作负载不同阶段(高峰时间与非高峰时间)的CPU利用率。

aa673bb40deed83c990389620155ac4e.png

非阻塞处理的非阻塞I/O

基于与CPU核心相同的线程数的服务器

如果我们能够以非阻塞的方式管理大部分工作负载,那么这种策略是最有效的。这意味着处理套接字(接受连接、读、写)是使用非阻塞算法实现的,但即使是业务处理也不包含任何阻塞操作。

这个策略的典型代表是Netty框架,所以让我们深入了解一下如何实现这个框架的架构基础,以了解为什么它最适合解决C10K问题。如果您想详细了解它的工作原理,那么我可以推荐以下资源:

Netty in Action——作者是诺曼·莫尔。由Netty Framework Norman Mauer的作者撰写。这是了解如何使用具有各种协议的处理程序基于Netty实现客户端或服务器的宝贵资源。

具有异步编程模型的I/O库

Netty是一个I/O库和框架,它简化了非阻塞IO编程,并为服务器生命周期和传入连接期间发生的事件提供了异步编程模型。我们只需要用我们的lambdas连接回拨,我们就可以免费得到所有东西。

很多协议都可以在不依赖于某个大型库的情况下使用

开始用纯JDK NIO构建应用程序是非常令人沮丧的,但Netty包含的特性使程序员保持在较低的级别,并提供了使许多事情更高效的可能性。Netty已经包含了大多数众所周知的协议,这意味着我们可以比在更高级别的库(例如Jersey/Spring MVC for HTTP/REST)中使用大量样板文件更有效地使用它们。

识别正确的非阻塞用例以充分利用Netty的能力

I/O处理、协议实现和所有其他处理程序都应该使用非阻塞操作来永不停止当前线程。我们总是可以使用额外的线程池来阻塞操作。但是,如果我们需要将每个请求的处理切换到专用的线程池来执行阻塞操作,那么我们几乎没有使用Netty的功能,因为我们很可能会遇到与非阻塞IO相同的情况,即阻塞处理-一个大的线程池正好位于应用程序的不同部分。

cf86b93cc038aafac4894b9705d3ec87.png

在上图中,我们可以看到Netty架构的主要组件

EventLoopGroup-收集事件循环并提供要注册到其中一个事件循环的通道。

event loop-处理给定事件循环的已注册通道的所有I/O操作。EventLoop只在一个线程上运行。因此,对于一个EventLoopGroup,事件循环的最佳数量是cpu的数量(有些框架在出现页面错误时使用多个cpu+1来拥有额外的线程)。

管道-保持处理程序的执行顺序(当发生某个输入或输出事件时排序和执行的组件包含实际的业务逻辑)。管道和处理程序在属于EventLoop的线程上执行,因此,处理程序中的阻塞操作会阻塞给定EventLoop上的所有其他处理/通道。

分享就到这啦,希望大家能关注哦。等着你们发表不同意见来讨论。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/335138.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ios 开发设置左滑退出_苹果铃声怎么设置自己的歌?教你用手机快速搞定!

苹果手机铃声怎么设置为自己喜欢的歌曲?由于iOS系统的封闭性,想要给苹果手机更换铃声不像在安卓手机一样那么方便,看到网上很多教程也是需要使用电脑才能完成铃声的设置,有没有不复杂的方法来直接帮我们更换手机铃声?别…

基于单片机步进电机ppt答辩_基于MCU和DSP的步进电机控制技术分析

来源 | 控制与传动步进电机已经渗透入我们生活的方方面面,本文介绍了一些重要的步进电机相关技术,为开发人员基本了解步进电机的工作原理提供了足够的信息,同时也介绍了用微控制器或数字信号处理器控制步进电机的方法。步进电机也叫步进器&am…

div获取第一个子节点jquery_【antd】Tree组件子节点不完全勾选获取父节点的值

注意⚠️:这篇文章适用于后台返回的树结构比较多的情况下,如果数据比较少的情况下,可以参考我的上一篇文章,操作起来比较简单我们在实际操作tree组件和后台交互的时候一般都是需要将父节点传过去,如图:点击…

修改value_Python | 快速修改或命名N个文件夹名称,你会吗?

#欢迎交流:shuilinggan163.com#工作中,经常会遇到需要修改或新建很多文件的文件命,是一件重复且头疼的事情,下面一组Python代码,轻松教你快速实现!程序一:根据文件(SSSSSS)新建并命名空文件夹im…

簇的局部变量中布尔类型_java基础2(变量、常量、数据类型)

一、注释(1)什么是注释?解释说明的文字(注释的内容不会被编译)(2)注释的作用①对代码的解释说明 ②便于后期维护(3)注释的分类:①单行注释 //单行注释作用域:只在当前行有…

数位进制转换详解

文章目录进制进制转换二进制和十进制互相转换十进制 → 二进制十进制正整数 → 二进制十进制负整数 → 二进制十进制负小数 → 二进制十进制小数 → 二进制二进制 → 十进制二进制负整数 → 十进制二进制的正整数 → 十进制二进制小数 → 十进制二进制的负小数 → 十进制八进制…

旋转散点图_聚类分析的结果如何用散点图展示出来?

SPSS系统聚类输出的树状图广受用户喜爱,二阶聚类也可以输出一系列美观的可视化图形用来观察聚类效果,但我们发现Kmeans均值聚类没有提供可视化程度高的图形,那怎么办,我们自己来制作。数据小兵推荐使用3D散点图全方位观察K均值聚类…

async 打包异常_重新打包流中的异常

async 打包异常Java 8已有两年历史,但是仍然存在社区尚未为其开发好的解决方案库的用例,甚至边缘用例。 如何处理流管道中的检查异常就是这样一个问题。 Stream操作接受的功能接口不允许实现抛出已检查的异常,但是我们可能要调用许多方法。 显…

补码基础

关于补码,有如下比较有趣的演化过程: 假如计算机中使用 4 位的二进制表示数据,如图-2,最多能表示 0 到 15(10 进制),之后有牛人做了 一个细微改动,如图-3,将所有二进制以 1 开头的数(大于 7 的数)放到 0 之…

身份验证错误错误指定的句柄无效_基于 Web 端的人脸识别身份验证「实践」

作者:沫沫 政采云前端团队转发链接:https://mp.weixin.qq.com/s/fRDpXixnLIy9c0Uh2tMezQ前言近些年来,随着生物识别技术的逐渐成熟,基于深度学习的人脸识别技术取得了突破性进展,准确率显著提高。现阶段,人…

打开 谷歌浏览器exe_专治各种网银不服:两步开启微软Edge浏览器IE兼容模式

此前微软已经预告过Microsoft Edge将支持IE模式,即可以在该浏览器下使用IE模式加载某些特定的需要的网站。不过在后续更新中微软又突然改口不再面向普通用户提供此功能,而企业级用户若要使用还需要管理员提前配置。现在这款浏览器的正式版已经发布&#…

aspose word 获取标题_Word干货|多级标题的自动编号怎么添加?

在对Word文档进行排版时,大家普遍认为的一个难点就是对多级标题添加自动编号,本期Word妹与大家分享相关技巧的使用。1、添加样式选中文本,点击开始——样式——选择标题1,相同的样式则可以借用F4来实现。PS:以同样方式…

Java集合类梳理

文章目录集合框架CollectionListList常用方法ArrayListArrayList常用方法LinkedListLinkedList常用方法VectorVector 常用方法StackStack 常用方法SetHashSetHashSet 常用方法LinkedHashSetLinkedHashSet 常用方法TreeSetTreeSet常用方法EnumSetEnumSet 常用方法MapHashMapHash…

增加第三方插件_AE插件排行!!

大家好是万能的懒懒酱After effects为视觉效果艺术家和动画设计师带来了大量的效果。然而,第三方开发人员提供了更多独特插件,供After Effects使用。在这里可以帮助你了解哪些插件是最流行的最受欢迎的。第10名:Looks(多功能调色插…

mysql 连续签到天数_签到功能实现,没有你想的那么复杂(一)

1 签到定义以及作用签到,指在规定的簿册上签名或写一“到”字,表示本人已经到达。在APP中使用此功能,可以增加用户粘性和活跃度.2 技术选型redis为主写入查询,mysql辅助查询. 传统签到多数都是直接采用mysql为存储DB,在大数据的情况下数据库的压力较大.查…

java包装项目_项目包装组织

java包装项目程序包是Java的基本概念,是您开始用该语言编程时偶然发现的第一件事。 作为一个初学者,您可能不太关注软件包的结构,但是随着您成为经验丰富且成熟的软件开发人员,您开始考虑可以采取哪些措施来提高其效率。 有几个主…

如何开发 Servlet 程序

文章目录如何开发 Servlet步骤 1:写一个类步骤 2:编译步骤 3:打包步骤 4:部署步骤 5:启动服务器步骤 6:访问 servletServlet 开发示例不使用 IDE 开发(手动编译和部署)步骤 1&#x…

报任安书文言现象_语文老师精心总结【文言文常考点】够你从初一用到初四!...

点击本号菜单栏 免费获取学习资料▼今天给大家整理了初中文言文的一些常用知识点:特殊句式和古今异义,这些只是文言文学习模块中的一部分,除此之外,其他大家需要在平时积累的文言文知识点有下面这些:文言文高频词、古代…

参数化测试 junit_JUnit 5 –参数化测试

参数化测试 junitJUnit 5令人印象深刻,尤其是当您深入研究扩展模型和体系结构时 。 但是从表面上讲,编写测试的地方,开发的过程比革命的过程更具进化性 – JUnit 4上没有杀手级功能吗? 幸运的是,至少有一个&#xff1a…

devexpress textedit调整文字何文本框的间距_手把手教学:用PPT做效果超赞的文字效果...

本文总计:2391 字预计阅读时间:6 分钟昨天文章的头图,貌似反馈还不错,挺多人比较感兴趣。所以,今天就分享一下,这种文字排版效果,是怎么做出来的。而且今天的实现手法与效果,做了一些…