网站建设教程视频西瓜,哈尔滨道外区建设局官方网站,策划案推广,wordpress 图片预加载jvm高并发HTTP可能是最流行的应用程序级别协议#xff0c;并且有许多库在网络I / O之上实现它#xff0c;这是常规I / O的一种特殊#xff08;面向流#xff09;情况。 由于所有I / O都有很多共同点1 #xff0c;所以让我们开始对其进行一些讨论。 我将集中讨论具有大量并… jvm高并发 HTTP可能是最流行的应用程序级别协议并且有许多库在网络I / O之上实现它这是常规I / O的一种特殊面向流情况。 由于所有I / O都有很多共同点1 所以让我们开始对其进行一些讨论。 我将集中讨论具有大量并发HTTP请求的I / O情况例如微服务其中一组较高级别的HTTP服务会调用多个较低级别的HTTP服务其中一些并发调用是由于数据依赖性而依次执行的。 当满足许多此类请求时同时打开的连接总数有时会变大 是否存在数据依存关系或者较低级别的服务速度较慢或由于特殊情况而减慢了速度。 因此微服务层往往需要许多并发的可能长期存在的连接。 看看我们有多少打开的连接需要支持没有崩溃让我们回忆一下利特尔法则2Ψ是正在进行中的请求数ρ是平均到达率和τ是平均完成时间的平均值 Ψρτ 我们可以支持的正在进行中的请求数量取决于语言运行时操作系统和硬件 平均请求完成时间或等待时间取决于我们满足请求所必须执行的操作当然包括对任何较低级别服务的调用对存储的访问等。 我们可以支持多少个并发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软件包。 这意味着要求OS仅在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 通过桥接http-kit的异步API集成了clj-http API的广泛子集。 可以轻松添加新的集成 当然也总是欢迎您提供贡献。 JBender的一些负载测试 jbender是Pinterest基于Quasar的网络负载测试框架。 它高效而灵活但是由于Quasar光纤阻隔其源代码很小且易于阅读 使用它就像使用传统的线程阻塞I / O一样简单。 考虑这个项目 该项目建立在JBender之上并以少量代码为所有Comsat集成库提供HTTP负载测试客户端无论是其原始线程阻塞版本还是Comsat的光纤阻塞版本。 JBender可以使用任何普通重量级OS线程或光纤来执行请求它们均被Quasar提取为共享的抽象类Strand 因此线程阻塞和光纤阻塞版本共享HTTP代码这证明了Comsat集成的API与原始API完全相同并且光纤和线程的使用方式完全相同。 负载测试客户端接受参数以自定义其运行的几乎每个方面但是我们将考虑的测试案例如下 41000个寿命长的HTTP连接以尽可能高的速率触发。 执行10000个请求加上1000个初始客户端和服务器预热每个请求持续1秒目标速率为1000 rps。 执行10000个请求加上1000个初始客户端和服务器预热每个请求持续100毫秒目标速率为10000 rps。 执行10000个请求加上1000个初始客户端和服务器预热并立即做出答复目标速率为100000 rps。 所有测试均针对运行Dropwizard的服务器触发该服务器经过优化可在HTTP服务器端使用带comsat-dropwizard以实现最大的并发性。 服务器仅用“ Hello”答复任何请求。 以下是有关我们的负载测试环境的一些信息 第一个重要的结果是 基于Comsat的客户端在不使用光纤模式的情况下赢得了成功 。 Apache用于许多持久连接而OkHttp用于许多短期请求这些请求具有很高的目标速率堆的大小也较小分别为990 MiB和3 GiB为简洁起见仅显示第一个 OkHttp在快速请求的速度和内存利用率方面表现出色。 JVM的光纤版本使用异步API并且即使底层机制是线程池提供的传统阻塞I / O其性能也显着提高。 更令人印象深刻的是基于http-kit的光纤阻塞comsat-httpkit击败传统clj-http客户端的方法仍然显示出很小的堆 也有其他Jersey提供程序GrizzlyJetty和Apache但Jersey证明是最差的其占用空间通常更大并且异步接口由Comsat的光纤阻塞集成使用不幸地为每个线程生成并阻塞了一个线程。每个请求 由于这个原因也可能是由于每个提供商的实施策略光纤版本有时会提供明显的性能优势而有时却没有。 无论如何这些数字并不像ApacheOkHttp和http-kit的数字那么有趣因此我不在这里包括它们但是请让我知道您是否希望看到它们。 可选从100 10,000英尺开始有关JVM上I / O性能的更多信息 因此您想知道为什么在高度并发的情况下光纤比线程更好。 当只有少数并发套接字打开时OS内核可以以非常低的延迟唤醒被阻塞的线程。 但是OS线程是通用的并且在许多用例中会增加可观的开销它们消耗大量内核内存用于簿记同步syscall可能比过程调用慢几个数量级 上下文切换昂贵 并且调度算法过于笼统。 。 所有这些意味着对于具有大量通信和同步的细粒度并发或者对于通常具有高度并发性的系统6而言当前OS线程并不是最佳选择。 阻止I / O系统调用确实可以无限期地阻止昂贵的OS线程因此当您为大量并发连接提供服务时“每连接线程”方法将很快导致系统崩溃。 另一方面使用线程池可能会使“可接受的”连接队列溢出因为我们无法保持到达速度或至少导致不可接受的延迟。 相反“每连接光纤”方法是完全可持续的因为光纤非常轻便。 总结一下 线程可以通过较少的并发连接来改善延迟而光纤可以在有许多并发连接的情况下改善吞吐量。 当然光纤需要在活动的OS线程之上运行因为OS对光纤一无所知因此Quasar在线程池上调度了光纤。 Quasar只是一个库并且完全在用户空间中运行这意味着执行syscall的光纤将在整个调用持续时间内阻塞其底层的JVM线程从而使其他光纤无法使用它。 这就是为什么这样的调用越短越重要尤其是它们不应等待很长时间甚至无限期地等待在实践中光纤仅应执行非阻塞 syscall。 那么如何使阻塞的HTTP客户端在光纤上运行得如此好呢 由于这些库还提供了非阻塞但不方便的API因此我们将异步API转换为光纤阻塞的API并使用它来实现原始的阻塞API。 新的实现非常简短只不过是一个包装器将 阻止当前的光纤。 启动等效的异步操作然后传入完成处理程序该处理程序将在完成后取消阻塞光纤。 从光纤和程序员的角度来看在I / O完成后库调用之后将重新开始执行就像使用线程和常规线程阻塞调用一样。 结语 借助Quasar和Comsat您可以轻松地用JavaClojure或Kotlin编写和维护高度并发且HTTP密集的代码甚至可以选择自己喜欢的HTTP客户端库而无需任何API锁定。 您还想使用其他东西吗 让我们知道或者自己将其与Quasar集成。 …还有很多不同之处例如文件I / O面向块支持内存映射的I / O而这与面向流的I / O毫无意义。 阅读此博客文章以进一步讨论。 在1.2之前只有 Green Threads时不是这样。 使用线程池意味着专用或有限数量的线程或池 来完成某种类型的任务在这种情况下它服务于HTTP请求进入的连接被排队直到池中的线程可以自由地为其服务如顺便说一句“连接池”是完全不同的并且最常见的是重用数据库连接。 请查看此介绍以获得更多信息。 例如如果要了解有关实现光纤的原因和方式的更多信息请阅读this this和this以获得更多信息和基准以及在ZeroTurnaround RebelLabs博客上的客座帖子 。 翻译自: https://www.javacodegeeks.com/2015/12/high-concurrency-http-clients-jvm.htmljvm高并发