【问题标题】:Why is my Hello World go server getting crushed by ApacheBench?为什么我的 Hello World go 服务器被 ApacheBench 压垮了?
【发布时间】:2015-05-20 14:32:05
【问题描述】:
package main

import (
    "io"
    "net/http"
)

func hello(w http.ResponseWriter, r *http.Request) {
    io.WriteString(w, "Hello world!\n")
}

func main() {
    http.HandleFunc("/", hello)
    http.ListenAndServe(":8000", nil)
}

我有几个非常基本的 HTTP 服务器,它们都存在这个问题。

$ ab -c 1000 -n 10000 http://127.0.0.1:8000/
This is ApacheBench, Version 2.3 <$Revision: 1604373 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking 127.0.0.1 (be patient)
Completed 1000 requests
Completed 2000 requests
Completed 3000 requests
Completed 4000 requests
Completed 5000 requests
apr_socket_recv: Connection refused (61)
Total of 5112 requests completed

使用较小的并发值,事情仍然会失败。对我来说,这个问题似乎通常出现在 5k-6k 左右:

$ ab -c 10 -n 10000 http://127.0.0.1:8000/
This is ApacheBench, Version 2.3 <$Revision: 1604373 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking 127.0.0.1 (be patient)
Completed 1000 requests
Completed 2000 requests
Completed 3000 requests
Completed 4000 requests
Completed 5000 requests
Completed 6000 requests
apr_socket_recv: Operation timed out (60)
Total of 6277 requests completed

事实上,您可以完全放弃并发,但问题仍然(有时)会发生:

$ ab -c 1 -n 10000 http://127.0.0.1:8000/
This is ApacheBench, Version 2.3 <$Revision: 1604373 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking 127.0.0.1 (be patient)
Completed 1000 requests
Completed 2000 requests
Completed 3000 requests
Completed 4000 requests
Completed 5000 requests
Completed 6000 requests
apr_socket_recv: Operation timed out (60)
Total of 6278 requests completed

我不禁想知道我是否在某个地方遇到了某种操作系统限制?我该怎么说?我将如何缓解?

【问题讨论】:

  • ab 不是很好,Go http 服务器远远胜过它。 ab 在 osx 上也很糟糕。您正在耗尽一些本地资源,例如可用的套接字。
  • 我认为默认情况下,Go服务器的连接没有关闭,因此可以重用,但似乎ab没有重用或关闭它们的速度不够快,所以最大打开连接是到达。您可以尝试在您的处理程序中将r.Close 设置为true(我还没有实际测试过)。
  • 在我的笔记本电脑上使用wrk,你的hello服务器达到46000req/sec(@Ainar-G:那也只使用了GOMAXPROCS=1。当你被网络绑定时,低GOMAXPROCS通常更多高效)。
  • @siritinga:这不会有帮助,因为ab 只使用 http/1.0 并且没有通过 keepalive 调用。连接必须每次都关闭。
  • @BobAman:尝试了httperf,在我的系统上它似乎比ab -k 还要慢,但处理100k 请求仍然没有问题。这个基准确实没有用,因为基准测试工具(和本地网络堆栈)的测试甚至比 Go 服务器更多。

标签: http go osx-yosemite


【解决方案1】:

简而言之,你的端口用完了。

osx 上默认的临时端口范围是 49152-65535,也就是只有 16383 个端口。由于每个ab 请求都是http/1.0(在您的第一个示例中没有keepalive),因此每个新请求都需要另一个端口。

当每个端口被使用时,它会被放入一个队列中,等待 tcp "Maximum Segment Lifetime",在 osx 上配置为 15 秒。因此,如果您在 15 秒内使用超过 16,383 个端口,您将在进一步连接时受到操作系统的限制。根据哪个进程首先耗尽端口,您将收到来自服务器的连接错误,或者从ab 挂起。

您可以通过使用支持http/1.1 的负载生成器(如wrk)或使用ab 的keepalive (-k) 选项来缓解这种情况,以便根据工具的并发设置重复使用连接。

现在,您进行基准测试的服务器代码做的很少,负载生成器的负担与服务器本身一样多,而本地操作系统和网络堆栈可能会做出很好的贡献。如果您想对 http 服务器进行基准测试,最好从不在同一台机器上运行的多个客户端做一些有意义的工作。

【讨论】:

  • 在这种情况下,我的主要目标不是对应用服务器进行基准测试,我真的想了解整个 Kubernetes 堆栈相对于应用服务器本身的性能开销,但是看到在实现该目标的过程中,我无法理解一些令人困惑的结果。
  • 我如何知道目前有多少临时端口可用?
  • 另外,出于好奇,对于虚拟机,来宾操作系统中使用的临时端口会以任何方式影响主机吗?即,我可以启动一堆运行 wrk/ab/httperf 的 VM 以绕过 OS X 临时端口限制吗?
  • @BobAman:强制延迟主要只是对 osx 的限制,osx 上的网络堆栈和环回设备没有像 e.g. Linux。本地虚拟机可能有助于为比较提供基础,但您必须保持相同的基础操作系统。比较在 vagrant VM 和本地主机中运行的应用程序是没有意义的。在玩具服务器上抛出数千个连接并不能证明任何事情。您是否尝试比较高并发下的带宽、延迟、CPU 负载或活跃度?这些工具将所有这些混为一谈。
  • 在整个测试过程中保持控制变量不变,并缩小查找范围。问诸如“在 docker 中运行是否会导致 my 应用程序出现不可接受的延迟?”或“此负载均衡器是否会影响 my 应用程序的带宽?”
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-09-12
  • 1970-01-01
  • 1970-01-01
  • 2010-11-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多