当前位置: 首页 > 知识库问答 >
问题:

Akka Http性能调优

经景辉
2023-03-14

我正在执行Akka-http框架(版本:10.0)的负载测试,我正在使用wrk工具。wrk命令:

WRK-T6-C10000-D 60S--超时10S--延迟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
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, write 0, timeout 0
Requests/sec:   1903.01
Transfer/sec:    267.61KB

现在,我应该使用哪些其他参数或配置来提高性能,同时使用future Call.,以便应用程序提供最大的吞吐量。

共有1个答案

公孙宏畅
2023-03-14

首先提出一些免责声明:我以前没有使用过wrk工具,因此可能会出错。下面是我为这个答案所做的假设:

  1. 连接计数独立于线程计数,即如果指定-t4-c10000,它将保留10000个连接,而不是4*10000
  2. 对于每个连接,其行为如下:发送请求,完全接收响应,然后立即发送下一个,等等,直到时间用完为止。

此外,我在wrk的同一台机器上运行服务器,我的机器似乎比你的弱(我只有双核CPU),所以我将wrk的线程数减少到2,连接数减少到1000,以获得良好的结果。

现在来看看答案。让我们看看您拥有的阻塞代码:

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让服务器扩展得更高之前,这种情况一直很好地工作了很多年。

complete {
  Future {
    "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

另外,不要混淆异步操作和非阻塞操作。带有futurethread.sleep的代码是异步但阻塞操作的完美示例。许多流行的软件都在这种模式下运行(一些遗留的HTTP客户端、Cassandra驱动程序、AWS Java SDK等)。要充分获得非阻塞HTTP服务器的好处,您需要一直处于非阻塞状态,而不仅仅是异步状态。这也许不是永远可能的,但这是一件值得努力的事情。

 类似资料:
  • 对于某些工作负载,可以在通过在内存中缓存数据或者打开一些实验选项来提高性能。 在内存中缓存数据 Spark SQL可以通过调用sqlContext.cacheTable("tableName")方法来缓存使用柱状格式的表。然后,Spark将会仅仅浏览需要的列并且自动地压缩数据以减少内存的使用以及垃圾回收的 压力。你可以通过调用sqlContext.uncacheTable("tableName")

  • 集群中的Spark Streaming应用程序获得最好的性能需要一些调整。这章将介绍几个参数和配置,提高Spark Streaming应用程序的性能。你需要考虑两件事情: 高效地利用集群资源减少批数据的处理时间 设置正确的批容量(size),使数据的处理速度能够赶上数据的接收速度 减少批数据的执行时间 设置正确的批容量 内存调优

  • 常用命令 1. 查看系统 CPU 总数 $ grep -c ^processor /proc/cpuinfo $ lscpu 2. 查看网卡信息,主机名 $ hostname $ ip addr show eth0 3. 查看系统上运行的服务 # systemctl list-units -t service | awk '$3=="active"' ** ** ** **

  • 硬件因素 内存(RAM)的读写速度时普通 SSD 的 25 倍。MongoDB 中依赖 RAM 最多的操作包括:聚合、索引遍历、写操作、查询引擎、连接 Table 1. 常见存储的IOPS 类型 IOPS 7200 rpm SATA 75 - 100 15000 rpm SAS 175 - 210 SSD Intel X25-E(SLC) 5000 SSD Intel X25-M G2(MLC)

  • 本文向大家介绍Hadoop性能调优?相关面试题,主要包含被问及Hadoop性能调优?时的应答技巧和注意事项,需要的朋友参考一下 调优可以通过系统配置、程序编写和作业调度算法来进行。 hdfs的block.size可以调到128/256(网络很好的情况下,默认为64) 调优的大头:mapred.map.tasks、mapred.reduce.tasks设置mr任务数(默认都是1) mapred.ta

  • 主要内容:硬件和操作系统问题,运行时配置问题,编译时配置问题,原子操作,附录:跟踪的详细分析Apache 2.x是一个通用的Web服务器,旨在提供灵活性,可移植性和性能之间的平衡。虽然它没有专门设计用于设置基准记录,但Apache 2.x在许多实际情况下都具有高性能。 与Apache 1.3相比,版本2.x包含许多额外的优化,以提高吞吐量和可伸缩性。默认情况下,大多数这些改进都已启用。但是,存在可能显着影响性能的编译时和运行时配置选择。本文档介绍了服务器管理员可以配置的选项,以调整Apa

  • 当你开始编写Apache Spark代码或者浏览公开的API的时候,你会遇到诸如transformation,action,RDD等术语。了解到这些是编写Spark代码的基础。同样,当你任务开始失败或者你需要透过web界面去了解自己的应用为何如此费时的时候,你需要去了解一些新的名词:job, stage, task。对于这些新术语的理解有助于编写良好Spark代码。这里的良好主要指更快的Spark

  • 我们正在运行一个web应用程序,并从memcached切换到redis(2.4)进行缓存。现在我们对redis的表现有些失望。Redis运行在同一台服务器上,我们只使用非常简单的GET和SET操作。对于一些大量使用缓存值的请求,我们有多达300个对redis的GET请求,但这些请求最多需要150ms。我们大约有20万个活动密钥,每秒大约有1000个redis请求。磁盘io、ram或CPU都没有问题