JVM上的高并发HTTP客户端

HTTP可能是最流行的应用程序级别协议,并且有许多库在网络I / O之上实现它,这是常规I / O的一种特殊(面向流)情况。 由于所有I / O都有很多共同点1 ,所以让我们开始对其进行一些讨论。

我将集中讨论具有大量并发HTTP请求的I / O情况,例如微服务,其中一组较高级别的HTTP服务会调用多个较低级别的HTTP服务,其中一些并发调用是由于数据依赖性而依次执行的。

当满足许多此类请求时,同时打开的连接总数有时可能会很大。 如果存在数据依赖性,或者较低级别的服务速度较慢(或由于特殊情况而减慢了速度)。 因此,微服务层往往需要许多并发的,可能长期存在的连接。 看看我们有多少打开的连接需要支持没有崩溃让我们回忆一下利特尔法则是正在进行中的请求数,ρ是平均到达率和τ是平均完成时间的平均值:

Ψ=ρτ

我们可以支持的处理中请求的数量取决于语言运行时,操作系统和硬件; 平均请求完成时间(或延迟)取决于我们为满足请求所必须执行的操作,当然包括对任何较低级别服务的调用,对存储的访问等。

我们可以支持多少个并发HTTP请求? 每个组件都需要一个开放的连接和一些可运行的原语,这些原语可以使用syscalls对其进行读写。 如果内存,I / O子系统和网络带宽可以保持同步,则现代OS可以支持数十万个开放的TCP连接。 它们提供的用于套接字的可运行基元是线程 。 线程比套接字要重得多:运行现代操作系统的单个盒子只能支持5000-15000个线程。

从10,000英尺开始:JVM上的I / O性能

如今,JDK线程是大多数平台3上的OS线程,但是如果在任何时候只有很少的并发连接,那么“每个连接的线程”模型就可以了。

如果没有呢? 这个问题的答案随着历史的变化而改变:

  • JDK 1.4之前的版本仅具有调用操作系统的线程阻塞I / O的库( java.io pkgs),因此只能使用“每个连接线程”模型或线程池4 。 如果您想要更好的东西,可以通过JNI来利用操作系统的其他功能。
  • JDK 1.4添加了非阻塞I / O或NIO( java.nio包),仅在可以立即完成连接时才可以从连接读取/写入数据,而不必让线程进入睡眠状态。 更重要的是,它增加了一种方法,使一个线程可以通过套接字选择在多个通道上有效工作,这意味着要求OS阻止当前线程,并在有可能立即从至少一个套接字中立即接收/发送数据时取消阻止该线程。一套。
  • JDK 1.7添加了NIO.2,也称为异步I / O(仍为java.nio软件包)。 这意味着要求操作系统仅在I / O完成后才在后台完全执行I / O任务,并在稍后唤醒带有通知的线程。

从JVM调用HTTP

JVM提供了多种开源HTTP客户端库。 线程阻塞API易于使用和维护,但对于许多并发请求而言可能效率较低,而异步请求有效但较难使用。 异步API也会通过异步对代码产生病毒影响:消耗异步数据的任何方法本身都必须是异步的,或者阻止并抵消了异步的优势。

以下是Java和Clojure的开源HTTP客户端的选择:

  • Java
    • JDK的URLConnection使用传统的线程阻塞I / O。
  • Clojure
    • clj-http包装Apache HTTP客户端。

从10,000英尺开始:轻松

由于Java线程占用大量资源 ,因此,如果要执行I / O并扩展到许多并发连接,则必须使用NIO或异步NIO。 另一方面,它们很难编码和维护。 有解决这个难题的方法吗?

如果线程不繁重,我们只能使用直接的阻塞I / O,那么我们的问题确实是: 我们是否可以拥有足够便宜的线程 ,并且可以创建比OS线程大得多的线程?

目前,JVM本身不提供轻量级线程,但Quasar借助纤维 (在用户空间中实现的非常有效的线程)来进行救援。

从JVM调用HTTP

Comsat将现有的某些库与Quasar纤维集成在一起。 Comsat API与原始API相同,“ HTTP客户端”部分 )说明了如何将其挂钩; 其余的只需确保您正确运行Quasar ,在需要执行新的HTTP调用时启动光纤,并使用以下一个(或多个)光纤阻塞API(或从模板和示例中汲取灵感:

  • Java的
    • Apache HTTP客户端 API的广泛子集,通过桥接异步者集成。
  • Clojure
    • clj-http API的广泛子集,通过桥接http-kit的异步API进行集成。

可以轻松添加新的集成 ,当然也总是欢迎您提供帮助。

JBender的一些负载测试

jbender是Pinterest基于Quasar的网络负载测试框架。 它高效而灵活,但是由于Quasar光纤阻塞,其源代码很小且可读性强。 使用它就像使用传统的线程阻塞I / O一样简单。

考虑这个项目 , 该项目建立在JBender之上,并以少量代码为所有Comsat集成库提供HTTP负载测试客户端,无论是其原始线程阻塞版本还是Comsat的光纤阻塞版本。

JBender可以使用任何(普通,重量级,OS)线程或光纤来执行请求,它们均被Quasar抽象到一个称为Strand的共享抽象类中,因此线程阻塞和光纤阻塞版本共享HTTP代码:这证明了Comsat集成的API与原始API完全相同,并且光纤和线程的使用方式完全相同。

负载测试客户端接受参数以自定义其运行的几乎每个方面,但是我们将考虑的测试案例如下:

  1. 以可能的最高速率触发了41000个寿命长的HTTP连接。
  2. 执行10000个请求(加上1000个初始客户端和服务器预热),每个请求持续1秒,目标速率为1000 rps。
  3. 执行10000个请求(加上1000个初始客户端和服务器预热),每个请求持续100毫秒,目标速率为10000 rps。
  4. 执行10000个请求(加上1000个初始客户端和服务器预热),并立即做出答复,目标速率为100000 rps。

所有测试均针对运行Dropwizard的服务器触发,该服务器经过优化,可在HTTP服务器端使用带comsat-dropwizard以实现最大的并发性。 服务器仅用“ Hello!”答复任何请求。

以下是有关我们的负载测试环境的一些信息:

表格1

第一个重要的结果是, 基于Comsat的客户端在不使用光纤模式的情况下赢得了成功 。 Apache用于许多持久连接,而OkHttp用于许多短期请求,这些请求具有很高的目标速率,堆的大小也较小(分别为990 MiB和3 GiB,为简洁起见仅显示第一个):

表2 表2.1

OkHttp在快速请求的速度和内存利用率方面表现出色。 JVM的光纤版本使用异步API,并且即使底层机制是线程池提供的传统阻塞I / O,其性能也显着提高。

更令人印象深刻的是基于http-kit的光纤阻塞comsat-httpkit击败传统clj-http客户端的方法(仍然显示出很小的堆):

表3

也有其他Jersey提供程序(Grizzly,Jetty和Apache),但Jersey证明是最差的,其占用空间通常更大,并且异步接口(由Comsat的光纤阻塞集成使用)不幸地为每个线程生成并阻塞了一个线程。每个请求; 由于这个原因(可能还取决于每个提供商的实施策略),光纤版本有时会提供明显的性能优势,而有时却没有。 无论如何,这些数字并不像Apache,OkHttp和http-kit那样有趣,因此我不在这里包括它们,但是请让我知道您是否希望看到它们。

(可选)从100 <10,000英尺开始:有关JVM上I / O性能的更多信息

因此,您想知道为什么在高并发情况下光纤比线程更好。

当只有少数并发套接字打开时,OS内核可以以非常低的延迟唤醒被阻塞的线程。 但是OS线程是通用的,并且在许多用例中会增加可观的开销:它们消耗大量内核内存用于簿记,同步syscall可能比过程调用慢几个数量级, 上下文切换昂贵 ,并且调度算法过于笼统。 。 所有这些都意味着,对于具有大量通信和同步的细粒度并发,或者对于一般来说高度并发的系统6而言,当前OS线程并不是最佳选择。

阻止I / O系统调用确实可以无限期地阻止昂贵的OS线程,因此,当您为大量并发连接提供服务时,“每个连接线程”方法将很快导致系统崩溃。 另一方面,使用线程池可能会使“可接受的”连接队列溢出,因为我们无法保持到达速度或至少导致不可接受的延迟。 相反,“每连接光纤”方法是完全可持续的,因为光纤非常轻便。

总结一下 :线程可以通过较少的并发连接来改善延迟,而光纤可以在有许多并发连接的情况下改善吞吐量。

当然,光纤需要在活动的OS线程之上运行,因为OS对光纤一无所知,因此Quasar在线程池上调度了光纤。 Quasar只是一个库,并且完全在用户空间中运行,这意味着执行syscall的光纤将在整个调用持续时间内阻塞其底层的JVM线程,从而使其他光纤无法使用它。 这就是为什么这样的调用要尽可能短的原因,尤其是它们不应该等待很长时间甚至无限期地等待是很重要的:在实践中,光纤应该只执行非阻塞的系统调用。 那么,如何使阻塞的HTTP客户端在光纤上运行得如此好呢? 由于这些库还提供了非阻塞(但不方便)的API,因此我们将该异步API转换为光纤阻塞的API,并使用它来实现原始的阻塞API。 新的实现(非常简短,只不过是一个包装器)将:

  1. 阻止当前的光纤。
  2. 启动等效的异步操作,然后传入完成处理程序,该处理程序将在完成后取消阻塞光纤。

从光纤(和程序员)的角度来看,当I / O完成时,执行将在库调用之后重新开始,就像使用线程和常规线程阻塞调用时一样。

包起来

使用Quasar和Comsat,您可以使用Java,Clojure或Kotlin轻松编写和维护高度并发且HTTP密集的代码,甚至可以选择自己喜欢的HTTP客户端库,而无需任何API锁定。 您还想使用其他东西吗? 让我们知道,或者自己将其与Quasar集成。

  1. …还有很多不同之处,例如文件I / O(面向块)支持内存映射的I / O,这与面向流的I / O无关。
  2. 阅读此博客文章以进一步讨论。
  3. 在1.2之前(只有) Green Threads时不是这样。
  4. 使用线程池意味着专用或有限数量的线程(或 )来完成某种类型的任务,在这种情况下,服务于HTTP请求:进入的连接被排队,直到池中的线程可以为它服务(如顺便说一句,“连接池”是完全不同的,并且最常见的是重用数据库连接。
  5. 请查看此介绍以获得更多信息。
  6. 例如,如果要了解有关实现光纤的原因和方式的更多信息,请阅读this , this和this以获得更多信息和基准,以及在ZeroTurnaround RebelLabs博客上的客座帖子 。

翻译自: https://www.javacodegeeks.com/2015/12/high-concurrency-http-clients-jvm.html

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

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

相关文章

win10系统卷影复制服务器,如何使用Windows卷影拷贝服务恢复文件和文件夹

本文介绍了如何使用Windows卷影拷贝服务恢复文件和文件夹&#xff0c;分享给大家&#xff0c;具体如下&#xff1a;什么是卷影拷贝&#xff1f;从Windows XP SP2和Windows Server 2013开始&#xff0c;微软就向Windows操作系统中引入了一项名叫卷影拷贝的服务(Volume Shadow Co…

Nginx下配置Http Basic Auth

nginx basic auth指令 第一条语句&#xff1a; 语法: auth_basic string | off;默认值: auth_basic off;配置段: http, server, location, limit_except 默认表示不开启认证&#xff0c;后面如果跟上字符&#xff0c;这些字符会在弹窗中显示。 第二条语句&#xff…

服务器多核性能排行,服务器内存多核性能

服务器内存多核性能 内容精选换一换本文介绍了弹性云服务器ECS的功能发布和对应的文档动态&#xff0c;新特性将在各个区域(Region)陆续发布&#xff0c;欢迎体验。关于弹性云服务器(ECS)更多历史版本变更内容&#xff0c;请单击“查看PDF”详细了解。超高I/O型弹性云服务器使用…

从去除毛刺的策略看开运算opening_circle和闭运算closing_circle的异同

例一&#xff1a;毛刺在往外凸的面上 策略1&#xff1a;分割出黑色部分&#xff0c;然后通过开运算去掉毛刺&#xff0c;再通过原黑色部分区域减去开运算之后的区域&#xff0c;得到毛刺部分的区域。 1 read_image (Tu, C:/Users/xiahui/Desktop/tu.jpg) 2 binary_threshold (…

买服务器带操作系统,买服务器带操作系统

买服务器带操作系统 内容精选换一换只有运行中的弹性云服务器才允许用户登录。Linux操作系统用户名“root”。忘记密码&#xff0c;请先通过“重置密码”功能设置登录密码。重置密码&#xff1a;选中待重置密码的云耀云服务器&#xff0c;并选择“操作”列下的“ 重置密码”。重…

自定义sql_【PL/SQL 自定义函数】 常用场景

看完这章后你会学习到以下内容&#xff1a;1.练习场景2.面试场景3.工作应用场景总览思维导图&#xff1a;面试部分&#xff1a;1.创建函数,从emp表中查询指定员工编号的职工的工资CREATE OR REPLACE FUNCTION CHECK_SAL(F_EMPNO IN EMP.EMPNO%TYPE) RETURN NUMBER ISV_SAL VARC…

进阶– Java EE 7前端5强

系列继续。 在初步概述和Arjan关于最重要的后端功能的文章之后 &#xff0c;我现在非常高兴让Ed Burns&#xff08; edburns &#xff09;使用他最喜欢的Java EE 7前端功能完成本系列。 感谢Markus Eisele让我有机会在他非常受欢迎的博客上发表帖子。 我和Markus的关系可以追溯…

一杯水怎么测试_一杯水就能鉴别翡翠真假的高招

大家好&#xff0c;小生有礼&#xff01;鄙人是秋玉蝉珠宝的杨杨&#xff0c;很高兴能在茫茫互联网中相识就是有缘。先简单介绍一下秋玉蝉珠宝&#xff0c;我们是年轻的品牌&#xff0c;我们的理念一直秉承坚持做真翡翠&#xff0c;好翡翠&#xff0c;把握翡翠的精髓&#xff0…

php连接mysql_PHP连接MySQL数据库的三种方式

本篇文章给大家介绍一下PHP连接MySQL数据库的三种方式(mysql、mysqli、pdo)&#xff0c;结合实例形式分析了PHP基于mysql、mysqli、pdo三种方式连接MySQL数据库的相关操作技巧与注意事项。有一定的参考价值&#xff0c;有需要的朋友可以参考一下&#xff0c;希望对大家有所帮助…

idea内置junit5_JUnit的内置Hamcrest Core Matcher支持

idea内置junit5在通过JUnit和Hamcrest改善对assertEquals的文章中&#xff0c;我简要讨论了Hamcrest “ 核心 ”匹配器与JUnit的现代版本“结合”在一起的情况。 在那篇文章中&#xff0c;我特别关注了JUnit的assertThat&#xff08;T&#xff0c;Matcher&#xff09;静态方法与…

jenkins 发送邮件模板

jenkins 发送邮件模板 <!DOCTYPE html> <html> <head> <meta charset"UTF-8"> <title>${ENV, var"JOB_NAME"}-第${BUILD_NUMBER}次构建日志</title> </head><body leftmargin"8" marginwidth"…

Oracle Spring Clean JavaFX应该吗?

我们确实在Codename One上依赖JavaFX&#xff0c;我们的模拟器需要它。 我们的桌面版本使用它&#xff0c;而我们的设计器工具基于Swing。 我们希望它成功&#xff0c;这对我们的业务至关重要&#xff01; 即使您是Java EE开发人员并且不关心桌面编程&#xff0c;我们也不是一个…

laravel mysql 锁表_Laravel中MySQL的乐观锁与悲观锁

MySQL/InnoDB的加锁&#xff0c;是一个老生常谈的话题。在数据库高并发请求下&#xff0c;如何兼顾数据完整性与用户体验的敏捷性是一代又一代程序员一直在思考的问题。乐观锁乐观锁之所以叫乐观&#xff0c;是因为这个模式不会对数据加锁。而是对数据操作保持一种乐观的心态&a…

mysql 超长记录_谁记录了mysql error log中的超长信息(记pt-stalk一个bug的定位过程)...

【问题】最近查看MySQL的error log文件时&#xff0c;发现有很多服务器的文件中有大量的如下日志&#xff0c;内容很长(大小在200K左右)&#xff0c;从记录的内容看&#xff0c;并没有明显的异常信息。有一台测试服务器也有类似的问题&#xff0c;为什么会记录这些信息&#xf…

glassfish发布应用_Arquillian 1.0.0.Final正式发布! 准备使用GlassFish和WebLogic! 所有虫子死亡!...

glassfish发布应用红帽公司和JBoss社区今天宣布的1.0.0.Final发布的Arquillian &#xff0c;其屡获殊荣的建在Java虚拟机&#xff08;JVM&#xff09;运行测试平台。 Arquillian大大减少了编写和执行Java中间件集成和功能测试所需的工作。 它甚至使测试工程师能够解决以前认为无…

使用ADF列表视图的主从数据

最近&#xff0c;从UI角度来看&#xff0c;ADF Faces 表组件不再被认为很酷。 对于显示数据集合&#xff0c; 列表视图今天应该很酷。 这并不意味着我们根本不应该使用af&#xff1a;table 。 在某些情况下&#xff08;经常是:)&#xff09;&#xff0c;表比列表视图更适合。 但…

java 调用私有方法_公开调用私有Java方法?

java 调用私有方法我们是Java开发人员&#xff0c;在Java中已知4种访问修饰符&#xff1a;私有&#xff0c;受保护&#xff0c;公共和包。 好吧&#xff0c;除了私有以外&#xff0c;最后三个可以通过继承&#xff0c;相同的包或实例从类外部调用。 现在&#xff0c;常见的问题…

港航环境变化引起的错误解决方法

1.serlvet API缺少&#xff0c;pom.xml中引入坐标&#xff1b; 2.web.xml中出现错误&#xff0c;将所有的filter调到filtermapping上面去&#xff1b; 3.依赖导入完成后项目依然有红叉&#xff0c;右击项目Propreties->myeclipse->Project Facets->java换成1.6就可以了…

flutter 国际化_从0开始设计Flutter独立APP | 第二篇: 完整的国际化语言支持

鉴于Flutter高性能渲染和跨平台的优势&#xff0c;闪点清单在移动端APP上&#xff0c;使用了完整的Flutter框架来开发。既然是完整APP&#xff0c;架构搭建完全不受历史Native APP的影响&#xff0c;没有历史包袱的沉淀&#xff0c;设计也能更灵活和健壮。国际化语言的支持&…

将旧版本从Java EE 5减少到7

Java EE 5于2005年首次引入&#xff0c;而Java EE 7于2013年问世。这两个版本之间有7年的差距&#xff0c;从技术角度来说&#xff0c;这就像一个世纪。 许多组织仍然对使用Java EE 5感到困惑&#xff0c;并且有很多正当理由选择不升级。 不过&#xff0c;如果您考虑一些前进的…