scala – Akka Http性能调优
我在Akka-http框架(版本:10.0)上执行负载测试,我正在使用
wrk工具.
wrk命令: wrk -t6 -c10000 -d 60s –timeout 10s –latency http:// localhost:8080 / hello 首先运行没有任何阻塞调用, object WebServer { implicit val system = ActorSystem("my-system") implicit val materializer = ActorMaterializer() implicit val executionContext = system.dispatcher def main(args: Array[String]) { val bindingFuture = Http().bindAndHandle(router.route,"localhost",8080) println( s"Server online at http://localhost:8080/nPress RETURN to stop...") StdIn.readLine() // let it run until user presses return bindingFuture .flatMap(_.unbind()) // trigger unbinding from the port .onComplete(_ => system.terminate()) // and shutdown when done } } object router { implicit val executionContext = WebServer.executionContext val route = path("hello") { get { complete { "Ok" } } } } 输出wrk: Running 1m test @ http://localhost:8080/hello 6 threads and 10000 connections Thread Stats Avg Stdev Max +/- Stdev Latency 4.22ms 16.41ms 2.08s 98.30% Req/Sec 9.86k 6.31k 25.79k 62.56% Latency Distribution 50% 3.14ms 75% 3.50ms 90% 4.19ms 99% 31.08ms 3477084 requests in 1.00m,477.50MB read Socket errors: connect 9751,read 344,write 0,timeout 0 Requests/sec: 57860.04 Transfer/sec: 7.95MB 现在如果我在路由中添加未来呼叫并再次运行测试. val route = path("hello") { get { complete { Future { // Blocking code Thread.sleep(100) "OK" } } } } 输出:wrk: Running 1m test @ http://localhost:8080/hello 6 threads and 10000 connections Thread Stats Avg Stdev Max +/- Stdev Latency 527.07ms 491.20ms 10.00s 88.19% Req/Sec 49.75 39.55 257.00 69.77% Latency Distribution 50% 379.28ms 75% 632.98ms 90% 1.08s 99% 2.07s 13744 requests in 1.00m,1.89MB read Socket errors: connect 9751,read 385,write 38,timeout 98 Requests/sec: 228.88 Transfer/sec: 32.19KB 正如你可以看到,将来只有13744个请求被提供. 在Akka documentation之后,我为路由添加了一个单独的调度程序线程池,创建了最多200个线程. implicit val executionContext = WebServer.system.dispatchers.lookup("my-blocking-dispatcher") // config of dispatcher my-blocking-dispatcher { type = Dispatcher executor = "thread-pool-executor" thread-pool-executor { // or in Akka 2.4.2+ fixed-pool-size = 200 } throughput = 1 } 经过上述变化,性能有所提升 Running 1m test @ http://localhost:8080/hello 6 threads and 10000 connections Thread Stats Avg Stdev Max +/- Stdev Latency 127.03ms 21.10ms 504.28ms 84.30% Req/Sec 320.89 175.58 646.00 60.01% Latency Distribution 50% 122.85ms 75% 135.16ms 90% 147.21ms 99% 190.03ms 114378 requests in 1.00m,15.71MB read Socket errors: connect 9751,read 284,timeout 0 Requests/sec: 1903.01 Transfer/sec: 267.61KB 在my-blocking-dispatcher配置中,如果我将池大小增加到200以上,那么性能是相同的. 现在,我应该使用什么其他参数或配置来增加使用将来的调用时的性能.因此该应用程序可以提供最大的吞吐量. 解决方法
一些免责声明:我以前没有使用过wrk工具,所以我可能会出错.这是我为这个答案做出的假设:
>连接计数与线程计数无关,即如果我指定-t4 -c10000,则保持10000个连接,而不是4 * 10000. 此外,我已经在与机器相同的机器上运行服务器,我的机器似乎比您的机器弱(我只有双核CPU),所以我将wrk的线程数减少到2,连接数为1000,得到体面的结果. 我使用的Akka Http版本是10.0.1,wrk版本是4.0.2. 现在回答我们来看看你拥有的阻止代码: Future { // Blocking code Thread.sleep(100) "OK" } 这意味着每个请求至少需要100毫秒.如果您有200个线程和1000个连接,则时间线将如下所示: Msg: 0 200 400 600 800 1000 1200 2000 |--------|--------|--------|--------|--------|--------|---..---|---... Ms: 0 100 200 300 400 500 600 1000 Msg是处理消息的数量,Ms是以毫秒为单位的时间. 这给我们每秒处理的2000条消息,或者每30秒处理60000条消息,这些消息大多同意测试数据: wrk -t2 -c1000 -d 30s --timeout 10s --latency http://localhost:8080/hello Running 30s test @ http://localhost:8080/hello 2 threads and 1000 connections Thread Stats Avg Stdev Max +/- Stdev Latency 412.30ms 126.87ms 631.78ms 82.89% Req/Sec 0.95k 204.41 1.40k 75.73% Latency Distribution 50% 455.18ms 75% 512.93ms 90% 517.72ms 99% 528.19ms here: --> 56104 requests in 30.09s <--,7.70MB read Socket errors: connect 0,read 1349,write 14,timeout 0 Requests/sec: 1864.76 Transfer/sec: 262.23KB 这也是很明显的,这个数字(每秒2000个消息)被线程计数严格约束.例如.如果我们有300个线程,我们将每100毫秒处理300条消息,所以如果我们的系统可以处理这么多线程,我们每秒会有3000条消息.让我们看看如果我们提供每个连接1个线程,即池中的1000个线程,我们将如何收费: wrk -t2 -c1000 -d 30s --timeout 10s --latency http://localhost:8080/hello Running 30s test @ http://localhost:8080/hello 2 threads and 1000 connections Thread Stats Avg Stdev Max +/- Stdev Latency 107.08ms 16.86ms 582.44ms 97.24% Req/Sec 3.80k 1.22k 5.05k 79.28% Latency Distribution 50% 104.77ms 75% 106.74ms 90% 110.01ms 99% 155.24ms 223751 requests in 30.08s,30.73MB read Socket errors: connect 0,read 1149,write 1,timeout 0 Requests/sec: 7439.64 Transfer/sec: 1.02MB 正如你所看到的,现在一个请求平均几乎完全是100ms,也就是说我们把它放在Thread.sleep中的数量相同.看来我们不能比这快得多!现在,我们几乎在每个请求的一个线程的标准情况下,多年来一直工作得很好,直到异步IO让服务器扩展得更高. 为了比较起见,这里是我的机器上使用默认fork-join线程池的完全非阻塞测试结果: complete { Future { // Blocking code Thread.sleep(100) "OK" } } ====> wrk -t2 -c1000 -d 30s --timeout 10s --latency http://localhost:8080/hello Running 30s test @ http://localhost:8080/hello 2 threads and 1000 connections Thread Stats Avg Stdev Max +/- Stdev Latency 15.50ms 14.35ms 468.11ms 93.43% Req/Sec 22.00k 5.99k 34.67k 72.95% Latency Distribution 50% 13.16ms 75% 18.77ms 90% 25.72ms 99% 66.65ms 1289402 requests in 30.02s,177.07MB read Socket errors: connect 0,read 1103,write 42,timeout 0 Requests/sec: 42946.15 Transfer/sec: 5.90MB 总而言之,如果使用阻塞操作,则每个请求需要一个线程来实现最佳吞吐量,因此相应地配置您的线程池.系统可以处理多少线程有自然限制,您可能需要调整操作系统以获得最大线程数.为了获得最佳吞吐量,请避免阻塞操作. 也不要将异步操作与非阻塞操作混淆.您的代码与Future和Thread.sleep是异步但阻止操作的完美示例.许多流行的软件以这种模式运行(一些传统的HTTP客户端,Cassandra驱动程序,AWS Java SDK等).为了充分获得非阻塞HTTP服务器的优点,您需要一直阻止一切,而不仅仅是异步.这可能不总是可能的,但这是值得的. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
- webService之拦截器
- angularjs – Angular Directive ng-click Not Working
- Angular 4找不到名称’ViewChild’
- 在angularjs中使用ui-date时如何将初始值设置为ng-model
- 同一个文件在windows和linux下计算md5哈希不一致的原因及解
- angularjs – 如何使用cordova获取移动设备的所有图库图像?
- 为什么这个scala prime代这么慢/内存密集?
- Dockerfile将主机用户UID和GID复制到映像
- 如何找到Scala中隐含的来源?
- angularjs – 如何在Jasmine / Protractor中模拟angular.mo